Skip to content

Commit

Permalink
Have native test runners consume answers.tsv
Browse files Browse the repository at this point in the history
  • Loading branch information
LivInTheLookingGlass committed Aug 17, 2024
1 parent f5955f1 commit 27b8a60
Show file tree
Hide file tree
Showing 8 changed files with 633 additions and 105 deletions.
3 changes: 2 additions & 1 deletion c/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ USER_FLAG?=--user
PIP?=$(PY) -m pip
BLUE=\033[0;34m
NC=\033[0m # No Color
O?=2

ifneq ($(https_proxy), )
PROXY_ARG=--proxy=$(https_proxy)
Expand Down Expand Up @@ -57,7 +58,7 @@ lint:

.PHONY: native
native: ../LICENSE Unity/src/unity.c
@$(CC) test.c Unity/src/unity.c -O2 -g -lm -lc -Wall -Werror -std=gnu99 -march=native -flto
@$(CC) test.c Unity/src/unity.c -O$(O) -g -lm -lc -Wall -Werror -std=gnu99 -march=native -flto

.PHONY: clean
clean:
Expand Down
152 changes: 152 additions & 0 deletions c/src/include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef _WIN32
#include <direct.h>
#include <windows.h>
Expand Down Expand Up @@ -100,3 +101,154 @@ char *get_data_file(const char *name) {

return buffer;
}

typedef enum {
ERROR,
INT8,
INT16,
INT32,
INT64,
UINT8,
UINT16,
UINT32,
UINT64,
STR,
} AnswerType;

typedef struct {
union {
uint8_t UINT8;
uint16_t UINT16;
uint32_t UINT32;
uint64_t UINT64;
int8_t INT8;
int16_t INT16;
int32_t INT32;
int64_t INT64;
char *STR;
} value;
uint16_t id : 12;
AnswerType type : 4;
} Answer;

Answer get_answer(uint16_t id) {
char *linepointer;
char *tabpointer;
Answer ret = {
id: id,
};
char *answers = get_data_file("answers.tsv");

if (!answers) {
fprintf(stderr, "Error: Unable to get data from file\n");
return ret;
}

char s_id[6];
snprintf(s_id, sizeof(s_id), "%" PRIu16, id);

char *line = strtok_r(answers, "\n", &linepointer); // skip header
while ((line = strtok_r(NULL, "\n", &linepointer)) != NULL) {
char *token = strtok_r(line, "\t", &tabpointer);
if (strcmp(token, s_id) != 0)
continue;

token = strtok_r(NULL, "\t", &tabpointer);
if (!token)
continue;

if (strcmp(token, "uint") == 0) {
ret.type = UINT8; // will adjust size later
} else if (strcmp(token, "int") == 0) {
ret.type = INT8; // will adjust size later
} else if (strcmp(token, "str") == 0) {
ret.type = STR;
} else {
fprintf(stderr, "Error: Unknown type '%s'\n", token);
return ret;
}

token = strtok_r(NULL, "\t", &tabpointer);
if (!token)
continue;
size_t size = strtoull(token, NULL, 10);

token = strtok_r(NULL, "\t", &tabpointer);
if (!token)
continue;

switch (ret.type) {
case UINT8:
case UINT16:
case UINT32:
case UINT64:
switch (size) {
case 8:
ret.value.UINT8 = (uint8_t)strtoul(token, NULL, 10);
break;
case 16:
ret.value.UINT16 = (uint16_t)strtoul(token, NULL, 10);
ret.type = UINT16;
break;
case 32:
ret.value.UINT32 = strtoul(token, NULL, 10);
ret.type = UINT32;
break;
case 64:
ret.value.UINT64 = strtoull(token, NULL, 10);
ret.type = UINT64;
break;
default:
fprintf(stderr, "Error: Unsupported uint size %" PRIu64 "\n", (uint64_t)size);
Answer err = {0};
return err;
}
break;
case INT8:
case INT16:
case INT32:
case INT64:
switch (size) {
case 8:
ret.value.INT8 = (int8_t)strtol(token, NULL, 10);
break;
case 16:
ret.value.INT16 = (int16_t)strtol(token, NULL, 10);
ret.type = INT16;
break;
case 32:
ret.value.INT32 = strtol(token, NULL, 10);
ret.type = INT32;
break;
case 64:
ret.value.INT64 = strtoll(token, NULL, 10);
ret.type = INT64;
break;
default:
fprintf(stderr, "Error: Unsupported int size %" PRIu64 "\n", (uint64_t)size);
Answer err = {0};
return err;
}
break;
case STR:
ret.value.STR = (char *)malloc(size + 1);
if (ret.value.STR) {
strncpy(ret.value.STR, token, size);
ret.value.STR[size] = 0;
} else {
fprintf(stderr, "Error: Memory allocation failed for string\n");
Answer err = {0};
return err;
}
break;
case ERROR:
fprintf(stderr, "Error: Unknown type (should be unreachable)\n");
Answer err = {0};
return err;
}
break;
}

free(answers);
return ret;
}
119 changes: 66 additions & 53 deletions c/test.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#define UNITY_SUPPORT_TEST_CASES
#include <stdint.h>
#include <inttypes.h>
#include "src/include/utils.h"
#include "Unity/src/unity.h"
#include "src/p0001.c"
#include "src/p0002.c"
Expand Down Expand Up @@ -28,51 +29,37 @@
#include "src/p0076.c"
#include "src/p0836.c"

typedef enum {
INT8,
INT16,
INT32,
INT64,
UINT8,
UINT16,
UINT32,
UINT64,
STR,
} AnswerType;

typedef struct {
uint32_t id;
AnswerType type;
void *answer;
uint16_t id;
void *(*func)();
} Answer;
} ProblemRef;

const Answer answers[] = {
{ 1, INT32, (void *)233168, (void *(*)())p0001 },
{ 2, INT32, (void *)4613732, (void *(*)())p0002 },
{ 3, INT16, (void *)6857, (void *(*)())p0003 },
{ 4, INT32, (void *)906609, (void *(*)())p0004 },
{ 5, INT32, (void *)232792560, (void *(*)())p0005 },
{ 6, INT32, (void *)25164150, (void *(*)())p0006 },
{ 7, INT32, (void *)104743, (void *(*)())p0007 },
{ 8, INT64, (void *)23514624000, (void *(*)())p0008 },
{ 9, INT32, (void *)31875000, (void *(*)())p0009 },
{ 10, INT64, (void *)142913828922, (void *(*)())p0010 },
{ 11, INT32, (void *)70600674, (void *(*)())p0011 },
// { 12, INT32, (void *)76576500, (void *(*)())p0012 },
{ 13, INT64, (void *)5537376230, (void *(*)())p0013 },
{ 14, INT32, (void *)837799, (void *(*)())p0014 },
{ 15, INT64, (void *)137846528820, (void *(*)())p0015 },
{ 16, INT16, (void *)1366, (void *(*)())p0016 },
{ 17, INT16, (void *)21124, (void *(*)())p0017 },
{ 19, UINT8, (void *)171, (void *(*)())p0019 },
{ 20, INT16, (void *)648, (void *(*)())p0020 },
{ 22, INT32, (void *)871198282, (void *(*)())p0022 },
{ 25, INT16, (void *)4782, (void *(*)())p0025 },
{ 30, INT32, (void *)443839, (void *(*)())p0030 },
{ 34, UINT16, (void *)40730, (void *(*)())p0034 },
{ 76, INT32, (void *)190569291, (void *(*)())p0076 },
{ 836, STR, (void *)"aprilfoolsjoke", (void *(*)())p0836 },
ProblemRef answers[] = {
{ 1, (void *(*)())p0001 },
{ 2, (void *(*)())p0002 },
{ 3, (void *(*)())p0003 },
{ 4, (void *(*)())p0004 },
{ 5, (void *(*)())p0005 },
{ 6, (void *(*)())p0006 },
{ 7, (void *(*)())p0007 },
{ 8, (void *(*)())p0008 },
{ 9, (void *(*)())p0009 },
{ 10, (void *(*)())p0010 },
{ 11, (void *(*)())p0011 },
// { 12, (void *(*)())p0012 },
{ 13, (void *(*)())p0013 },
{ 14, (void *(*)())p0014 },
{ 15, (void *(*)())p0015 },
{ 16, (void *(*)())p0016 },
{ 17, (void *(*)())p0017 },
{ 19, (void *(*)())p0019 },
{ 20, (void *(*)())p0020 },
{ 22, (void *(*)())p0022 },
{ 25, (void *(*)())p0025 },
{ 30, (void *(*)())p0030 },
{ 34, (void *(*)())p0034 },
{ 76, (void *(*)())p0076 },
{ 836, (void *(*)())p0836 },
};
const size_t ANSWERS_LEN = sizeof(answers) / sizeof(answers[0]);
static size_t current_index = 0;
Expand All @@ -82,33 +69,59 @@ void setUp(void) {}
void tearDown(void) {}

void test_euler_answer() {
Answer key = answers[current_index];
char *msg = (char*)malloc(256 * sizeof(char)), *sresult;
ProblemRef key = answers[current_index];
Answer answer = get_answer(key.id);
char msg[256], *sresult;
int64_t iresult;
uint64_t uresult;
switch (key.type) {
switch (answer.type) {
case ERROR:
TEST_FAIL_MESSAGE("Unknown answer type. This should be unreachable.");
case INT8:
iresult = ((int8_t (*)()) key.func)();
snprintf(msg, 256, "Euler problem %" PRIu16 " should have an answer of %" PRId8 ", but we actually got %" PRId8, key.id, answer.value.INT8, (int8_t)iresult);
TEST_ASSERT_EQUAL_INT8_MESSAGE(answer.value.INT8, iresult, msg);
break;
case INT16:
iresult = ((int16_t (*)()) key.func)();
snprintf(msg, 256, "Euler problem %" PRIu16 " should have an answer of %" PRId16 ", but we actually got %" PRId16, key.id, answer.value.INT16, (int16_t)iresult);
TEST_ASSERT_EQUAL_INT16_MESSAGE(answer.value.INT16, iresult, msg);
break;
case INT32:
iresult = ((int32_t (*)()) key.func)();
snprintf(msg, 256, "Euler problem %" PRIu16 " should have an answer of %" PRId32 ", but we actually got %" PRId32, key.id, answer.value.INT32, (int32_t)iresult);
TEST_ASSERT_EQUAL_INT32_MESSAGE(answer.value.INT32, iresult, msg);
break;
case INT64:
iresult = ((uint64_t (*)()) key.func)();
snprintf(msg, 256, "Euler problem %u should have an answer of %" PRId64 ", but we actually got %" PRId64, key.id, (int64_t) key.answer, iresult);
TEST_ASSERT_EQUAL_INT64_MESSAGE(key.answer, iresult, msg);
iresult = ((int64_t (*)()) key.func)();
snprintf(msg, 256, "Euler problem %" PRIu16 " should have an answer of %" PRId64 ", but we actually got %" PRId64, key.id, answer.value.UINT64, iresult);
TEST_ASSERT_EQUAL_INT64_MESSAGE(answer.value.INT64, iresult, msg);
break;
case UINT8:
uresult = ((uint8_t (*)()) key.func)();
snprintf(msg, 256, "Euler problem %" PRIu16 " should have an answer of %" PRIu8 ", but we actually got %" PRIu8, key.id, answer.value.UINT8, (uint8_t)uresult);
TEST_ASSERT_EQUAL_UINT8_MESSAGE(answer.value.UINT8, uresult, msg);
break;
case UINT16:
uresult = ((uint16_t (*)()) key.func)();
snprintf(msg, 256, "Euler problem %" PRIu16 " should have an answer of %" PRIu16 ", but we actually got %" PRIu16, key.id, answer.value.UINT16, (uint16_t)uresult);
TEST_ASSERT_EQUAL_UINT16_MESSAGE(answer.value.UINT16, uresult, msg);
break;
case UINT32:
uresult = ((uint32_t (*)()) key.func)();
snprintf(msg, 256, "Euler problem %" PRIu16 " should have an answer of %" PRIu32 ", but we actually got %" PRIu32, key.id, answer.value.UINT32, (uint32_t)uresult);
TEST_ASSERT_EQUAL_UINT32_MESSAGE(answer.value.UINT32, uresult, msg);
break;
case UINT64:
uresult = ((uint64_t (*)()) key.func)();
snprintf(msg, 256, "Euler problem %u should have an answer of %" PRIu64 ", but we actually got %" PRIu64, key.id, (uint64_t) key.answer, uresult);
TEST_ASSERT_EQUAL_UINT64_MESSAGE(key.answer, uresult, msg);
snprintf(msg, 256, "Euler problem %" PRIu16 " should have an answer of %" PRIu64 ", but we actually got %" PRIu64, key.id, answer.value.UINT64, uresult);
TEST_ASSERT_EQUAL_UINT64_MESSAGE(answer.value.UINT64, uresult, msg);
break;
case STR:
sresult = ((char *(*)()) key.func)();
snprintf(msg, 256, "Euler problem %u should have an answer of %s, but we actually got %s", key.id, (char *) key.answer, sresult);
TEST_ASSERT_EQUAL_STRING_MESSAGE(key.answer, sresult, msg);
snprintf(msg, 256, "Euler problem %u should have an answer of %s, but we actually got %s", key.id, answer.value.STR, sresult);
TEST_ASSERT_EQUAL_STRING_MESSAGE(answer.value.STR, sresult, msg);
}
free(msg);
}

int main(int argc, char const *argv[]) {
Expand Down
3 changes: 2 additions & 1 deletion cplusplus/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ USER_FLAG?=--user
PIP?=$(PY) -m pip
BLUE=\033[0;34m
NC=\033[0m # No Color
O?=2

ifneq ($(https_proxy), )
PROXY_ARG=--proxy=$(https_proxy)
Expand Down Expand Up @@ -49,7 +50,7 @@ lint:

.PHONY: native
native: ../LICENSE Unity/src/unity.c
@$(CXX) test.cpp Unity/src/unity.c -O2 -g -lm -lstdc++ -Wall -Werror -std=gnu++98 -march=native -flto
@$(CXX) test.cpp Unity/src/unity.c -O$(O) -g -lm -lstdc++ -Wall -Werror -std=gnu++11 -march=native -flto

.PHONY: clean
clean:
Expand Down
Loading

0 comments on commit 27b8a60

Please sign in to comment.