From e20b4c3a5dfe081fa2d6d772617307fae4689698 Mon Sep 17 00:00:00 2001 From: physick Date: Fri, 31 Jul 2026 15:21:45 +0500 Subject: More desriptive output --- src/puzzles/puzzle.c | 211 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 173 insertions(+), 38 deletions(-) (limited to 'src/puzzles/puzzle.c') diff --git a/src/puzzles/puzzle.c b/src/puzzles/puzzle.c index 11328a8..2da9ffc 100644 --- a/src/puzzles/puzzle.c +++ b/src/puzzles/puzzle.c @@ -57,6 +57,64 @@ void FreePuzzle(Puzzle *self) { free(self); } +void PrintArgumentToSB(PuzzleIO *io, StringBuilder *sb) { + if (sb == NULL || io == NULL) return; + char buf[128]; + switch (io->type) { + case (WREN_TYPE_BOOL): + bool value = *(bool *)io->value; + AppendStringBuilder(sb, value ? "true" : "false"); + return; + case (WREN_TYPE_NUM): + sprintf(buf, "%lf", *(double *)io->value) ; + AppendStringBuilder(sb, buf); + break; + case (WREN_TYPE_LIST): + AppendStringBuilder(sb, "[TODO]"); + break; + case (WREN_TYPE_MAP): + // TODO + return; + case (WREN_TYPE_NULL): + AppendStringBuilder(sb, "null"); + break; + case (WREN_TYPE_STRING): + sprintf(buf, "\"%s\"", (char *)io->value) ; + AppendStringBuilder(sb, buf); + break; + default: + return; + } +} + +bool PrintTestCallToSB(Test *test, StringBuilder *sb) { + if (test == NULL || test->MainMethodSignature == NULL || test->RecieverName == NULL) + return false; + AppendStringBuilder(sb, test->RecieverName); + AppendStringBuilder(sb, "."); + size_t sig_len = strlen(test->MainMethodSignature); + size_t arg_ptr = 0; + for (size_t i = 0; i < sig_len; i++) { + char ch = test->MainMethodSignature[i]; + + if (ch != '_') { + char buf[2]; + buf[0] = ch; buf[1] = 0; + AppendStringBuilder(sb, buf); + continue; + } + if (arg_ptr >= test->argc) { + AppendStringBuilder(sb, "null"); + continue; + } + + PuzzleIO arg = test->argv[arg_ptr]; + PrintArgumentToSB(&arg, sb); + arg_ptr += 1; + } + return true; +} + // We are currenttly void PutIOIntoSlot(int slot, PuzzleIO *io, WrenVM *vm) { switch (io->type) { @@ -83,33 +141,69 @@ void PutIOIntoSlot(int slot, PuzzleIO *io, WrenVM *vm) { } } -// The cleanest way to do it is move this from the CheckResult enum -bool checkResultString(PuzzleIO *io, WrenVM *vm) { - const char *res = wrenGetSlotString(vm, 0); - if (res == NULL || io->value == NULL) return false; - return strcmp(res, io->value) == 0; +const char *GetTypeName(WrenType type) { + switch (type) { + case WREN_TYPE_BOOL: return "bool"; + case WREN_TYPE_NUM: return "num"; + case WREN_TYPE_FOREIGN: return "foreign"; + case WREN_TYPE_LIST: return "list"; + case WREN_TYPE_MAP: return "map"; + case WREN_TYPE_NULL: return "null"; + case WREN_TYPE_STRING: return "string"; + case WREN_TYPE_UNKNOWN: return "unknown"; + } } -bool CheckResult(PuzzleIO *io, WrenVM *vm) { +bool CheckResult(PuzzleIO *io, WrenVM *vm, char *outp) { WrenType actual_type = wrenGetSlotType(vm, 0); + if (io->type != actual_type) { + sprintf(outp, "Expected type %s, got %s", + GetTypeName(io->type), + GetTypeName(actual_type)); + return false; + } + bool output = false; switch (io->type) { - case (WREN_TYPE_BOOL): - if (actual_type != WREN_TYPE_BOOL) return false; - if (io->value == NULL) return false; - return wrenGetSlotBool(vm, 0) == *((bool *)io->value); - - case (WREN_TYPE_NUM): - if (actual_type != WREN_TYPE_NUM) return false; - if (io->value == NULL) return false; - return wrenGetSlotDouble(vm, 0) == *((double *)io->value); + case (WREN_TYPE_BOOL): + { + if (io->value == NULL) return false; // Invalid puzzle + bool result = wrenGetSlotBool(vm, 0); + output = result == *((bool *)io->value); + if (!output) + sprintf(outp, "Expected '%s', got '%s'", + result ? "true" : "false", + output ? "true" : "false"); + return output; + } + + case (WREN_TYPE_NUM): + { + if (io->value == NULL) return false; // Invalid puzzle + double result = wrenGetSlotDouble(vm, 0); + output = result == *((double *)io->value); + if (!output) + sprintf(outp, "Expected '%lf', got '%lf'", + *((double *)io->value), + result); + return output; + } case (WREN_TYPE_NULL): return actual_type == WREN_TYPE_NULL; case (WREN_TYPE_STRING): - if (actual_type != WREN_TYPE_STRING) return false; - return checkResultString(io, vm); + { + if (io->value == NULL) return false; // Invalid puzzle + + const char *result = wrenGetSlotString(vm, 0); + output = strcmp(result, io->value) == 0; + if (!output) + sprintf(outp, "Expected '%s', got '%s'", + (char *)io->value, + result); + return output; + } case (WREN_TYPE_LIST): case (WREN_TYPE_MAP): @@ -118,19 +212,33 @@ bool CheckResult(PuzzleIO *io, WrenVM *vm) { } } -enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm, size_t max_op) { + + +TestResult RunTest(Test *test, WrenVM *vm, size_t max_op) { wrenEnsureSlots(vm, test->argc + 1); // finction handle + arguments wrenGetVariable(vm, USER_MODULE_NAME, test->RecieverName, 0); + char outp_buf[512]; WrenHandle *obj_handle = wrenGetSlotHandle(vm, 0); if (obj_handle == NULL) { - return RESULT_COMPTIME_NO_ENTRY; + sprintf(outp_buf, "No such class as %s", test->RecieverName); + return (TestResult) { + .res = RESULT_COMPTIME_NO_ENTRY, + .message = strdup(outp_buf), + }; } WrenHandle *fn_handle = wrenMakeCallHandle(vm, test->MainMethodSignature); if (fn_handle == NULL) { wrenReleaseHandle(vm, obj_handle); - return RESULT_COMPTIME_NO_ENTRY; + sprintf(outp_buf, "No such method as %s in a class %s", + test->MainMethodSignature, + test->RecieverName); + + return (TestResult) { + .res = RESULT_COMPTIME_NO_ENTRY, + .message = strdup(outp_buf), + }; } wrenSetSlotHandle(vm, 0, obj_handle); @@ -141,25 +249,31 @@ enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm, size_t max_op) { WrenInterpretResult call_result = wrenCallLim(vm, fn_handle, max_op); switch (call_result) { - case WREN_RESULT_COMPILE_ERROR: - return RESULT_COMPTIME_ERR; + case WREN_RESULT_COMPILE_ERROR: + return (TestResult) { .res = RESULT_COMPTIME_ERR, .message = NULL }; case WREN_RESULT_RUNTIME_ERROR: - return RESULT_RUNTIME_ERR; + return (TestResult) { .res = RESULT_RUNTIME_ERR, .message = NULL }; case WREN_RESULT_RUNTIME_LIMIT: - return RESULT_TIMEOUT; + return (TestResult) { + .res = RESULT_RUNTIME_ERR, + .message = strdup("The execution halted") + }; default: break; } - bool result = CheckResult(&test->ExpectedResult, vm); + bool result = CheckResult(&test->ExpectedResult, vm, outp_buf); wrenReleaseHandle(vm, fn_handle); wrenReleaseHandle(vm, obj_handle); if (result) { - return RESULT_OK; - } else { - return RESULT_WRONG_ANSWER; + return (TestResult) { .res = RESULT_OK, .message = NULL }; } + + return (TestResult) { + .res = RESULT_WRONG_ANSWER, + .message = strdup(outp_buf) + }; } // Returns the res ptr. Does not modify the address @@ -203,21 +317,42 @@ SubmitionResult *SubmitSolution(Puzzle *self, char *script) { res->result = RESULT_INIT_ERROR; return res; } - + + StringBuilder *sb = GetOutputSb(vm); + AppendStringBuilder(sb, "Evaluating user code...\n"); res = TryEvaluateUserCode(vm, script, res, cfg->MaxOperations); - if (res->result != RESULT_OK) { - return PrepareResult(res, vm, res->result); + switch (res->result) { + case RESULT_OK: break; + case RESULT_COMPTIME_ERR: + return PrepareResult(res, vm, res->result); + break; + case RESULT_RUNTIME_ERR: + return PrepareResult(res, vm, res->result); + break; + case RESULT_TIMEOUT: + AppendStringBuilder(sb, "The execution halted\n"); + return PrepareResult(res, vm, res->result); + break; + default: break; } + AppendStringBuilder(sb, "Success!\n"); for (size_t i = 0; i < self->TestC; i++) { - enum PUZZLE_TEST_RESULT test_res = RunTest(&self->Tests[i], vm, cfg->MaxOperations); - switch (test_res) { - case WREN_RESULT_COMPILE_ERROR: - return PrepareResult(res, vm, RESULT_COMPTIME_ERR); - case WREN_RESULT_RUNTIME_ERROR: - return PrepareResult(res, vm, RESULT_RUNTIME_ERR); - default: break; + Test *test = &self->Tests[i]; + AppendStringBuilder(sb, "\nRunning test "); + PrintTestCallToSB(test, sb); + AppendStringBuilder(sb, "... \n"); + TestResult test_res = RunTest(test, vm, cfg->MaxOperations); + if (test_res.message != NULL) { + AppendStringBuilder(sb, test_res.message); + AppendStringBuilder(sb, "\n"); + free(test_res.message); + } + if (test_res.res != RESULT_OK) { + AppendStringBuilder(sb, "Test failed.\n"); + return PrepareResult(res, vm, test_res.res); } + AppendStringBuilder(sb, "Success!\n"); } return PrepareResult(res, vm, RESULT_OK); -- cgit v1.3