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

181
src/env.c
View File

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

View File

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