1 #include <test.h>
2 
3 
4 #include <iteration.c>
5 
6 
7 
test_FindDollarParen(void)8 static void test_FindDollarParen(void)
9 {
10     /* not found */
11     assert_int_equal(FindDollarParen("", 1), 0);
12     assert_int_equal(FindDollarParen(" ", 2), 1);
13     assert_int_equal(FindDollarParen("$", 2), 1);
14     assert_int_equal(FindDollarParen("(", 2), 1);
15     assert_int_equal(FindDollarParen("{", 2), 1);
16     assert_int_equal(FindDollarParen("$ ", 3), 2);
17     assert_int_equal(FindDollarParen("$$", 3), 2);
18     assert_int_equal(FindDollarParen("$[", 3), 2);
19     assert_int_equal(FindDollarParen("($", 3), 2);
20     assert_int_equal(FindDollarParen(" $", 3), 2);
21     assert_int_equal(FindDollarParen(" $[", 4), 3);
22     assert_int_equal(FindDollarParen("$ (", 4), 3);
23     assert_int_equal(FindDollarParen("$ {", 4), 3);
24 
25     /* found */
26     assert_int_equal(FindDollarParen("${", 3), 0);
27     assert_int_equal(FindDollarParen("$(", 3), 0);
28     assert_int_equal(FindDollarParen(" $(", 4), 1);
29     assert_int_equal(FindDollarParen(" ${", 4), 1);
30     assert_int_equal(FindDollarParen("$$(", 4), 1);
31     assert_int_equal(FindDollarParen("$${", 4), 1);
32 
33     // Detect out of bounds read:
34     // If max is 0, it shouldn't try to deref these invalid pointers:
35     char a = 'a';
36     assert_int_equal(FindDollarParen((char *)0x1, 0), 0);
37     assert_int_equal(FindDollarParen((&a) + 1, 0), 0);
38 
39     // Should not read past max bytes:
40     char b[1] = {'b'};
41     assert_int_equal(FindDollarParen(b, 1), 1);
42     char c[8] = {'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c'};
43     assert_int_equal(FindDollarParen(c, 8), 8);
44 
45     // We had some problems with FindDollarParen reading outside a buffer
46     // so I added these cryptic but useful tests. Some of them will only
47     // fail if you run tests with ASAN, valgrind or similar.
48 }
49 
50 
test_IsMangled(void)51 static void test_IsMangled(void)
52 {
53     /* Simply true. */
54     assert_false(IsMangled(""));
55     assert_false(IsMangled("blah"));
56     assert_false(IsMangled("namespace:blah"));
57     assert_false(IsMangled("scope.blah"));
58     assert_false(IsMangled("namespace:scope.blah"));
59 
60     /* Simply false. */
61     assert_true(IsMangled("scope#blah"));
62     assert_true(IsMangled("namespace*blah"));
63     assert_true(IsMangled("namespace*scope.blah"));
64     assert_true(IsMangled("namespace:scope#blah"));
65 
66     /* Complicated: nested expansions shouldn't affect result */
67     assert_false(IsMangled("$("));
68     assert_false(IsMangled("${"));
69     assert_false(IsMangled("blah$(blue)"));
70     assert_false(IsMangled("blah$(scope.blue)"));
71     assert_false(IsMangled("blah$(scope#blue)"));
72     assert_false(IsMangled("blah$(namespace:blue)"));
73     assert_false(IsMangled("blah$(namespace*blue)"));
74     assert_false(IsMangled("blah$(namespace:scope.blue)"));
75     assert_false(IsMangled("blah$(namespace:scope#blue)"));
76     assert_false(IsMangled("blah$(namespace*scope.blue)"));
77     assert_false(IsMangled("blah$(namespace*scope#blue)"));
78 
79     assert_false(IsMangled("scope.blah$(blue)"));
80     assert_false(IsMangled("scope.blah$(scope.blue)"));
81     assert_false(IsMangled("scope.blah$(scope#blue)"));
82     assert_false(IsMangled("scope.blah$(namespace:blue)"));
83     assert_false(IsMangled("scope.blah$(namespace*blue)"));
84     assert_false(IsMangled("scope.blah$(namespace:scope.blue)"));
85     assert_false(IsMangled("scope.blah$(namespace:scope#blue)"));
86     assert_false(IsMangled("scope.blah$(namespace*scope.blue)"));
87     assert_false(IsMangled("scope.blah$(namespace*scope#blue)"));
88 
89     assert_true(IsMangled("scope#blah$(blue)"));
90     assert_true(IsMangled("scope#blah$(scope.blue)"));
91     assert_true(IsMangled("scope#blah$(scope#blue)"));
92     assert_true(IsMangled("scope#blah$(namespace:blue)"));
93     assert_true(IsMangled("scope#blah$(namespace*blue)"));
94     assert_true(IsMangled("scope#blah$(namespace:scope.blue)"));
95     assert_true(IsMangled("scope#blah$(namespace:scope#blue)"));
96     assert_true(IsMangled("scope#blah$(namespace*scope.blue)"));
97     assert_true(IsMangled("scope#blah$(namespace*scope#blue)"));
98 
99     assert_true(IsMangled("namespace*blah$(blue)"));
100     assert_true(IsMangled("namespace*blah$(scope.blue)"));
101     assert_true(IsMangled("namespace*blah$(scope#blue)"));
102     assert_true(IsMangled("namespace*blah$(namespace:blue)"));
103     assert_true(IsMangled("namespace*blah$(namespace*blue)"));
104     assert_true(IsMangled("namespace*blah$(namespace:scope.blue)"));
105     assert_true(IsMangled("namespace*blah$(namespace:scope#blue)"));
106     assert_true(IsMangled("namespace*blah$(namespace*scope.blue)"));
107     assert_true(IsMangled("namespace*blah$(namespace*scope#blue)"));
108 
109     assert_false(IsMangled("$(scope#blah)"));
110     assert_false(IsMangled("$(namespace*blah)"));
111     assert_false(IsMangled("$(namespace*scope#blah)"));
112 
113     /* Multiple nested expansions, again, none should matter. */
114     assert_false(IsMangled("blah$(blue$(bleh))"));
115     assert_false(IsMangled("blah$(scope.blue$(scope#bleh))"));
116 
117     /* Array indexes shouldn't affect the result either. */
118     assert_false(IsMangled("["));
119     assert_false(IsMangled("blah[$(blue)]"));
120     assert_false(IsMangled("blah$(blue[bleh])"));
121     assert_false(IsMangled("blah[S#i]"));
122     assert_false(IsMangled("blah[S#i][N*i]"));
123     assert_false(IsMangled("blah[S#i][N*i]"));
124 
125     assert_true(IsMangled("S#blah[S.blue]"));
126     assert_true(IsMangled("S#blah[N:blue]"));
127     assert_true(IsMangled("S#blah[S#blue]"));
128     assert_true(IsMangled("N*blah[S.blue]"));
129     assert_true(IsMangled("N*blah[N:blue]"));
130     assert_true(IsMangled("N*S.blah[N:blue]"));
131     assert_true(IsMangled("N*S.blah[S.blue]"));
132 
133     assert_false(IsMangled("S.blah[S#i][N*i]"));
134     assert_true (IsMangled("S#blah[S#i][N*i]"));
135 
136     assert_false(IsMangled("[scope#blah]"));
137     assert_false(IsMangled("[namespace*blah]"));
138     assert_false(IsMangled("[namespace*scope#blah]"));
139 
140     /* Complicated: combine nested variables with array expansions. */
141     assert_false(IsMangled("[$("));
142     assert_false(IsMangled("S.blah[$("));
143     assert_false(IsMangled("S.blah[i]$(blah)"));
144     assert_false(IsMangled("S.blah[$(i)]"));
145     assert_false(IsMangled("S.v[$(i)]"));
146     assert_true (IsMangled("S#v[$(i)]"));
147     assert_true (IsMangled("N*v[$(i)]"));
148     assert_false(IsMangled("N:v[$(i)]"));
149     assert_false(IsMangled("N:v[$(N*i)]"));
150     assert_false(IsMangled("N:v[$(S#i)]"));
151     assert_true (IsMangled("N*v[$(S#i)]"));
152     assert_true (IsMangled("S#v[$(S#i)]"));
153     assert_false(IsMangled("v[$(N*S#i)]"));
154     assert_false(IsMangled("v[$(N:S#i)]"));
155     assert_false(IsMangled("v[$(N*S.i)]"));
156     assert_false(IsMangled("S.v[$(N*S#i)]"));
157     assert_true (IsMangled("S#v[$(N*S#i)]"));
158     assert_false(IsMangled("N:v[$(N*S#i)]"));
159     assert_true (IsMangled("N*v[$(N*S#i)]"));
160 }
161 
162 
Mangle_TestHelper(const char * orig,const char * expected)163 static void Mangle_TestHelper(const char *orig, const char *expected)
164 {
165     printf("Testing MangleVarRefString: %s\n", orig);
166 
167     char *s = xstrdup(orig);
168     MangleVarRefString(s, strlen(s));
169     assert_string_equal(s, expected);
170     free(s);
171 }
Mangle_TestHelperWithLength1(const char * orig,size_t orig_len,const char * expected)172 static void Mangle_TestHelperWithLength1(const char *orig, size_t orig_len,
173                                          const char *expected)
174 {
175     printf("Testing MangleVarRefString: %.*s\n", (int) orig_len, orig);
176 
177     char *s = xstrdup(orig);
178     MangleVarRefString(s, orig_len);
179     assert_string_equal(s, expected);
180     free(s);
181 }
182 /* NOTE: this one changes "orig" in-place. */
Mangle_TestHelperWithLength2(char * orig,size_t orig_len,const char * expected,size_t expected_len)183 static void Mangle_TestHelperWithLength2(char *orig,           size_t orig_len,
184                                          const char *expected, size_t expected_len)
185 {
186     printf("Testing MangleVarRefString: %.*s\n", (int) orig_len, orig);
187 
188     MangleVarRefString(orig, orig_len);
189     assert_memory_equal(orig, expected, expected_len);
190 }
test_MangleVarRefString(void)191 static void test_MangleVarRefString(void)
192 {
193     Mangle_TestHelper            ("", "");
194     Mangle_TestHelperWithLength1 ("a", 0, "a");
195 
196     Mangle_TestHelper            ("a.b", "a#b");
197     /* Force length to 1, no change should occur. */
198     Mangle_TestHelperWithLength1 ("a.b", 1, "a.b");
199 
200     Mangle_TestHelper            ("a:b",    "a*b");
201     /* Force length to 1, no change should occur. */
202     Mangle_TestHelperWithLength1 ("a:b", 1, "a:b");
203 
204     Mangle_TestHelper            ("a:b.c",  "a*b#c");
205     /* Force length to 1, no change should occur. */
206     Mangle_TestHelperWithLength1 ("a:b.c", 1, "a:b.c");
207 
208     /* Never mangle after array indexing */
209     Mangle_TestHelper            ("a[b.c]",   "a[b.c]");
210 
211     /* "this" scope never gets mangled. */
212     Mangle_TestHelper            ("this.a", "this.a");
213 
214     /* Inner expansions never get mangled. */
215     Mangle_TestHelper            ("a_$(s.i)", "a_$(s.i)");
216     Mangle_TestHelper            ("a_$(n:i)", "a_$(n:i)");
217 
218     /* Only before the inner expansion it gets mangled. */
219     Mangle_TestHelper            ("s.a_$(s.i)", "s#a_$(s.i)");
220     Mangle_TestHelper            ("n:a_$(n:i)", "n*a_$(n:i)");
221 
222     /* Testing non '\0'-terminated char arrays. */
223 
224     char A[4] = {'a','b','.','c'};
225     Mangle_TestHelperWithLength2(A, 0, "ab.c", 4);
226     Mangle_TestHelperWithLength2(A, 4, "ab#c", 4);
227     char B[3] = {'a',':','b'};
228     Mangle_TestHelperWithLength2(B, 0, "a:b", 3);
229     Mangle_TestHelperWithLength2(B, 3, "a*b", 3);
230     char C[1] = {'a'};
231     Mangle_TestHelperWithLength2(C, 0, "a", 1);
232     Mangle_TestHelperWithLength2(C, 1, "a", 1);
233 }
234 
235 
236 /* NOTE: the two variables "i" and "j" are defined as empty slists in the
237  * EvalContext. */
IteratorPrepare_TestHelper(const char * promiser,size_t expected_wheels_num,const char ** expected_wheels)238 static void IteratorPrepare_TestHelper(
239     const char *promiser,
240     size_t expected_wheels_num,
241     const char **expected_wheels)
242 {
243     /* INIT EvalContext and Promise. */
244     EvalContext *evalctx = EvalContextNew();
245     Policy *policy = PolicyNew();
246     Bundle *bundle = PolicyAppendBundle(policy, "ns1", "bundle1", "agent",
247                                         NULL, NULL);
248     BundleSection *section = BundleAppendSection(bundle, "dummy");
249     Promise *promise = BundleSectionAppendPromise(section, promiser,
250                                                   (Rval) { NULL, RVAL_TYPE_NOPROMISEE },
251                                                   "any", NULL);
252     EvalContextStackPushBundleFrame(evalctx, bundle, NULL, false);
253     EvalContextStackPushBundleSectionFrame(evalctx, section);
254     PromiseIterator *iterctx = PromiseIteratorNew(promise);
255     char *promiser_copy = xstrdup(promiser);
256 
257     /* Insert the variables "i" and "j" as empty Rlists in the EvalContext, so
258      * that the iteration engine creates wheels for them. */
259     {
260         VarRef *ref_i = VarRefParseFromBundle("i", bundle);
261         EvalContextVariablePut(evalctx, ref_i,
262                                (Rlist *) NULL, CF_DATA_TYPE_STRING_LIST,
263                                NULL);
264         VarRefDestroy(ref_i);
265 
266         VarRef *ref_j = VarRefParseFromBundle("j", bundle);
267         EvalContextVariablePut(evalctx, ref_j,
268                                (Rlist *) NULL, CF_DATA_TYPE_STRING_LIST,
269                                NULL);
270         VarRefDestroy(ref_j);
271     }
272 
273     /* TEST */
274     printf("Testing PromiseIteratorPrepare: %s\n", promiser);
275     PromiseIteratorPrepare(iterctx, evalctx, promiser_copy);
276 
277     /* CHECK */
278     assert_true(iterctx->wheels != NULL);
279 
280     size_t wheels_num = SeqLength(iterctx->wheels);
281     assert_int_equal(wheels_num, expected_wheels_num);
282 
283     for (size_t i = 0; i < expected_wheels_num; i++)
284     {
285         const Wheel *wheel = SeqAt(iterctx->wheels, i);
286         assert_string_equal(wheel->varname_unexp, expected_wheels[i]);
287     }
288 
289     /* CLEANUP */
290     free(promiser_copy);
291     PromiseIteratorDestroy(iterctx);
292     EvalContextStackPopFrame(evalctx);
293     EvalContextStackPopFrame(evalctx);
294     PolicyDestroy(policy);
295     EvalContextDestroy(evalctx);
296 }
test_PromiseIteratorPrepare(void)297 static void test_PromiseIteratorPrepare(void)
298 {
299     IteratorPrepare_TestHelper("", 0, NULL);
300     /* No wheel added for "blah" because this variable does not resolve. */
301     IteratorPrepare_TestHelper("$(blah)", 0, NULL);
302     /* "$(i)" is a valid list, but these syntaxes are not correct. */
303     IteratorPrepare_TestHelper("i", 0, NULL);
304     IteratorPrepare_TestHelper("$i", 0, NULL);
305     IteratorPrepare_TestHelper("$(i", 0, NULL);
306     /* The following however is correct and should add one wheel */
307     IteratorPrepare_TestHelper("$(i)", 1,
308                                (const char *[]) {"i"});
309     IteratorPrepare_TestHelper("$(i))", 1,
310                                (const char *[]) {"i"});
311     IteratorPrepare_TestHelper("$(i)(", 1,
312                                (const char *[]) {"i"});
313     IteratorPrepare_TestHelper("$(i)$(", 1,
314                                (const char *[]) {"i"});
315     /* The same variable twice should just add one wheel. */
316     IteratorPrepare_TestHelper("$(i)$(i)", 1,
317                                (const char *[]) {"i"});
318     /* "$(ij)" does not resolve. */
319     IteratorPrepare_TestHelper("$(i)$(ij)", 1,
320                                (const char *[]) {"i"});
321     /* Both "$(i)" and "$(j)" resolve. */
322     IteratorPrepare_TestHelper("$(i)$(j)", 2,
323                                (const char *[]) {"i","j"});
324     IteratorPrepare_TestHelper("$(i))$(j)", 2,
325                                (const char *[]) {"i","j"});
326     IteratorPrepare_TestHelper("0$(i)$(j)", 2,
327                                (const char *[]) {"i","j"});
328     IteratorPrepare_TestHelper("$(i)1$(j)", 2,
329                                (const char *[]) {"i","j"});
330     IteratorPrepare_TestHelper("$(i)$(j)2", 2,
331                                (const char *[]) {"i","j"});
332     IteratorPrepare_TestHelper("0$(i)1$(j)", 2,
333                                (const char *[]) {"i","j"});
334     IteratorPrepare_TestHelper("0$(i)1$(j)2", 2,
335                                (const char *[]) {"i","j"});
336     /* Any variable dependent on other variables should be added as a wheel. */
337     IteratorPrepare_TestHelper("$(A[$(i)][$(j)])", 3,
338                                (const char *[]) {"i","j", "A[$(i)][$(j)]"});
339     /* Even if the inner variables don't resolve. */
340     IteratorPrepare_TestHelper("$(A[$(blah)][$(blue)])", 1,
341                                (const char *[]) {"A[$(blah)][$(blue)]"});
342     IteratorPrepare_TestHelper("$(A[1][2]) $(A[$(i)][$(j)])", 3,
343                                (const char *[]) {"i","j", "A[$(i)][$(j)]"});
344     IteratorPrepare_TestHelper("$(A[$(B[$(i)])][$(j)])", 4,
345                                (const char *[]) {"i", "B[$(i)]", "j", "A[$(B[$(i)])][$(j)]"});
346     IteratorPrepare_TestHelper("$(A[$(B[$(i)][$(j)])])", 4,
347                                (const char *[]) {"i","j", "B[$(i)][$(j)]", "A[$(B[$(i)][$(j)])]"});
348 }
349 
350 
351 
main()352 int main()
353 {
354     PRINT_TEST_BANNER();
355     const UnitTest tests[] =
356     {
357         unit_test(test_FindDollarParen),
358         unit_test(test_IsMangled),
359         unit_test(test_MangleVarRefString),
360         unit_test(test_PromiseIteratorPrepare),
361     };
362 
363     int ret = run_tests(tests);
364 
365     return ret;
366 }
367