Skip to content

Commit 09e599a

Browse files
committed
Add tests around quantifiers to ensure both matching and non-matching compliance.
1 parent 84767a7 commit 09e599a

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

tests/test-grammar-integration.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,115 @@ ws ::= [ \t\n\r]?)""";
153153
llama_grammar_free(grammar);
154154
}
155155

156+
static void test_quantifiers() {
157+
// Populate test data with grammar strings and their associated collections of expected passing and failing strings
158+
const std::vector<
159+
std::tuple<
160+
std::string,
161+
std::vector<std::string>,
162+
std::vector<std::string>>>
163+
test_data = {
164+
{
165+
// Grammar
166+
R"""(root ::= "a"*)""",
167+
// Passing strings
168+
{
169+
"",
170+
"a",
171+
"aaaaa",
172+
"aaaaaaaaaaaaaaaaaa",
173+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
174+
},
175+
// Failing strings
176+
{
177+
"b",
178+
"ab",
179+
"aab",
180+
"ba",
181+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
182+
}
183+
},
184+
{
185+
// Grammar
186+
R"""(root ::= "a"+)""",
187+
// Passing strings
188+
{
189+
"a",
190+
"aaaaa",
191+
"aaaaaaaaaaaaaaaaaa",
192+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
193+
},
194+
// Failing strings
195+
{
196+
"",
197+
"b",
198+
"ab",
199+
"aab",
200+
"ba",
201+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
202+
}
203+
},
204+
{
205+
// Grammar
206+
R"""(root ::= "a"?)""",
207+
// Passing strings
208+
{
209+
"",
210+
"a"
211+
},
212+
// Failing strings
213+
{
214+
"b",
215+
"ab",
216+
"aa",
217+
"ba",
218+
}
219+
}
220+
};
221+
222+
for (const auto & test_datum : test_data) {
223+
const auto & [grammar_str, passing_strings, failing_strings] = test_datum;
224+
225+
auto grammar = build_grammar(grammar_str);
226+
227+
// Save the original grammar stacks so that we can reset after every new string we want to test
228+
auto original_stacks = grammar->stacks;
229+
230+
// Passing strings
231+
for (const auto & test_string : passing_strings) {
232+
bool matched = match_string(test_string, grammar);
233+
234+
if (!matched) {
235+
fprintf(stderr, "Against grammar: %s\n", grammar_str.c_str());
236+
fprintf(stderr, "Failed to match string: %s\n", test_string.c_str());
237+
}
238+
239+
assert(matched);
240+
241+
// Reset the grammar stacks
242+
grammar->stacks = original_stacks;
243+
}
244+
245+
// Failing strings
246+
for (const auto & test_string : failing_strings) {
247+
bool matched = match_string(test_string, grammar);
248+
249+
if (matched) {
250+
fprintf(stderr, "Against grammar: %s\n", grammar_str.c_str());
251+
fprintf(stderr, "Improperly matched string: %s\n", test_string.c_str());
252+
}
253+
254+
assert(!matched);
255+
256+
// Reset the grammar stacks
257+
grammar->stacks = original_stacks;
258+
}
259+
260+
// Clean up allocated memory
261+
llama_grammar_free(grammar);
262+
}
263+
}
264+
156265
static void test_failure_missing_root() {
157266
// Test case for a grammar that is missing a root rule
158267
const std::string grammar_str = R"""(rot ::= expr
@@ -189,6 +298,7 @@ number ::= [0-9]+)""";
189298
int main() {
190299
test_simple_grammar();
191300
test_complex_grammar();
301+
test_quantifiers();
192302
test_failure_missing_root();
193303
test_failure_missing_reference();
194304
fprintf(stdout, "All tests passed.\n");

0 commit comments

Comments
 (0)