Split up some of the native testing code.

Makes running specific tests a little cleaner.
This commit is contained in:
Sage Vaillancourt 2022-04-13 16:48:09 -04:00 committed by Sage Vaillancourt
parent 54410030f7
commit 80255af52e
2 changed files with 102 additions and 87 deletions

111
src/env.c
View File

@ -115,14 +115,19 @@ struct Environment envForLambda(const Object* params, const Object* arguments, i
.refs = 1, .refs = 1,
}; };
// Evaluate the `argument` list
const Object* param = params->list;
const Object* argument = arguments; const Object* argument = arguments;
for (int i = 0; i < paramCount; i++) { for (int i = 0; i < paramCount && param; i++) {
const char* paramName = itemAt(params, i)->string; Object newEnvObj = eval(argument, outer);
// Eval the `argument` list
Object newEnvObj = argument ? eval(argument, outer) : errorWithContext(NOT_ENOUGH_ARGUMENTS, paramName); const char* paramName = param->string;
addToEnv(&env, paramName, newEnvObj); // Could use eval_forms? addToEnv(&env, paramName, newEnvObj);
cleanObject(&newEnvObj); cleanObject(&newEnvObj);
argument = argument ? argument->forward : NULL; argument = argument ? argument->forward : NULL;
param = param->forward;
} }
env.outer = outer; env.outer = outer;
@ -224,8 +229,7 @@ struct Environment defaultEnv()
#endif #endif
}; };
unsigned i; for (unsigned i = 0; i < sizeof(symFuncs) / sizeof(symFuncs[0]); i++) {
for (i = 0; i < sizeof(symFuncs) / sizeof(symFuncs[0]); i++) {
addFunc(symFuncs[i].sym, symFuncs[i].func, &e); addFunc(symFuncs[i].sym, symFuncs[i].func, &e);
} }
@ -391,7 +395,9 @@ Object help(Object* params, int length, struct Environment* env)
} }
for (int i = 0; i < currentHelp; i++) { for (int i = 0; i < currentHelp; i++) {
struct helpText h = helpTexts[i]; struct helpText h = helpTexts[i];
if (strcmp(symbol, h.symbol) == 0) { if (strcmp(symbol, h.symbol) != 0) {
continue;
}
Object text = withLen(1024, TYPE_STRING); Object text = withLen(1024, TYPE_STRING);
char* textCursor = text.string; char* textCursor = text.string;
textCursor += sprintf(textCursor, "%s", h.help); textCursor += sprintf(textCursor, "%s", h.help);
@ -411,7 +417,6 @@ Object help(Object* params, int length, struct Environment* env)
} }
return text; return text;
} }
}
for (int i = 0; i < dictionary.structCount; i++) { for (int i = 0; i < dictionary.structCount; i++) {
if (strcmp(dictionary.structDefs[i].name, symbol) == 0) { if (strcmp(dictionary.structDefs[i].name, symbol) == 0) {
@ -438,37 +443,9 @@ Object help(Object* params, int length, struct Environment* env)
return nullTerminated("Help not found!"); return nullTerminated("Help not found!");
} }
// Returns number of failures, or -1 if the requested specificTest is invalid /// Returns 1 if the test passed, or 0 if it failed
int runTests(int detailed, int specificTest) int runTest(const char* test, const char* expected, int detailed)
{ {
int isSpecific = specificTest != -1;
if (specificTest >= currentHelp) {
return -1;
}
if (!isSpecific) {
printf("::NATIVE TESTS::\n");
}
int failureCount = 0;
int passCount = 0;
int start = isSpecific ? specificTest : 0;
int end = isSpecific ? specificTest + 1 : currentHelp;
for (int hi = start; hi < end; hi++) {
struct helpText h = helpTexts[hi];
if (h.tests) {
if (detailed && h.testCount > 0) {
if (isSpecific) {
printf("`%s` ", h.symbol);
} else {
printf(" `%s` ", h.symbol);
}
}
for (int ti = 0; ti < h.testCount; ti += 2) {
const char* test = h.tests[ti];
const char* expected = h.tests[ti + 1];
if (test[0] == ';') {
continue;
}
struct Environment env = defaultEnv(); struct Environment env = defaultEnv();
Object o = parseEval(test, &env); Object o = parseEval(test, &env);
size_t length; size_t length;
@ -478,8 +455,9 @@ int runTests(int detailed, int specificTest)
while (expected[expectedLen] && expected[expectedLen] != ';') { while (expected[expectedLen] && expected[expectedLen] != ';') {
expectedLen++; expectedLen++;
} }
int ret;
if (strncmp(result, expected, expectedLen) != 0) { if (strncmp(result, expected, expectedLen) != 0) {
failureCount++; ret = 0;
printf("Test failed!\n"); printf("Test failed!\n");
printf("%s\n", test); printf("%s\n", test);
printf("Expected '%s' but received '%s'\n", expected, result); printf("Expected '%s' but received '%s'\n", expected, result);
@ -487,30 +465,69 @@ int runTests(int detailed, int specificTest)
if (detailed) { if (detailed) {
printf("✓"); printf("✓");
} }
passCount++; ret = 1;
} }
free(result); free(result);
deleteEnv(&env); deleteEnv(&env);
return ret;
}
void runHelpTests(struct helpText h, int detailed, int* failureCount, int* passCount)
{
if (!h.tests) {
return;
}
if (detailed && h.testCount > 0) {
printf(" `%s` ", h.symbol);
}
for (int ti = 0; ti < h.testCount; ti += 2) {
const char* test = h.tests[ti];
const char* expected = h.tests[ti + 1];
if (test[0] == ';') {
continue;
}
int* outcome = runTest(test, expected, detailed) ? passCount : failureCount;
*outcome = *outcome + 1;
} }
if (detailed && h.testCount > 0) { if (detailed && h.testCount > 0) {
printf("\n"); printf("\n");
} }
} }
// Returns number of failures, or -1 if the requested specificTest is invalid
int runTests(int detailed, int specificTest)
{
if (specificTest >= currentHelp) {
return -1;
} }
int failureCount = 0;
int passCount = 0;
int isSpecificTest = specificTest != -1;
if(isSpecificTest) {
struct helpText h = helpTexts[specificTest];
runHelpTests(h, detailed, &failureCount, &passCount);
return failureCount;
}
printf("::NATIVE TESTS::\n");
for (int hi = 0; hi < currentHelp; hi++) {
runHelpTests(helpTexts[hi], detailed, &failureCount, &passCount);
}
if (passCount > 0) { if (passCount > 0) {
printf(""); printf("");
} }
if (!isSpecific) {
printf("%d tests passed!\n", passCount); printf("%d tests passed!\n", passCount);
}
if (failureCount > 0) { if (failureCount > 0) {
printf(""); printf("%d tests failed!\n", failureCount);
}
if (!isSpecific || failureCount != 0) {
printf("%d tests failed!\n", failureCount);
} }
// fprintf(stderr, "TOTAL ALLOCATIONS: %d\n", getAllocations()); // fprintf(stderr, "TOTAL ALLOCATIONS: %d\n", getAllocations());
// fprintf(stderr, "TOTAL BYTES: %zu\n", getBytes()); // fprintf(stderr, "TOTAL BYTES: %zu\n", getBytes());
return failureCount; return failureCount;
} }

View File

@ -59,10 +59,6 @@ void printColored(const char* code);
int runTests(int detailed, int specificTest); int runTests(int detailed, int specificTest);
int getTotalSearchDepth();
int getTotalSearches();
#define unused __attribute__((unused)) #define unused __attribute__((unused))
#define array_length(_array) (sizeof(_array) / sizeof((_array)[0])) #define array_length(_array) (sizeof(_array) / sizeof((_array)[0]))
@ -91,7 +87,9 @@ fn(help, "?",
" (? Output) => \"{ stdout stderr }\"\n" " (? Output) => \"{ stdout stderr }\"\n"
"\n" "\n"
" Other objects:\n" " Other objects:\n"
" (? \"Hello\") => \"Hello\"" " (? \"Hello\") => \"Hello\"\n"
"\n"
"Note: The included repl allows you to drop the parentheses."
); );