File size: 4,684 Bytes
7510827
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "sqliteInt.h"
#include "unity.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

/* Wrapper for the static function under test (provided by the build as per instructions) */
extern int test_getConstraintToken(const u8 *z, int *piToken);

void setUp(void) {
  /* No global setup required */
}

void tearDown(void) {
  /* No global teardown required */
}

/* Helper: return index of first occurrence of character c in s, or -1 if not found */
static int idx_of_char(const char *s, char c){
  const char *p = strchr(s, c);
  if( !p ) return -1;
  return (int)(p - s);
}

/* Helper: return index immediately after the first occurrence of substring sub in s, or -1 if not found */
static int idx_after_sub(const char *s, const char *sub){
  const char *p = strstr(s, sub);
  if( !p ) return -1;
  return (int)((p - s) + (int)strlen(sub));
}

/* 1) Simple identifier with no leading whitespace/comments */
void test_getConstraintToken_simple_identifier(void) {
  const char *z = "abc def";
  int t = 0;
  int n = test_getConstraintToken((const u8*)z, &t);
  TEST_ASSERT_EQUAL_INT(TK_ID, t);
  TEST_ASSERT_EQUAL_INT(3, n); /* "abc" length */
}

/* 2) Skips leading spaces and comments, then identifies "abc" */
void test_getConstraintToken_skips_space_and_comments_before_id(void) {
  const char *z = "   /* comment */\n-- line comment\nabc def";
  int expected = idx_after_sub(z, "abc"); /* position immediately after "abc" */
  TEST_ASSERT_TRUE_MESSAGE(expected > 0, "Did not find 'abc' in test string");

  int t = 0;
  int n = test_getConstraintToken((const u8*)z, &t);

  TEST_ASSERT_EQUAL_INT(TK_ID, t);
  TEST_ASSERT_EQUAL_INT(expected, n);
}

/* 3) Minimal parenthesis token "()" followed by sentinel 'X' */
void test_getConstraintToken_minimal_parentheses(void) {
  const char *z = "()X";
  int expected = idx_of_char(z, 'X');
  TEST_ASSERT_TRUE_MESSAGE(expected >= 0, "Sentinel 'X' not found");

  int t = 0;
  int n = test_getConstraintToken((const u8*)z, &t);

  TEST_ASSERT_EQUAL_INT(TK_LP, t);
  TEST_ASSERT_EQUAL_INT(expected, n);
}

/* 4) Parenthesis token with inner tokens and leading spaces; should consume up to the matching ')' */
void test_getConstraintToken_parentheses_with_inner_tokens(void) {
  const char *z = "   (two three)X";
  int expected = idx_of_char(z, 'X');
  TEST_ASSERT_TRUE_MESSAGE(expected >= 0, "Sentinel 'X' not found");

  int t = 0;
  int n = test_getConstraintToken((const u8*)z, &t);

  TEST_ASSERT_EQUAL_INT(TK_LP, t);
  TEST_ASSERT_EQUAL_INT(expected, n);
}

/* 5) Nested parentheses: (a(b)c)X -> should consume exactly up to the ')' before X */
void test_getConstraintToken_nested_parentheses(void) {
  const char *z = "(a(b)c)X";
  int expected = idx_of_char(z, 'X');
  TEST_ASSERT_TRUE_MESSAGE(expected >= 0, "Sentinel 'X' not found");

  int t = 0;
  int n = test_getConstraintToken((const u8*)z, &t);

  TEST_ASSERT_EQUAL_INT(TK_LP, t);
  TEST_ASSERT_EQUAL_INT(expected, n);
}

/* 6) Unclosed parenthesis at end-of-input: expect TK_ILLEGAL and only the '(' consumed */
void test_getConstraintToken_unclosed_parenthesis_hits_illegal(void) {
  const char *z = "(abc";
  int t = 0;
  int n = test_getConstraintToken((const u8*)z, &t);

  TEST_ASSERT_EQUAL_INT(TK_ILLEGAL, t);
  /* Expect at least the leading '(' to be consumed; tokenizer should return 0-length illegal at EOF */
  TEST_ASSERT_EQUAL_INT(1, n);
}

/* 7) Unterminated string literal inside parentheses should trigger TK_ILLEGAL */
void test_getConstraintToken_unterminated_string_inside_parentheses(void) {
  const char *z = "('unterminated";
  int t = 0;
  int n = test_getConstraintToken((const u8*)z, &t);

  TEST_ASSERT_EQUAL_INT(TK_ILLEGAL, t);
  /* Should have consumed the '(' plus at least part of the string token */
  TEST_ASSERT_TRUE(n > 1);
  TEST_ASSERT_TRUE(n <= (int)strlen(z));
}

/* 8) Non-parenthesis keyword token (SELECT) */
void test_getConstraintToken_keyword_token(void) {
  const char *z = "SELECT rest";
  int t = 0;
  int n = test_getConstraintToken((const u8*)z, &t);

  TEST_ASSERT_EQUAL_INT(TK_SELECT, t);
  TEST_ASSERT_EQUAL_INT(6, n); /* "SELECT" length */
}

int main(void) {
  UNITY_BEGIN();

  RUN_TEST(test_getConstraintToken_simple_identifier);
  RUN_TEST(test_getConstraintToken_skips_space_and_comments_before_id);
  RUN_TEST(test_getConstraintToken_minimal_parentheses);
  RUN_TEST(test_getConstraintToken_parentheses_with_inner_tokens);
  RUN_TEST(test_getConstraintToken_nested_parentheses);
  RUN_TEST(test_getConstraintToken_unclosed_parenthesis_hits_illegal);
  RUN_TEST(test_getConstraintToken_unterminated_string_inside_parentheses);
  RUN_TEST(test_getConstraintToken_keyword_token);

  return UNITY_END();
}