Skip to content

Commit

Permalink
harness macro example
Browse files Browse the repository at this point in the history
  • Loading branch information
xansec committed Oct 21, 2024
1 parent 5995bee commit c6a2685
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 6 deletions.
6 changes: 6 additions & 0 deletions harness/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package(default_visibility = ["//visibility:public"])

cc_library(
name = "harness_utils",
hdrs = ["harness_utils.h"],
)
112 changes: 112 additions & 0 deletions harness/harness_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#include <stdio.h>
#include <stdlib.h>

#define MALLOC(num_elements, type) ((type*) malloc((num_elements) * sizeof(type)))
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof((arr)[0]))

#ifdef _MSC_VER
// Disable warnings for using fopen when compiling with MSVC
#define _CRT_SECURE_NO_WARNINGS
#endif

// Structure representing the contents of a file in memory
typedef struct EntireFile {
char* contents;
size_t len;
} EntireFile;

/*
Reads an entire file into memory.
Example usage:
EntireFile file = read_entire_file_into_memory("some/path/to/file");
// We can also check file.len
if (!file.contents) {
// Could not read the file. Handle error
}
// File was read successfully
*/
EntireFile read_entire_file_into_memory(const char* path) {
EntireFile res = {0};
long int file_size;
size_t bytes_read;

if (!path) {
fprintf(stderr, "No path was given to read\n");
return res;
}

FILE* file = fopen(path, "rb");
if (!file) {
fprintf(stderr, "Could not open %s for reading\n", path);
goto error;
}

if (fseek(file, 0, SEEK_END) != 0) {
fprintf(stderr, "Could not seek to the end of file %s\n", path);
goto error;
}

file_size = ftell(file);
if (file_size == -1L) {
fprintf(stderr, "Could not tell the size of file %s\n", path);
goto error;
}

if (fseek(file, 0, SEEK_SET) != 0) {
fprintf(stderr, "Could not set the cursor to the start of file %s\n", path);
goto error;
}

res.contents = MALLOC(file_size, char);
if (!res.contents) {
fprintf(stderr, "Could not allocate memory for storing contents of file %s\n", path);
goto error;
}

bytes_read = fread(res.contents, sizeof(char), file_size, file);
if (bytes_read != file_size) {
fprintf(stderr, "Could not read entire file %s\n", path);
goto error;
}
res.len = bytes_read;

fclose(file);

return res;

error:
if (file) {
fclose(file);
}

if (res.contents) {
free(res.contents);
}

return (EntireFile) {0};
}

typedef int (*HarnessFunction)(const char*, size_t);

#define HARNESS(...) \
static HarnessFunction harnesses[] = { \
__VA_ARGS__ \
}; \
int main(int argc, char* args[]) { \
::testing::InitGoogleTest(&argc, args); \
if (argc > 1) { \
EntireFile file = read_entire_file_into_memory(args[1]); \
if (!file.contents) { \
fprintf(stderr, "Failed to open input file: %s\n", args[1]); \
return 1; \
} \
if (file.len < 2) { \
return 1; \
} \
size_t harness_index = file.contents[0] % ARRAY_LEN(harnesses); \
return harnesses[harness_index](file.contents + 1, file.len - 1); \
} \
return RUN_ALL_TESTS(); \
}
16 changes: 15 additions & 1 deletion test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ cc_test(
data = [":testsuite", "//test:download_combined_test_calculator_results"],
)

cc_test(
name = "harness_test_calculator",
size = "small",
srcs = ["harness_test_calculator.cc"],
copts = ["-ftest-coverage", "-fprofile-arcs"],
linkopts = ["-lgcov", "--coverage"],
deps = [
"@googletest//:gtest_main",
"//main:calculator_lib",
"//harness:harness_utils",
],
data = [":testsuite", "//test:download_combined_test_calculator_results"],
)

mayhem_download(
name = "download_combined_test_calculator_results",
owner = "training",
Expand All @@ -47,4 +61,4 @@ mayhem_download(
}),
output_dir = "combined_test_calculator-pkg",
testonly = True,
)
)
5 changes: 0 additions & 5 deletions test/gtest_calculator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,4 @@ TEST(CalculatorTest, TestDivide) {

TEST(CalculatorTest, TestFactorGame) {
EXPECT_EQ(factor_game(6, 2), 0);
}

int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
88 changes: 88 additions & 0 deletions test/harness_test_calculator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <gtest/gtest.h>

#include "harness/harness_utils.h"

extern "C" {
#include "main/calculator.h"
}

int test_add(const char* buf, size_t len) {
int x, y;
if (len < sizeof(int) * 2) {
return 1;
}
sscanf(buf, "%d %d", &x, &y);
assert(add(x, y) == x + y);
return 0;
}

int test_subtract(const char* buf, size_t len) {
int x, y;
if (len < sizeof(int) * 2) {
return 1;
}
sscanf(buf, "%d %d", &x, &y);
assert(subtract(x, y) == x - y);
return 0;
}

int test_multiply(const char* buf, size_t len) {
int x, y;
if (len < sizeof(int) * 2) {
return 1;
}
sscanf(buf, "%d %d", &x, &y);
assert(multiply(x, y) == x * y);
return 0;
}

int test_divide(const char* buf, size_t len) {
int x, y;
if (len < sizeof(int) * 2) {
return 1;
}
sscanf(buf, "%d %d", &x, &y);
assert(divide(x, y) == x / y);
return 0;
}

int test_factor_game(const char* buf, size_t len) {
int x, y;
if (len < sizeof(int) * 2) {
return 1;
}
sscanf(buf, "%d %d", &x, &y);
factor_game(x, y); // bug is hidden in factor_game() itself, no need for extra assert() here
return 0;
}

TEST(CalculatorTest, TestAdd) {
char buf[64] = {1, 2};
test_add(buf, sizeof(buf));
}

TEST(CalculatorTest, TestSubtract) {
char buf[64] = {2, 1};
test_subtract(buf, sizeof(buf));
}

TEST(CalculatorTest, TestMultiply) {
char buf[64] = {3, 2};
test_multiply(buf, sizeof(buf));
}

TEST(CalculatorTest, TestDivide) {
char buf[64] = {6, 2};
test_divide(buf, sizeof(buf));
}

TEST(CalculatorTest, TestFactorGame) {
char buf[64] = {6, 2};
test_factor_game(buf, sizeof(buf));
}

HARNESS(test_add, test_subtract, test_multiply, test_divide, test_factor_game)

0 comments on commit c6a2685

Please sign in to comment.