From eb8e200a319452deb49b7901a095043b02556525 Mon Sep 17 00:00:00 2001 From: welcor <357770+welcor@users.noreply.github.com> Date: Sat, 18 May 2024 21:21:17 +0200 Subject: [PATCH] Add munit for unit testing. Main method extracted to separate file to make it easier to test the _rest_ of the code. munit is added as a submodule by running `cd src; git submodule add https://github.com/nemequ/munit.git` . Unit testing has so far only been tested on ubuntu. --- .gitignore | 9 +++++ .gitmodules | 3 ++ src/comm.c | 3 +- src/comm.h | 1 + src/main.c | 90 +++++++++++++++++++++++++++++++++++++++++ src/munit | 1 + src/test/Makefile | 75 ++++++++++++++++++++++++++++++++++ src/test/test_handler.c | 40 ++++++++++++++++++ src/test/test_handler.h | 10 +++++ src/test/testrunner.c | 23 +++++++++++ src/test/testrunner.h | 26 ++++++++++++ 11 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 .gitmodules create mode 100644 src/main.c create mode 160000 src/munit create mode 100644 src/test/Makefile create mode 100644 src/test/test_handler.c create mode 100644 src/test/test_handler.h create mode 100644 src/test/testrunner.c create mode 100644 src/test/testrunner.h diff --git a/.gitignore b/.gitignore index b8aeaa9..1b47281 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,12 @@ lib/plrobjs/index /lib/etc/last # or mail lib/etc/plrmail + +# test object files, etc +src/test/depend +src/test/*.o +src/test/testfile + + +# ide etc. +.vscode diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4ce94b9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/munit"] + path = src/munit + url = https://github.com/nemequ/munit.git diff --git a/src/comm.c b/src/comm.c index 0c1ec9e..607ec2d 100644 --- a/src/comm.c +++ b/src/comm.c @@ -198,7 +198,7 @@ void gettimeofday(struct timeval *t, struct timezone *dummy) #endif /* CIRCLE_WINDOWS || CIRCLE_MACINTOSH */ -int main(int argc, char **argv) +int _main(int argc, char **argv) { int pos = 1; const char *dir; @@ -390,6 +390,7 @@ int main(int argc, char **argv) return (0); } + /* Reload players after a copyover */ void copyover_recover() { diff --git a/src/comm.h b/src/comm.h index 9837c86..ea5bb86 100644 --- a/src/comm.h +++ b/src/comm.h @@ -17,6 +17,7 @@ #define COPYOVER_FILE "copyover.dat" /* comm.c */ +int _main(int argc, char **argv); void close_socket(struct descriptor_data *d); void game_info(const char *messg, ...) __attribute__ ((format (printf, 1, 2))); size_t send_to_char(struct char_data *ch, const char *messg, ...) __attribute__ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..3948efd --- /dev/null +++ b/src/main.c @@ -0,0 +1,90 @@ +/************************************************************************** +* File: comm.c Part of tbaMUD * +* Usage: Communication, socket handling, main(), central game loop. * +* * +* All rights reserved. See license for complete information. * +* * +* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * +* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * +**************************************************************************/ + +#include "conf.h" +#include "sysdep.h" + +/* Begin conf.h dependent includes */ + +#if CIRCLE_GNU_LIBC_MEMORY_TRACK +# include +#endif + +#ifdef CIRCLE_MACINTOSH /* Includes for the Macintosh */ +# define SIGPIPE 13 +# define SIGALRM 14 + /* GUSI headers */ +# include + /* Codewarrior dependant */ +# include +# include +#endif + +#ifdef CIRCLE_WINDOWS /* Includes for Win32 */ +# ifdef __BORLANDC__ +# include +# else /* MSVC */ +# include +# include +# endif +# include +#endif /* CIRCLE_WINDOWS */ + +#ifdef CIRCLE_AMIGA /* Includes for the Amiga */ +# include +# include +#endif /* CIRCLE_AMIGA */ + +#ifdef CIRCLE_ACORN /* Includes for the Acorn (RiscOS) */ +# include +# include +# include +#endif + +#ifdef HAVE_ARPA_TELNET_H +#include +#else +#include "telnet.h" +#endif + +/* end conf.h dependent includes */ + +/* Note, most includes for all platforms are in sysdep.h. The list of + * files that is included is controlled by conf.h for that platform. */ + +#include "structs.h" +#include "utils.h" +#include "comm.h" +#include "interpreter.h" +#include "handler.h" +#include "db.h" +#include "house.h" +#include "oasis.h" +#include "genolc.h" +#include "dg_scripts.h" +#include "dg_event.h" +#include "screen.h" /* to support the gemote act type command */ +#include "constants.h" /* For mud versions */ +#include "boards.h" +#include "act.h" +#include "ban.h" +#include "msgedit.h" +#include "fight.h" +#include "spells.h" /* for affect_update */ +#include "modify.h" +#include "quest.h" +#include "ibt.h" /* for free_ibt_lists */ +#include "mud_event.h" + + +int main(int argc, char **argv) +{ + return _main(argc, argv); +} \ No newline at end of file diff --git a/src/munit b/src/munit new file mode 160000 index 0000000..fbbdf14 --- /dev/null +++ b/src/munit @@ -0,0 +1 @@ +Subproject commit fbbdf1467eb0d04a6ee465def2e529e4c87f2118 diff --git a/src/test/Makefile b/src/test/Makefile new file mode 100644 index 0000000..bc01c7e --- /dev/null +++ b/src/test/Makefile @@ -0,0 +1,75 @@ +# Using µnit is very simple; just include the header and add the C +# file to your sources. That said, here is a simple Makefile to build +# the example. + +CSTD:=99 +OPENMP:=n +ASAN:=n +UBSAN:=n +EXTENSION:= +TEST_ENV:= +CFLAGS:=-Wall -Wno-char-subscripts -Wno-unused-but-set-variable +AGGRESSIVE_WARNINGS=n +LIBS:=-lcrypt + +#ifeq ($(CC),pgcc) +# CFLAGS+=-c$(CSTD) +#else +# CFLAGS+=-std=c$(CSTD) +#endif + +ifeq ($(OPENMP),y) + ifeq ($(CC),pgcc) + CFLAGS+=-mp + else + CFLAGS+=-fopenmp + endif +endif + +ifneq ($(SANITIZER),) + CFLAGS+=-fsanitize=$(SANITIZER) +endif + +ifneq ($(CC),pgcc) + ifeq ($(EXTRA_WARNINGS),y) + CFLAGS+=-Wall -Wextra -Werror + endif + + ifeq ($(ASAN),y) + CFLAGS+=-fsanitize=address + endif + + ifeq ($(UBSAN),y) + CFLAGS+=-fsanitize=undefined + endif +endif + +MUNIT_FILES := ../munit/munit.h ../munit/munit.c +TEST_FILES := $(ls *.c) + +# exclude main.c to avoid having multiple entrypoints. +OBJ_FILES_FROM_MUD_CODE != ls ../*.c | grep -v main.c | sed 's/\.c$$/.o/g' | xargs +OBJ_FILES_FORM_MUNIT:= ../munit/munit.o +OBJ_FILES_FROM_TESTS!= ls *.c | sed 's/\$$.c/.o/g' | xargs + +OBJ_FILES := $(OBJ_FILES_FROM_MUD_CODE) $(OBJ_FILES_FORM_MUNIT) $(OBJ_FILES_FROM_TESTS) $(LIBS) + +testfile: $(OBJ_FILES) + $(CC) $(CFLAGS) -o testfile $(OBJ_FILES) + +test: testfile + $(TEST_ENV) ./testfile + +$%.o: %.c + $(CC) $< $(CFLAGS) -c -o $@ + +clean: + rm -f *.o testfile depend +all: test + +default: all + +depend: + $(CC) -MM *.c > depend + +-include depend \ No newline at end of file diff --git a/src/test/test_handler.c b/src/test/test_handler.c new file mode 100644 index 0000000..85f4815 --- /dev/null +++ b/src/test/test_handler.c @@ -0,0 +1,40 @@ +#include "test_handler.h" + +static void run_single_get_number_test(const char* input_param, const char *name_result, int number_result); + +UNIT_TEST(test_get_number) +{ + run_single_get_number_test("1.feather", "feather", 1); + run_single_get_number_test("2.feather", "feather", 2); + run_single_get_number_test("1.feat", "feat", 1); + run_single_get_number_test("feather", "feather", 1); + run_single_get_number_test("10.feather", "feather", 10); + + return MUNIT_OK; +} + +static void run_single_get_number_test(const char* input_param, const char *name_result, int number_result) +{ + char *to_free; + char *input = to_free = strdup(input_param); + + int number = get_number(&input); + munit_assert_int32(number, ==, number_result); + munit_assert_string_equal(input, name_result); + + free(to_free); +} + +/* Creating a test suite is pretty simple. First, you'll need an + * array of tests: */ +MunitTest handler_c_tests[] = { + { + (char*) "/get_number", + test_get_number, + NULL, // setup callback + NULL, // cleanup callback + MUNIT_TEST_OPTION_NONE, + NULL + }, + { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } +}; diff --git a/src/test/test_handler.h b/src/test/test_handler.h new file mode 100644 index 0000000..7ffbb11 --- /dev/null +++ b/src/test/test_handler.h @@ -0,0 +1,10 @@ +#include "testrunner.h" + +#ifndef TEST_HANDLER_H +#define TEST_HANDLER_H + +extern MunitTest handler_c_tests[]; + +UNIT_TEST(test_get_number); + +#endif \ No newline at end of file diff --git a/src/test/testrunner.c b/src/test/testrunner.c new file mode 100644 index 0000000..ce07680 --- /dev/null +++ b/src/test/testrunner.c @@ -0,0 +1,23 @@ +#include "testrunner.h" +#include "test_handler.h" + +static MunitSuite suites[] = { + { "/handler.c", handler_c_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE }, + { NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } +}; + +static const MunitSuite test_suite = { + (char*) "", + /* The first parameter is the array of test suites. */ + NULL, + /* The second an array of suites to trigger from this one */ + suites, + MUNIT_SUITE_OPTION_NONE +}; + +int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) { + /* Finally, we'll actually run our test suite! That second argument + * is the user_data parameter which will be passed either to the + * test or (if provided) the fixture setup function. */ + return munit_suite_main(&test_suite, (void*) "µnit", argc, argv); +} diff --git a/src/test/testrunner.h b/src/test/testrunner.h new file mode 100644 index 0000000..603a405 --- /dev/null +++ b/src/test/testrunner.h @@ -0,0 +1,26 @@ +#ifndef TESTRUNNER_H +#define TESTRUNNER_H + +#include "../conf.h" +#include "../sysdep.h" +#include "../structs.h" +#include "../utils.h" +#include "../comm.h" +#include "../db.h" +#include "../handler.h" +#include "../screen.h" +#include "../interpreter.h" +#include "../spells.h" +#include "../dg_scripts.h" +#include "../act.h" +#include "../class.h" +#include "../fight.h" +#include "../quest.h" +#include "../mud_event.h" +#include "../munit/munit.h" + + +#define UNIT_TEST(test_name) MunitResult (test_name)(const MunitParameter params[], void* data) + + +#endif \ No newline at end of file