75 static char* cpMakeFileName(
char* cpBuffer,
const char* cpBase,
const char* cpDivider,
const char* cpName){
76 strcpy(cpBuffer, cpBase);
77 strcat(cpBuffer, cpDivider);
78 strcat(cpBuffer, cpName);
82 static char s_caBuf[2*PATH_MAX];
84 static char* s_cpDescription =
85 "Example demonstrating the use and usefulness of the AST.";
87 static char* s_cppCases[] = {
88 "Display application information.",
89 "Build the JSON test file from the XML test file using the APG XML parser. Must be run before other tests.",
90 "Parse all of the valid tests.",
91 "Parse all of the invalid tests.",
92 "Trace test with JSON ID number = arg2.",
94 static long int s_iCaseCount = (
long int)(
sizeof(s_cppCases) /
sizeof(s_cppCases[0]));
96 static int iHelp(
void){
99 printf(
"description: %s\n", s_cpDescription);
100 printf(
" usage: ex-trace [arg]\n");
101 printf(
" arg = n, 1 <= n <= %ld\n", s_iCaseCount);
102 printf(
" execute case number n\n");
103 printf(
" arg = anything else, or nothing at all\n");
104 printf(
" print this help screen\n");
106 for(; i < s_iCaseCount; i++){
107 printf(
"case %ld %s\n", (i + 1), s_cppCases[i]);
121 static abool bMatchU32PhraseAscii(
const char* cpString,
u32_phrase* spPhrase){
123 if(strlen(cpString) == (
size_t)spPhrase->
uiLength){
125 for(; ui < spPhrase->
uiLength; ui++){
126 if(spPhrase->
uipPhrase[ui] != (uint32_t)cpString[ui]){
137 for(; ui < spPhrase->
uiLength; ui++){
138 if(spPhrase->
uipPhrase[ui] != (uint32_t)acpString[ui]){
145 static void* vpGetConstraintsIterator(
exception* spException,
void* vpJson,
void* vpItRoot){
149 XTHROW(spException,
"could not find \"constraints\" key");
153 XTHROW(spException,
"\"constraints\" member not an array");
156 if(!vpItConstraints){
157 XTHROW(spException,
"could not find \"constraint\" members");
159 return vpItConstraints;
162 static aint uiGetTestId(
exception* spEx,
void* vpJson, json_value* spTest){
164 json_value* spChild, *spChildEnd;
165 spChild = *spTest->sppChildren;
166 spChildEnd = spChild + spTest->uiChildCount;
167 for(; spChild < spChildEnd; spChild++){
168 if(bMatchU32PhraseAscii(
"ID", spChild->spKey)){
173 XTHROW(spEx,
"expected key ID not found");
176 XTHROW(spEx,
"ID value not unsigned int");
179 XTHROW(spEx,
"ID value too big - > APG_MAX_AINT");
181 return (
aint)spChild->spNumber->uiUnsigned;
183 static aint uiGetRuleId(
exception* spEx,
void* vpJson, json_value* spTest){
185 json_value* spChild, *spChildEnd;
186 spChild = *spTest->sppChildren;
187 spChildEnd = spChild + spTest->uiChildCount;
188 for(; spChild < spChildEnd; spChild++){
189 if(bMatchU32PhraseAscii(
"ruleId", spChild->spKey)){
194 XTHROW(spEx,
"expected key ruleId not found");
197 XTHROW(spEx,
"ruleId value not unsigned int");
200 XTHROW(spEx,
"ruleId value too big - > APG_MAX_AINT");
202 return (
aint)spChild->spNumber->uiUnsigned;
206 json_value* spChild, *spChildEnd;
207 spChild = *spTest->sppChildren;
208 spChildEnd = spChild + spTest->uiChildCount;
209 for(; spChild < spChildEnd; spChild++){
210 if(bMatchU32PhraseAscii(
"input", spChild->spKey)){
215 XTHROW(spEx,
"expected key input not found");
218 XTHROW(spEx,
"input value not string");
220 if(spChild->spString->uiLength > uiBufLen){
221 XTHROW(spEx,
"input string too long - larger than uiBufLen - increase buffer size and try again");
224 for(; ui < spChild->spString->uiLength; ui++){
225 acpBuf[ui] = (
achar)spChild->spString->uipPhrase[ui];
227 return (
aint)spChild->spString->uiLength;
232 void* vpItValue = NULL;
234 aint ui, uj, uiCount, uiRuleIndex;
235 const uint32_t* uipString;
236 const achar *acpPhrase;
237 json_value* spChild, *spChildEnd;
238 json_value* spMatch, *spMatchEnd;
247 spChild = *spConstraint->sppChildren;
248 spChildEnd = spChild + spConstraint->uiChildCount;
249 for(; spChild < spChildEnd; spChild++){
250 if(spChild->uiId ==
JSON_ID_NUMBER && bMatchU32PhraseAscii(
"ruleId", spChild->spKey)){
251 uiRuleIndex = (
aint)spChild->spNumber->uiUnsigned;
259 spChild = *spConstraint->sppChildren;
260 spChildEnd = spChild + spConstraint->uiChildCount;
261 for(; spChild < spChildEnd; spChild++){
262 if(spChild->uiId ==
JSON_ID_ARRAY && bMatchU32PhraseAscii(
"match", spChild->spKey)){
265 spMatch = *spChild->sppChildren;
266 spMatchEnd = spMatch + spChild->uiChildCount;
267 for(; spMatch < spMatchEnd; spMatch++){
269 if(bMatchU32PhraseAchar(acpPhrase, spMatch->spString)){
277 printf(
"=> for rule index %d the parsed phrase did not match any strings in the list\n", (
int)uiRuleIndex);
292 static void vParseTests(
exception* spEx,
void* vpParser,
void* vpJson,
abool bValid,
void* vpItConstraints,
void* vpItTests){
293 char* cpTestName = bValid ?
"valid" :
"invalid";
294 printf(
"Parsing tests: %s\n", cpTestName);
297 aint uiTestId, uiRuleId, uiInputLen;
299 aint uiSuccessCount = 0;
300 aint uiFailCount = 0;
302 aint uiBufLen = 1024;
309 uiTestId = uiGetTestId(spEx, vpJson, spTest);
310 uiRuleId = uiGetRuleId(spEx, vpJson, spTest);
311 uiInputLen = uiGetInput(spEx, vpJson, spTest, acaBuf, uiBufLen);
321 printf(
"test ID: %d: succeeded\n", (
int)uiTestId);
325 printf(
"test ID: %d: failed\n", (
int)uiTestId);
332 printf(
"count: %d: success: %d: fail: %d\n", (
int)uiCount, (
int)uiSuccessCount, (
int)uiFailCount);
335 static int iTraceTestId(
aint uiTraceId){
336 int iReturn = EXIT_SUCCESS;
337 static void* vpJson = NULL;
338 static void* vpParser = NULL;
339 static void* vpTrace = NULL;
340 void* vpItRoot, *vpItKey, *vpItTests, *vpItConstraints;
345 aint uiTestId, uiRuleId, uiInputLen;
347 aint uiBufLen = 1024;
352 char* cpDesc =
"This program will read the JSON file built in case 2 and parse all of the valid tests.\n";
354 printf(
"%s", cpDesc);
366 char* cpJsonName = cpMakeFileName(&s_caBuf[PATH_MAX], SOURCE_DIR,
"/../output/",
"odata-abnf-testcases.json");
368 vpItConstraints = vpGetConstraintsIterator(&e, vpJson, vpItRoot);
372 XTHROW(&e,
"could not find \"valid\" key");
376 XTHROW(&e,
"\"valid\" member not an array");
380 XTHROW(&e,
"could not find \"valid\" tests");
384 uiTestId = uiGetTestId(&e, vpJson, spTest);
385 if(uiTestId == uiTraceId){
386 printf(
"Trace test: tracing %s test id %d\n", cpWhich, (
int)uiTraceId);
387 uiRuleId = uiGetRuleId(&e, vpJson, spTest);
388 uiInputLen = uiGetInput(&e, vpJson, spTest, acaBuf, uiBufLen);
396 printf(
"TRACE TEST: %d: success\n", (
int)uiTraceId);
398 printf(
"TRACE TEST: %d: failure\n", (
int)uiTraceId);
408 XTHROW(&e,
"could not find \"invalid\" key");
412 XTHROW(&e,
"\"valid\" member not an array");
416 XTHROW(&e,
"could not find \"invalid\" tests");
420 uiTestId = uiGetTestId(&e, vpJson, spTest);
421 if(uiTestId == uiTraceId){
422 printf(
"Trace test: tracing %s test id %d\n", cpWhich, (
int)uiTraceId);
423 uiRuleId = uiGetRuleId(&e, vpJson, spTest);
424 uiInputLen = uiGetInput(&e, vpJson, spTest, acaBuf, uiBufLen);
432 printf(
"TRACE TEST: %d: success\n", (
int)uiTraceId);
434 printf(
"TRACE TEST: %d: failure\n", (
int)uiTraceId);
440 printf(
"TRACE TEST: test id %d not found\n", (
int)uiTraceId);
444 iReturn = EXIT_FAILURE;
452 static int iParseValid(){
453 int iReturn = EXIT_SUCCESS;
454 static void* vpJson = NULL;
455 static void* vpParser = NULL;
456 void* vpItRoot, *vpItKey, *vpItTests, *vpItConstraints;
462 char* cpDesc =
"This program will read the JSON file built in case 2 and parse all of the valid tests.\n";
464 printf(
"%s", cpDesc);
470 char* cpJsonName = cpMakeFileName(&s_caBuf[PATH_MAX], SOURCE_DIR,
"/../output/",
"odata-abnf-testcases.json");
472 vpItConstraints = vpGetConstraintsIterator(&e, vpJson, vpItRoot);
477 XTHROW(&e,
"could not find \"valid\" key");
481 XTHROW(&e,
"\"valid\" member not an array");
485 XTHROW(&e,
"could not find \"valid\" tests");
487 vParseTests(&e, vpParser, vpJson,
APG_TRUE, vpItConstraints, vpItTests);
491 iReturn = EXIT_FAILURE;
499 static int iParseInvalid(){
500 int iReturn = EXIT_SUCCESS;
501 static void* vpJson = NULL;
502 static void* vpParser = NULL;
503 void* vpItRoot, *vpItKey, *vpItTests, *vpItConstraints;
508 char* cpDesc =
"This program will read the JSON file built in case 2 and parse all of the valid tests.\n";
510 printf(
"%s", cpDesc);
516 char* cpJsonName = cpMakeFileName(&s_caBuf[PATH_MAX], SOURCE_DIR,
"/../output/",
"odata-abnf-testcases.json");
518 vpItConstraints = vpGetConstraintsIterator(&e, vpJson, vpItRoot);
521 XTHROW(&e,
"could not find \"valid\" key");
525 XTHROW(&e,
"\"invalid\" member not an array");
529 XTHROW(&e,
"could not find \"invalid\" tests");
531 vParseTests(&e, vpParser, vpJson,
APG_FALSE, vpItConstraints, vpItTests);
535 iReturn = EXIT_FAILURE;
559 if(bCompU32(spAttNames, spCtx->
spRule)){
571 XTHROW(spCtx->
spException,
"vStartTag: Constraint node must have a \"Rule\" attribute");
573 }
else if(bCompU32(spName, spCtx->
spTestCase)){
578 for(; ui < uiAttCount; ui++, spAttNames++, spAttValues++){
579 if(bCompU32(spAttNames, spCtx->
spName)){
585 if(bCompU32(spAttNames, spCtx->
spRule)){
591 XTHROW(spCtx->
spException,
"character buffer too small for name conversion to string");
599 if(bCompU32(spAttNames, spCtx->
spFailAt)){
601 const uint32_t* uipDigit = spAttValues->
uipPhrase;
602 const uint32_t* uipDigitEnd = uipDigit + spAttValues->
uiLength;
603 uint32_t uiNum = *uipDigit++ - 48;
604 for(; uipDigit < uipDigitEnd; uipDigit++){
605 uiNum = 10 * uiNum + (
aint)(*uipDigit - 48);
624 }
else if(bCompU32(spName, spCtx->
spMatch)){
626 XTHROW(spCtx->
spException,
"vStartTag: \"Match\" node not child of \"Constraint\" node");
632 memcpy((
void*)uipMem, (
void*)spContent->
uipPhrase, (
sizeof(uint32_t) * spContent->
uiLength));
633 spPhrase->
uipPhrase = (
const uint32_t*)uipMem;
635 }
else if(bCompU32(spName, spCtx->
spInput)){
645 spCtx->
vpMem = vpMem;
652 spCtx->
cpXmlName = cpMakeFileName(s_caBuf, SOURCE_DIR,
"/../input/",
"odata-abnf-testcases.xml");
653 spCtx->
cpJsonName = cpMakeFileName(&s_caBuf[PATH_MAX], SOURCE_DIR,
"/../output/",
"odata-abnf-testcases.json");
669 for(; ui < spCtx->
uiRuleCount; ui++, spConstraint++){
677 static int iMakeJsonApgXml() {
678 int iReturn = EXIT_SUCCESS;
679 static void* vpMem = NULL;
680 static void* vpXml = NULL;
681 static void* vpParser = NULL;
682 static void* vpJson = NULL;
683 static void* vpBuilder = NULL;
685 char* cpDesc =
"This program will build a JSON file that will be used for the parsing tests.\n"
686 "It first reads the complete list of ABNF grammar rules for the OData grammar.\n"
687 "It then reads the XML file of test cases and an APG XML parser is used to extract the test information.\n"
688 "The XML file has valid tests and invalid tests with an attribute that indicates that the test is to fail.\n"
689 "The valid and invalid tests are interspersed. This program will separate the valid and invalid tests.\n"
690 "The root JSON object will have two members - an array of valid test object and an array of invalid test objects.\n";
696 printf(
"%s", cpDesc);
714 aint uiRoot, uiKey, uiValue, uiObj, uiMatchArray, uiConstraintsArray, uiValidArray, uiInvalidArray;
741 for(; spConstraint < spConstraintEnd; spConstraint++){
754 for(; spPhrase < spPhraseEnd; spPhrase++){
766 for(ui64 = 0;spTest < spTestEnd; spTest++, ui64++){
814 uint8_t* ucpBytes =
ucpJsonWrite(vpJson, spValue, &uiCount);
821 printf(
"\nJSON file written to %s\n", spCtx->
cpJsonName);
826 iReturn = EXIT_FAILURE;
846 int main(
int argc,
char **argv) {
848 long int iTestId = 0;
850 if(
sizeof(
achar) !=
sizeof(uint8_t)){
851 char* cpMsg =
"For these tests, sizeof(achar) == sizeof(uint8_t) must be true.\n"
852 "Insure that in the build the symbol APG_ACHAR is undefined or defined with a value of 8.\n";
857 iCase = atol(argv[1]);
859 if((iCase > 0) && (iCase <= s_iCaseCount)){
860 printf(
"%s\n", s_cppCases[iCase -1]);
866 return iMakeJsonApgXml();
868 return iParseValid();
870 return iParseInvalid();
873 iTestId = atol(argv[2]);
874 return iTraceTestId((
aint)iTestId);