From 7e0b305d178fa6029bf2faec42030ac7cbd21e14 Mon Sep 17 00:00:00 2001 From: Samuel Walker Date: Thu, 30 Jan 2025 14:30:19 -0700 Subject: [PATCH] Initial Project Setup --- .gitignore | 1 + .gitmodules | 10 + .vscode/launch.json | 16 + CMakeLists.txt | 10 + cmake/FindCheck.cmake | 66 + deps/SDL | 1 + deps/SDL_ttf | 1 + deps/check | 1 + deps/windows/check.h | 2366 +++++++++++++++++++++++++++++++++ deps/windows/check_error.h | 39 + deps/windows/check_impl.h | 140 ++ deps/windows/check_list.h | 59 + deps/windows/check_log.h | 55 + deps/windows/check_msg.h | 39 + deps/windows/check_pack.h | 84 ++ deps/windows/check_print.h | 32 + deps/windows/check_stdint.h | 41 + deps/windows/check_str.h | 44 + gbemu/CMakeLists.txt | 6 + gbemu/main.c | 5 + include/bus.h | 6 + include/cart.h | 22 + include/common.h | 17 + include/cpu.h | 6 + include/emu.h | 12 + include/ppu.h | 6 + include/timer.h | 6 + lib/CMakeLists.txt | 6 + lib/bus.c | 0 lib/cart.c | 6 + lib/cpu.c | 10 + lib/emu.c | 57 + lib/ppu.c | 9 + lib/timer.c | 10 + roms/01-special.gb | Bin 0 -> 32768 bytes roms/02-interrupts.gb | Bin 0 -> 32768 bytes roms/03-op sp,hl.gb | Bin 0 -> 32768 bytes roms/04-op r,imm.gb | Bin 0 -> 32768 bytes roms/05-op rp.gb | Bin 0 -> 32768 bytes roms/06-ld r,r.gb | Bin 0 -> 32768 bytes roms/07-jr,jp,call,ret,rst.gb | Bin 0 -> 32768 bytes roms/08-misc instrs.gb | Bin 0 -> 32768 bytes roms/09-op r,r.gb | Bin 0 -> 32768 bytes roms/10-bit ops.gb | Bin 0 -> 32768 bytes roms/11-op a,(hl).gb | Bin 0 -> 32768 bytes roms/cpu_instrs.gb | Bin 0 -> 65536 bytes roms/dmg-acid2.gb | Bin 0 -> 32768 bytes roms/mem_timing.gb | Bin 0 -> 65536 bytes tests/CMakeLists.txt | 7 + tests/test.c | 31 + 50 files changed, 3227 insertions(+) create mode 100644 .gitmodules create mode 100644 .vscode/launch.json create mode 100644 CMakeLists.txt create mode 100644 cmake/FindCheck.cmake create mode 160000 deps/SDL create mode 160000 deps/SDL_ttf create mode 160000 deps/check create mode 100644 deps/windows/check.h create mode 100644 deps/windows/check_error.h create mode 100644 deps/windows/check_impl.h create mode 100644 deps/windows/check_list.h create mode 100644 deps/windows/check_log.h create mode 100644 deps/windows/check_msg.h create mode 100644 deps/windows/check_pack.h create mode 100644 deps/windows/check_print.h create mode 100644 deps/windows/check_stdint.h create mode 100644 deps/windows/check_str.h create mode 100644 gbemu/CMakeLists.txt create mode 100644 gbemu/main.c create mode 100644 include/bus.h create mode 100644 include/cart.h create mode 100644 include/common.h create mode 100644 include/cpu.h create mode 100644 include/emu.h create mode 100644 include/ppu.h create mode 100644 include/timer.h create mode 100644 lib/CMakeLists.txt create mode 100644 lib/bus.c create mode 100644 lib/cart.c create mode 100644 lib/cpu.c create mode 100644 lib/emu.c create mode 100644 lib/ppu.c create mode 100644 lib/timer.c create mode 100644 roms/01-special.gb create mode 100644 roms/02-interrupts.gb create mode 100644 roms/03-op sp,hl.gb create mode 100644 roms/04-op r,imm.gb create mode 100644 roms/05-op rp.gb create mode 100644 roms/06-ld r,r.gb create mode 100644 roms/07-jr,jp,call,ret,rst.gb create mode 100644 roms/08-misc instrs.gb create mode 100644 roms/09-op r,r.gb create mode 100644 roms/10-bit ops.gb create mode 100644 roms/11-op a,(hl).gb create mode 100644 roms/cpu_instrs.gb create mode 100644 roms/dmg-acid2.gb create mode 100644 roms/mem_timing.gb create mode 100644 tests/CMakeLists.txt create mode 100644 tests/test.c diff --git a/.gitignore b/.gitignore index d93251f..bca203e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake _deps +build/ # ---> C++ # Prerequisites diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..22cc8ff --- /dev/null +++ b/.gitmodules @@ -0,0 +1,10 @@ +[submodule "deps/check"] + path = deps/check + url = https://github.com/libcheck/check.git +[submodule "deps/SDL"] + path = deps/SDL + url = https://github.com/libsdl-org/SDL.git + branch = SDL2 +[submodule "deps/SDL_ttf"] + path = deps/SDL_ttf + url = https://github.com/libsdl-org/SDL_ttf.git diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6a9f67b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug", + "program": "${workspaceFolder}/build/gbemu/Debug/gbemu.exe", + "args": [ "${workspaceFolder}/roms/cpu_instrs.gb" ], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f95680a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.10) +set(BUILD_SHARED_LIBS OFF) +add_subdirectory(deps/SDL) +add_subdirectory(deps/SDL_ttf) +add_subdirectory(lib/) +add_subdirectory(gbemu/) +add_subdirectory(deps/check/) +enable_testing() +add_subdirectory(tests/) +project(top) \ No newline at end of file diff --git a/cmake/FindCheck.cmake b/cmake/FindCheck.cmake new file mode 100644 index 0000000..47ee8f8 --- /dev/null +++ b/cmake/FindCheck.cmake @@ -0,0 +1,66 @@ +# - Try to find the CHECK libraries +# Once done this will define +# +# CHECK_FOUND - system has check +# CHECK_INCLUDE_DIR - the check include directory +# CHECK_LIBRARIES - check library +# +# This configuration file for finding libcheck is originally from +# the opensync project. The originally was downloaded from here: +# opensync.org/browser/branches/3rd-party-cmake-modules/modules/FindCheck.cmake +# +# Copyright (c) 2007 Daniel Gollub +# Copyright (c) 2007 Bjoern Ricks +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +# + +# Take care about check.pc settings +# + +if(WIN32) +SET (CHECK_FOUND 1) +SET (CHECK_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/deps/windows) +SET (CHECK_LIBRARIES ${PROJECT_SOURCE_DIR}/deps/windows/check.lib) +else() +INCLUDE( FindPkgConfig ) +PKG_SEARCH_MODULE( CHECK Check ) +endif() + +# Look for CHECK include dir and libraries +IF( NOT CHECK_FOUND ) + IF ( CHECK_INSTALL_DIR ) + MESSAGE ( STATUS "Using override CHECK_INSTALL_DIR to find Check" ) + SET ( CHECK_INCLUDE_DIR "${CHECK_INSTALL_DIR}/include" ) + SET ( CHECK_INCLUDE_DIRS "${CHECK_INCLUDE_DIR}" ) + FIND_LIBRARY( CHECK_LIBRARY NAMES check PATHS "${CHECK_INSTALL_DIR}/lib" ) + FIND_LIBRARY( COMPAT_LIBRARY NAMES compat PATHS "${CHECK_INSTALL_DIR}/lib" ) + SET ( CHECK_LIBRARIES "${CHECK_LIBRARY}" "${COMPAT_LIBRARY}" ) + ELSE ( CHECK_INSTALL_DIR ) + FIND_PATH( CHECK_INCLUDE_DIR check.h ) + FIND_LIBRARY( CHECK_LIBRARIES NAMES check ) + ENDIF ( CHECK_INSTALL_DIR ) + + IF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES ) + SET( CHECK_FOUND 1 ) + IF ( NOT Check_FIND_QUIETLY ) + MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" ) + ENDIF ( NOT Check_FIND_QUIETLY ) + ELSE ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES ) + IF ( Check_FIND_REQUIRED ) + MESSAGE( FATAL_ERROR "Could NOT find CHECK" ) + ELSE ( Check_FIND_REQUIRED ) + IF ( NOT Check_FIND_QUIETLY ) + MESSAGE( STATUS "Could NOT find CHECK" ) + ENDIF ( NOT Check_FIND_QUIETLY ) + ENDIF ( Check_FIND_REQUIRED ) + ENDIF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES ) +ENDIF( NOT CHECK_FOUND ) + +# Hide advanced variables from CMake GUIs +MARK_AS_ADVANCED( CHECK_INCLUDE_DIR CHECK_LIBRARIES ) + diff --git a/deps/SDL b/deps/SDL new file mode 160000 index 0000000..934d695 --- /dev/null +++ b/deps/SDL @@ -0,0 +1 @@ +Subproject commit 934d6954e21a816c1b28f8499e5b7d976cecd2b8 diff --git a/deps/SDL_ttf b/deps/SDL_ttf new file mode 160000 index 0000000..1dc1623 --- /dev/null +++ b/deps/SDL_ttf @@ -0,0 +1 @@ +Subproject commit 1dc162336f680c459aadef299b02c099a5533b34 diff --git a/deps/check b/deps/check new file mode 160000 index 0000000..455005d --- /dev/null +++ b/deps/check @@ -0,0 +1 @@ +Subproject commit 455005dc29dc6727de7ee36fee4b49a13b39f73f diff --git a/deps/windows/check.h b/deps/windows/check.h new file mode 100644 index 0000000..497f0ea --- /dev/null +++ b/deps/windows/check.h @@ -0,0 +1,2366 @@ +/*-*- mode:C; -*- */ +/* + * Check: a unit test framework for C + * Copyright (C) 2001, 2002 Arien Malec + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_H +#define CHECK_H + +#include +#include +#include +#include + +#include + +/* + Macros and functions starting with _ (underscore) are internal and + may change without notice. You have been warned!. +*/ + + +#ifdef __cplusplus +#define CK_CPPSTART extern "C" { +#define CK_CPPEND } +CK_CPPSTART +#endif + +/** + * __GNUC_PATCHLEVEL__ is new to GCC 3.0; + * it is also present in the widely-used development snapshots leading up to 3.0 + * (which identify themselves as GCC 2.96 or 2.97, depending on which snapshot you have). + * + * https://stackoverflow.com/questions/1936719/what-are-the-gcc-predefined-macros-for-the-compilers-version-number/1936745#1936745 + */ + +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define GCC_VERSION_AT_LEAST(major, minor, patch) \ +((__GNUC__ > (major)) || \ + (__GNUC__ == (major) && __GNUC_MINOR__ > (minor)) || \ + (__GNUC__ == (major) && __GNUC_MINOR__ == (minor) && __GNUC_PATCHLEVEL__ >= (patch)) ) +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) +#define GCC_VERSION_AT_LEAST(major, minor, patch) \ +((__GNUC__ > (major)) || \ + (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) +#else +#define GCC_VERSION_AT_LEAST(major, minor, patch) 0 +#endif + +#if GCC_VERSION_AT_LEAST(2,95,3) +#define CK_ATTRIBUTE_UNUSED __attribute__ ((unused)) +#define CK_ATTRIBUTE_FORMAT(a, b, c) __attribute__ ((format (a, b, c))) +#else +#define CK_ATTRIBUTE_UNUSED +#define CK_ATTRIBUTE_FORMAT(a, b, c) +#endif /* GCC 2.95 */ + +#if GCC_VERSION_AT_LEAST(2,5,0) +#define CK_ATTRIBUTE_NORETURN __attribute__ ((noreturn)) +#else +#define CK_ATTRIBUTE_NORETURN +#endif /* GCC 2.5 */ + +#if GCC_VERSION_AT_LEAST(4,7,4) && (__STDC_VERSION__ >= 199901L) +/* Operator _Pragma introduced in C99 */ +#define CK_DIAGNOSTIC_STRINGIFY(x) #x +#define CK_DIAGNOSTIC_HELPER1(y) CK_DIAGNOSTIC_STRINGIFY(GCC diagnostic ignored y) +#define CK_DIAGNOSTIC_HELPER2(z) CK_DIAGNOSTIC_HELPER1(#z) +#define CK_DIAGNOSTIC_PUSH_IGNORE(w) \ + _Pragma("GCC diagnostic push") \ + _Pragma(CK_DIAGNOSTIC_HELPER2(w)) +#define CK_DIAGNOSTIC_POP(w) _Pragma ("GCC diagnostic pop") +#else +#define CK_DIAGNOSTIC_PUSH_IGNORE(w) +#define CK_DIAGNOSTIC_POP(w) +#endif /* GCC 4.7.4 */ + +#undef GCC_VERSION_AT_LEAST + +#include + +#if defined(_MSC_VER) +/* define pid_t for Windows, as it is needed later */ +#define pid_t int +#endif /* _MSC_VER */ + +/* + * Used to create the linker script for hiding lib-local symbols. Shall + * be put directly in front of the exported symbol. + */ +#define CK_EXPORT + +/* + * Used for MSVC to create the export attribute + * CK_DLL_EXP is defined during the compilation of the library + * on the command line. + * + * This definition is only used when building or linking to + * the shared library, i.e. libcheck.so. When building the library + * the value must be "_declspec(dllexport)". + * When linking with the library, the value must be "_declspec(dllimport)" + * + * This is only used with Microsoft Visual C. In other systems + * the value is empty. In MSVC the value is empty when linking with + * a static library. + */ +#ifndef CK_DLL_EXP +#define CK_DLL_EXP +#endif + +/* check version numbers */ + +#define CHECK_MAJOR_VERSION (0) +#define CHECK_MINOR_VERSION (15) +#define CHECK_MICRO_VERSION (2) + +CK_DLL_EXP extern int CK_EXPORT check_major_version; +CK_DLL_EXP extern int CK_EXPORT check_minor_version; +CK_DLL_EXP extern int CK_EXPORT check_micro_version; + +#ifndef NULL +#define NULL ((void*)0) +#endif + +/** + * Type for a test case + * + * A TCase represents a test case. Create with tcase_create, free + * with tcase_free. For the moment, test cases can only be run + * through a suite +*/ +typedef struct TCase TCase; + +/** + * Type for a test function + */ +typedef void (*TFun) (int); + +/** + * Type for a setup/teardown function + */ +typedef void (*SFun) (void); + +/** + * Type for a test suite + */ +typedef struct Suite Suite; + +/** + * Type for a test, which wraps a test function + */ +typedef struct TTest { + const char *name; + TFun fn; + const char *file; + int line; +} TTest; + +/** + * Creates a test suite with the given name. + * + * Create a suite, which will contain test cases. Once + * created, use suite_add_tcase() to add test cases. + * When finished, create a suite runner from the + * suite using srunner_create() + * + * @param name name of the suite + * + * @return suite + * + * @since 0.6.0 + */ +CK_DLL_EXP Suite *CK_EXPORT suite_create(const char *name); + +/** + * Determines whether a given test suite contains a case named after a + * given string. + * + * @param s suite to check + * @param tcname test case to look for + * + * @return 1 iff the given test case is within the given suite; + * 0 otherwise + * + * @since 0.9.9 + */ +CK_DLL_EXP int CK_EXPORT suite_tcase(Suite * s, const char *tcname); + +/** + * Add a test case to a suite. + * + * Note that if the TCase has already been added attempting + * to add it again will be ignored. + * + * @param s suite to add test case to + * @param tc test case to add to suite + * + * @since 0.6.0 + */ +CK_DLL_EXP void CK_EXPORT suite_add_tcase(Suite * s, TCase * tc); + +/** + * Create a test case. + * + * Once created, tests can be added with the tcase_add_test() + * function, and the test case assigned to a suite with the + * suite_add_tcase() function. + * + * @param name name of the test case + * + * @return test case containing no tests + * + * @since 0.6.0 + * */ +CK_DLL_EXP TCase *CK_EXPORT tcase_create(const char *name); + +/** + * Associate a test case with certain tags. + * Replaces any existing tags with the new set. + * + * @param tc the test case + * + * @param tags string containing arbitrary tags separated by spaces. + * This will be copied. Passing NULL clears all tags. + * + * @since 0.11.0 + * */ +CK_DLL_EXP void CK_EXPORT tcase_set_tags(TCase * tc, + const char *tags); +/** + * Add a test function to a test case + * + * @param tc test case to add test to + * @param tf test function to add to test case + * + * @since 0.6.0 + * */ +#define tcase_add_test(tc,tf) tcase_add_test_raise_signal(tc,tf,0) + +/** + * Add a test function with signal handling to a test case + * + * The added test is expected to terminate by throwing the given signal + * + * @param tc test case to add test to + * @param tf test function to add to test case + * @param signal expected signal for test function to throw in order for + * the test to be considered passing + * + * @since 0.9.2 + * */ +#define tcase_add_test_raise_signal(tc,ttest,signal) \ + _tcase_add_test((tc),(ttest),(signal), 0, 0, 1) + +/** + * Add a test function with an expected exit value to a test case + * + * The added test is expected to terminate by exiting with the given value + * + * @param tc test case to add test to + * @param tf test function to add to test case + * @param expected_exit_value exit value for test function to return in + * order for the test to be considered passing + * + * @since 0.9.7 + */ +#define tcase_add_exit_test(tc, ttest, expected_exit_value) \ + _tcase_add_test((tc),(ttest),0,(expected_exit_value),0,1) + +/** + * Add a looping test function to a test case + * + * The test will be called in a for(i = s; i < e; i++) loop with each + * iteration being executed in a new context. The loop variable 'i' is + * available in the test. + * + * @param tc test case to add test to + * @param tf function to add to test case + * @param s starting index for value "i" in test + * @param e ending index for value "i" in test + * + * @since 0.9.4 + */ +#define tcase_add_loop_test(tc,ttest,s,e) \ + _tcase_add_test((tc),(ttest),0,0,(s),(e)) + +/** + * Add a looping test function with signal handling to a test case + * + * The test will be called in a for(i = s; i < e; i++) loop with each + * iteration being executed in a new context. The loop variable 'i' is + * available in the test. + * + * The added test is expected to terminate by throwing the given signal + * + * @param tc test case to add test to + * @param tf function to add to test case + * @param signal expected signal for test function to throw in order for + * the test to be considered passing + * @param s starting index for value "i" in test + * @param e ending index for value "i" in test + * + * @since 0.9.5 + */ +#define tcase_add_loop_test_raise_signal(tc,ttest,signal,s,e) \ + _tcase_add_test((tc),(ttest),(signal),0,(s),(e)) + +/** + * Add a looping test function with an expected exit value to a test case + * + * The test will be called in a for(i = s; i < e; i++) loop with each + * iteration being executed in a new context. The loop variable 'i' is + * available in the test. + * + * The added test is expected to terminate by exiting with the given value + * + * @param tc test case to add test to + * @param tf function to add to test case + * @param expected_exit_value exit value for test function to return in + * order for the test to be considered passing + * @param s starting index for value "i" in test + * @param e ending index for value "i" in test + * + * @since 0.9.7 + */ +#define tcase_add_loop_exit_test(tc,ttest,expected_exit_value,s,e) \ + _tcase_add_test((tc),(ttest),0,(expected_exit_value),(s),(e)) + +/* Add a test function to a test case + (function version -- use this when the macro won't work +*/ +CK_DLL_EXP void CK_EXPORT _tcase_add_test(TCase * tc, const TTest * ttest, + int _signal, int allowed_exit_value, + int start, int end); + +/** + * Add unchecked fixture setup/teardown functions to a test case + * + * Unchecked fixture functions are run at the start and end of the + * test case, and not before and after unit tests. Further, + * unchecked fixture functions are not run in a separate address space, + * like test functions, and so must not exit or signal (e.g., + * segfault). + * + * Also, when run in CK_NOFORK mode, unchecked fixture functions may + * lead to different unit test behavior if unit tests change data + * setup by the fixture functions. + * + * Note that if a setup function fails, the remaining setup functions + * will be omitted, as will the test case and the teardown functions. + * If a teardown function fails the remaining teardown functins will be + * omitted. + * + * @param tc test case to add unchecked fixture setup/teardown to + * @param setup function to add to be executed before the test case; + * if NULL no setup function is added + * @param teardown function to add to be executed after the test case; + * if NULL no teardown function is added + * @since 0.8.0 + */ +CK_DLL_EXP void CK_EXPORT tcase_add_unchecked_fixture(TCase * tc, SFun setup, + SFun teardown); + +/** + * Add checked fixture setup/teardown functions to a test case + * + * Checked fixture functions are run before and after each unit test inside + * of the address space of the test. Thus, if using CK_FORK + * mode the separate process running the unit test will survive signals + * or unexpected exits in the fixture function. Also, if the setup + * function is idempotent, unit test behavior will be the same in + * CK_FORK and CK_NOFORK modes. + * + * However, since fixture functions are run before and after each unit + * test, they should not be expensive code. + * + * Note that if a setup function fails, the remaining setup functions + * will be omitted, as will the test and the teardown functions. If a + * teardown function fails the remaining teardown functins will be + * omitted. + * + * @param tc test case to add checked fixture setup/teardown to + * @param setup function to add to be executed before each unit test in + * the test case; if NULL no setup function is added + * @param teardown function to add to be executed after each unit test in + * the test case; if NULL no teardown function is added + * + * @since 0.8.0 +*/ +CK_DLL_EXP void CK_EXPORT tcase_add_checked_fixture(TCase * tc, SFun setup, + SFun teardown); + +/** + * Set the timeout for all tests in a test case. + * + * A test that lasts longer than the timeout (in seconds) will be killed + * and thus fail with an error. + * + * If not set, the default timeout is one assigned at compile time. If + * the environment variable CK_DEFAULT_TIMEOUT is defined and no timeout + * is set, the value in the environment variable is used. + * + * If Check is compile without fork() support this call is ignored, + * as timeouts are not possible. + * + * @param tc test case to assign timeout to + * @param timeout to use, in seconds. If the value contains a decimal + * portion, but no high resolution timer is available, + * the value is rounded up to the nearest second. + * + * @since 0.9.2 + */ +CK_DLL_EXP void CK_EXPORT tcase_set_timeout(TCase * tc, double timeout); + +/* Internal function to mark the start of a test function */ +CK_DLL_EXP void CK_EXPORT tcase_fn_start(const char *fname, const char *file, + int line); + +/** + * Retreive the name of the current running test. This is the name + * of the test passed to START_TEST. This is only valid when called + * from a running test. The value return outside of a running test is + * undefined. + * + * @since 0.11.0 + */ +CK_DLL_EXP const char* CK_EXPORT tcase_name(void); + +/** + * Start a unit test with START_TEST(unit_name), end with END_TEST. + * + * One must use braces within a START_/END_ pair to declare new variables + * + * @since 0.6.0 + */ +#define START_TEST(__testname)\ +static void __testname ## _fn (int _i CK_ATTRIBUTE_UNUSED);\ +static const TTest __testname ## _ttest = {""# __testname, __testname ## _fn, __FILE__, __LINE__};\ +static const TTest * __testname = & __testname ## _ttest;\ +static void __testname ## _fn (int _i CK_ATTRIBUTE_UNUSED) + +/** + * End a unit test + * + * @since 0.6.0 + */ +#define END_TEST + +/* + * Fail the test case unless expr is false + * + * This call is deprecated. + */ +#define fail_unless(expr, ...) \ + (expr) ? \ + _mark_point(__FILE__, __LINE__) : \ + _ck_assert_failed(__FILE__, __LINE__, "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL) + +/* + * Fail the test case if expr is false + * + * This call is deprecated. + * + * NOTE: The space before the comma sign before ## is essential to be compatible + * with gcc 2.95.3 and earlier. + * FIXME: these macros may conflict with C89 if expr is + * FIXME: strcmp (str1, str2) due to excessive string length. + */ +#define fail_if(expr, ...)\ + (expr) ? \ + _ck_assert_failed(__FILE__, __LINE__, "Failure '"#expr"' occurred" , ## __VA_ARGS__, NULL) \ + : _mark_point(__FILE__, __LINE__) + +/* + * Fail the test + * + * This call is deprecated. + */ +#define fail(...) _ck_assert_failed(__FILE__, __LINE__, "Failed" , ## __VA_ARGS__, NULL) + +/* + * This is called whenever an assertion fails. + * Note that it only has the noreturn modifier when + * using fork. If fork is unavailable, the function + * calls longjmp() when a test assertion fails. Marking + * the function as noreturn causes gcc to make assumptions + * which are not valid, as longjmp() is like a return. + */ +#if 0 +CK_DLL_EXP void CK_EXPORT _ck_assert_failed(const char *file, int line, + const char *expr, const char *msg, + ...) CK_ATTRIBUTE_NORETURN CK_ATTRIBUTE_FORMAT(printf, 4, 5); +#else +CK_DLL_EXP void CK_EXPORT _ck_assert_failed(const char *file, int line, + const char *expr, const char *msg, + ...) CK_ATTRIBUTE_FORMAT(printf, 4, 5); +#endif + +/** + * Fail the test if expression is false + * + * @param expr expression to evaluate + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert(expr) ck_assert_msg(expr, NULL) + +/* The space before the comma sign before ## is essential to be compatible + with gcc 2.95.3 and earlier. +*/ +/** + * Fail the test if the expression is false; print message on failure + * + * @param expr expression to evaluate + * @param ... message to print (in printf format) if expression is false + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_msg(expr, ...) \ + (expr) ? \ + _mark_point(__FILE__, __LINE__) : \ + _ck_assert_failed(__FILE__, __LINE__, "Assertion '"#expr"' failed" , ## __VA_ARGS__) + +/** + * Unconditionally fail the test + * + * @note Once called, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_abort() ck_abort_msg(NULL) +/** + * Unconditionally fail the test; print a message + * + * @param ... message to print (in printf format) + * + * @note Once called, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_abort_msg(...) _ck_assert_failed(__FILE__, __LINE__, "Failed" , ## __VA_ARGS__) + +/* Signed and unsigned integer comparison macros with improved output compared to ck_assert(). */ +/* OP may be any comparison operator. */ +#define _ck_assert_int(X, OP, Y) do { \ + intmax_t _ck_x = (X); \ + intmax_t _ck_y = (Y); \ + ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s == %jd, %s == %jd", #X" "#OP" "#Y, #X, _ck_x, #Y, _ck_y); \ +} while (0) + +/** + * Check two signed integers to determine if X==Y + * + * If not X==Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y) +/** + * Check two signed integers to determine if X!=Y + * + * If not X!=Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_int_ne(X, Y) _ck_assert_int(X, !=, Y) +/** + * Check two signed integers to determine if XY + * + * If not X>Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_int_gt(X, Y) _ck_assert_int(X, >, Y) +/** + * Check two signed integers to determine if X>=Y + * + * If not X>=Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_int_ge(X, Y) _ck_assert_int(X, >=, Y) + +#define _ck_assert_uint(X, OP, Y) do { \ + uintmax_t _ck_x = (X); \ + uintmax_t _ck_y = (Y); \ + ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s == %ju, %s == %ju", #X" "#OP" "#Y, #X, _ck_x, #Y, _ck_y); \ +} while (0) +/** + * Check two unsigned integers to determine if X==Y + * + * If not X==Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_uint_eq(X, Y) _ck_assert_uint(X, ==, Y) +/** + * Check two unsigned integers to determine if X!=Y + * + * If not X!=Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_uint_ne(X, Y) _ck_assert_uint(X, !=, Y) +/** + * Check two unsigned integers to determine if XY + * + * If not X>Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_uint_gt(X, Y) _ck_assert_uint(X, >, Y) +/** + * Check two unsigned integers to determine if X>=Y + * + * If not X>=Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_uint_ge(X, Y) _ck_assert_uint(X, >=, Y) + +/* Number of digits after the decimal point to output via printf */ +#ifndef CK_FLOATING_DIG +# define CK_FLOATING_DIG 6 +#endif /* CK_FLOATING_DIG */ + +/* Floating point number comparison macros with improved output + * compared to ck_assert(). */ +/* OP may be any comparison operator, TP is type, TM is type modifier. */ +#define _ck_assert_floating(X, OP, Y, TP, TM) do { \ + TP _ck_x = (X); \ + TP _ck_y = (Y); \ + ck_assert_msg(_ck_x OP _ck_y, \ + "Assertion '%s' failed: %s == %.*" TM "g, %s == %.*" TM "g", \ + #X" "#OP" "#Y, \ + #X, (int)CK_FLOATING_DIG, _ck_x, \ + #Y, (int)CK_FLOATING_DIG, _ck_y); \ +} while (0) + +/* Check floating point number is finise. */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_finite(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(isfinite(_ck_x), \ + "Assertion '%s' failed: %s == %.*" TM "g", \ + #X" is finite", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Check floating point number is infinise. */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_infinite(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(isinf(_ck_x), \ + "Assertion '%s' failed: %s == %.*" TM "g", \ + #X" is infinite", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Check floating point number is "Not a Number". */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_nan(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(isnan(_ck_x), \ + "Assertion '%s' failed: %s == %.*" TM "g", \ + #X" is NaN", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Check floating point number is not "Not a Number". */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_nonnan(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(!isnan(_ck_x), \ + "Assertion '%s' failed: %s == %.*" TM "g", \ + #X" is not NaN", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Floating point tolerance comparison macros with improved output + * compared to ck_assert(). */ +/* OP, D can have values: >, -1; <, 1. */ +#define _ck_assert_floating_op_tol(X, OP, Y, T, D, TP, TM) do { \ + TP _ck_x = (X); \ + TP _ck_y = (Y); \ + TP _ck_t = (T); \ + ck_assert_msg((_ck_x - _ck_y) OP _ck_t * (D), \ + "Assertion '%s' failed: %s == %.*" TM "g, %s == %.*" TM "g, %s == %.*" TM "g", \ + #X" "#OP"= "#Y", error < "#T, \ + #X, (int)CK_FLOATING_DIG, _ck_x, \ + #Y, (int)CK_FLOATING_DIG, _ck_y, \ + #T, (int)CK_FLOATING_DIG, _ck_t); \ +} while (0) + +/* Floating point tolerance comparison macros with improved output + * compared to ck_assert(). */ +/* OP can have values: <; >=. */ +#define _ck_assert_floating_absdiff_op_tol(X, Y, OP, T, TP, TM) \ +do { \ + TP _ck_x = (X); \ + TP _ck_y = (Y); \ + TP _ck_t = (T); \ + ck_assert_msg(fabsl(_ck_y - _ck_x) OP _ck_t, \ + "Assertion '%s' failed: %s == %.*" TM "g, %s == %.*" TM "g, %s == %.*" TM "g", \ + "fabsl("#Y" - "#X") "#OP" "#T, \ + #X, (int)CK_FLOATING_DIG, _ck_x, \ + #Y, (int)CK_FLOATING_DIG, _ck_y, \ + #T, (int)CK_FLOATING_DIG, _ck_t); \ +} while (0) + +/** + * Check two single precision floating point numbers to determine if X == Y. + * + * Note that the usefulness of this assertion is very limited. If you + * want to compare two floating point numbers for equality, you probably + * want to use ck_assert_float_eq_tol instead. + * + * If not X == Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_eq(X, Y) _ck_assert_floating(X, ==, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X != Y. + * + * Note that the usefulness of this assertion is very limited. If you + * want to compare two floating point numbers for equality, you probably + * want to use ck_assert_float_ne_tol instead. + * + * If not X != Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ne(X, Y) _ck_assert_floating(X, !=, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X < Y + * + * If not X < Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_lt(X, Y) _ck_assert_floating(X, <, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X <= Y + * + * If not X <= Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_le(X, Y) _ck_assert_floating(X, <=, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X > Y + * + * If not X > Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_gt(X, Y) _ck_assert_floating(X, >, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X >= Y + * + * If not X >= Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ge(X, Y) _ck_assert_floating(X, >=, Y, float, "") + +/** + * Check two single precision floating point numbers to determine if X≈Y + * with specified tolerance + * + * If not X ≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_eq_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, <, T, float, "") + +/** + * Check two single precision floating point numbers to determine if not X≈Y + * with specified tolerance + * + * If X ≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ne_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, >=, T, float, "") + +/** + * Check two single precision floating point numbers to determine if X>≈Y + * with specified tolerance + * + * If not X >≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ge_tol(X, Y, T) _ck_assert_floating_op_tol(X, >, Y, T, -1, float, "") + +/** + * Check two single precision floating point numbers to determine if X<≈Y + * with specified tolerance + * + * If not X <≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_le_tol(X, Y, T) _ck_assert_floating_op_tol(X, <, Y, T, 1, float, "") + +/** + * Check that a single precision floating point number is finite; i.e. is + * not +infinity, -infinity, or "Not a Number" (NaN) + * + * If X is +INFINITY or X is -INFINITY, or X is NaN, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_finite(X) _ck_assert_floating_finite(X, float, "") + +/** + * Check that a single precision floating point number is infinite, + * either +infinity or -infinity + * + * If X is not +INFINITY and X is not -INFINITY, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_infinite(X) _ck_assert_floating_infinite(X, float, "") + +/** + * Check that a single precision floating point number + * is "Not a Number" (NaN) + * + * If X is not NaN, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_nan(X) _ck_assert_floating_nan(X, float, "") + +/** + * Check that a single precision floating point number is + * not "Not a Number" (NaN) + * + * If X is NaN, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_nonnan(X) _ck_assert_floating_nonnan(X, float, "") + +/** + * Check two double precision floating point numbers to determine if X == Y. + * + * Note that the usefulness of this assertion is very limited. If you + * want to compare two floating point numbers for equality, you probably + * want to use ck_assert_double_eq_tol instead. + * + * If not X == Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_eq(X, Y) _ck_assert_floating(X, ==, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X != Y. + * + * Note that the usefulness of this assertion is very limited. If you + * want to compare two floating point numbers for equality, you probably + * want to use ck_assert_double_ne_tol instead. + * + * If not X != Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ne(X, Y) _ck_assert_floating(X, !=, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X < Y + * + * If not X < Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_lt(X, Y) _ck_assert_floating(X, <, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X <= Y + * + * If not X <= Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_le(X, Y) _ck_assert_floating(X, <=, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X > Y + * + * If not X > Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_gt(X, Y) _ck_assert_floating(X, >, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X >= Y + * + * If not X >= Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ge(X, Y) _ck_assert_floating(X, >=, Y, double, "") + +/** + * Check two double precision floating point numbers to determine if X≈Y + * with specified tolerance + * + * If not X ≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_eq_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, <, T, double, "") + +/** + * Check two double precision floating point numbers to determine if not X≈Y + * with specified tolerance + * + * If X ≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ne_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, >=, T, double, "") + +/** + * Check two double precision floating point numbers to determine if X>≈Y + * with specified tolerance + * + * If not X >≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ge_tol(X, Y, T) _ck_assert_floating_op_tol(X, >, Y, T, -1, double, "") + +/** + * Check two double precision floating point numbers to determine if X<≈Y + * with specified tolerance + * + * If not X <≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_le_tol(X, Y, T) _ck_assert_floating_op_tol(X, <, Y, T, 1, double, "") + +/** + * Check that a double precision floating point number is finite; i.e. is + * not +infinity, -infinity, or "Not a Number" (NaN) + * + * If X is +INFINITY or X is -INFINITY, or X is NaN, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_finite(X) _ck_assert_floating_finite(X, double, "") + +/** + * Check that a double precision floating point number is infinite, + * either +infinity or -infinity + * + * If X is not +INFINITY and X is not -INFINITY, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_infinite(X) _ck_assert_floating_infinite(X, double, "") + +/** + * Check that a double precision floating point number + * is "Not a Number" (NaN) + * + * If X is not NaN, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_nan(X) _ck_assert_floating_nan(X, double, "") + +/** + * Check that a double precision floating point number is + * not "Not a Number" (NaN) + * + * If X is NaN, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_nonnan(X) _ck_assert_floating_nonnan(X, double, "") + +/** + * Check two double precision floating point numbers to determine if X == Y. + * + * Note that the usefulness of this assertion is very limited. If you + * want to compare two floating point numbers for equality, you probably + * want to use ck_assert_ldouble_eq_tol instead. + * + * If not X == Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_eq(X, Y) _ck_assert_floating(X, ==, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X != Y. + * + * Note that the usefulness of this assertion is very limited. If you + * want to compare two floating point numbers for equality, you probably + * want to use ck_assert_ldouble_ne_tol instead. + * + * If not X != Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ne(X, Y) _ck_assert_floating(X, !=, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X < Y + * + * If not X < Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_lt(X, Y) _ck_assert_floating(X, <, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X <= Y + * + * If not X <= Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_le(X, Y) _ck_assert_floating(X, <=, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X > Y + * + * If not X > Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_gt(X, Y) _ck_assert_floating(X, >, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X >= Y + * + * If not X >= Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ge(X, Y) _ck_assert_floating(X, >=, Y, long double, "L") + +/** + * Check two double precision floating point numbers to determine if X≈Y + * with specified tolerance + * + * If not X ≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_eq_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, <, T, long double, "L") + +/** + * Check two double precision floating point numbers to determine if not X≈Y + * with specified tolerance + * + * If X ≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ne_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, >=, T, long double, "L") + +/** + * Check two double precision floating point numbers to determine if X>≈Y + * with specified tolerance + * + * If not X >≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ge_tol(X, Y, T) _ck_assert_floating_op_tol(X, >, Y, T, -1, long double, "L") + +/** + * Check two double precision floating point numbers to determine if X<≈Y + * with specified tolerance + * + * If not X <≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_le_tol(X, Y, T) _ck_assert_floating_op_tol(X, <, Y, T, 1, long double, "L") + +/** + * Check that a double precision floating point number is finite; i.e. is + * not +infinity, -infinity, or "Not a Number" (NaN) + * + * If X is +INFINITY or X is -INFINITY, or X is NaN, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_finite(X) _ck_assert_floating_finite(X, long double, "L") + +/** + * Check that a double precision floating point number is infinite, + * either +infinity or -infinity + * + * If X is not +INFINITY and X is not -INFINITY, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_infinite(X) _ck_assert_floating_infinite(X, long double, "L") + +/** + * Check that a double precision floating point number + * is "Not a Number" (NaN) + * + * If X is not NaN, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_nan(X) _ck_assert_floating_nan(X, long double, "L") + +/** + * Check that a double precision floating point number is + * not "Not a Number" (NaN) + * + * If X is NaN, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_nonnan(X) _ck_assert_floating_nonnan(X, long double, "L") + +/* String comparison macros with improved output compared to ck_assert() */ +/* OP might be any operator that can be used in '0 OP strcmp(X,Y)' comparison. */ +/* String pointer could be compared againts NULL with == (NULLEQ = 1) and != (NULLNE = 1) operators. */ +/* The x and y parameter swap in strcmp() is needed to handle >, >=, <, <= operators. */ +/* If the x or y parameter is NULL its value will be printed without quotes. */ +#define _ck_assert_str(X, OP, Y, NULLEQ, NULLNE) do { \ + const char* _ck_x = (X); \ + const char* _ck_y = (Y); \ + const char* _ck_x_s; \ + const char* _ck_y_s; \ + const char* _ck_x_q; \ + const char* _ck_y_q; \ + if (_ck_x != NULL) { \ + _ck_x_q = "\""; \ + _ck_x_s = _ck_x; \ + } else { \ + _ck_x_q = ""; \ + _ck_x_s = "(null)"; \ + } \ + if (_ck_y != NULL) { \ + _ck_y_q = "\""; \ + _ck_y_s = _ck_y; \ + } else { \ + _ck_y_q = ""; \ + _ck_y_s = "(null)"; \ + } \ + ck_assert_msg( \ + (NULLEQ && (_ck_x == NULL) && (_ck_y == NULL)) || \ + (NULLNE && ((_ck_x == NULL) || (_ck_y == NULL)) && (_ck_x != _ck_y)) || \ + ((_ck_x != NULL) && (_ck_y != NULL) && (0 OP strcmp(_ck_y, _ck_x))), \ + "Assertion '%s' failed: %s == %s%s%s, %s == %s%s%s", \ + #X" "#OP" "#Y, \ + #X, _ck_x_q, _ck_x_s, _ck_x_q, \ + #Y, _ck_y_q, _ck_y_s, _ck_y_q); \ +} while (0) + +/** + * Check two strings to determine if 0==strcmp(X,Y) + * + * If X or Y is NULL the test fails. + * If not 0==strcmp(X,Y), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_str_eq(X, Y) _ck_assert_str(X, ==, Y, 0, 0) + +/** + * Check two strings to determine if 0!=strcmp(X,Y) + * + * If X or Y is NULL the test fails. + * If not 0!=strcmp(X,Y), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_str_ne(X, Y) _ck_assert_str(X, !=, Y, 0, 0) + +/** + * Check two strings to determine if 00) + * + * If X or Y is NULL the test fails. + * If not 0=0) + * + * If X or Y is NULL the test fails. + * If not 0<=strcmp(X,Y), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_str_le(X, Y) _ck_assert_str(X, <=, Y, 0, 0) + +/** + * Check two strings to determine if 00) + * + * If X or Y is NULL the test fails. + * If not 0, Y, 0, 0) + +/** + * Check two strings to determine if 0>=strcmp(X,Y) (e.g. strcmp(X,Y)<=0) + * + * If X or Y is NULL the test fails. + * If not 0>=strcmp(X,Y), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_str_ge(X, Y) _ck_assert_str(X, >=, Y, 0, 0) + +/** + * Check two strings to determine if 0==strcmp(X,Y) or if both are undefined + * + * If both X and Y are NULL the test passes. However, if only one is NULL + * the test fails. + * If not ((X==NULL)&&(Y==NULL)) || (0==strcmp(X,Y)), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_pstr_eq(X, Y) _ck_assert_str(X, ==, Y, 1, 0) + +/** + * Check two strings to determine if 0!=strcmp(X,Y) or one of them is undefined + * + * If either X or Y is NULL the test passes, however if both are NULL + * the test fails. + * If not (X!=NULL)&&(Y!=NULL)&&(0!=strcmp(X,Y)), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_pstr_ne(X, Y) _ck_assert_str(X, !=, Y, 0, 1) + +/* Memory location comparison macros with improved output compared to ck_assert() */ +/* OP might be any operator that can be used in '0 OP memcmp(X,Y,L)' comparison */ +/* The x and y parameter swap in memcmp() is needed to handle >, >=, <, <= operators */ +/* Output is limited to CK_MAX_ASSERT_MEM_PRINT_SIZE bytes */ +#ifndef CK_MAX_ASSERT_MEM_PRINT_SIZE +#define CK_MAX_ASSERT_MEM_PRINT_SIZE 64 +#endif + +/* Memory location comparison macros with improved output compared to ck_assert() */ +/* OP might be any operator that can be used in '0 OP memcmp(X,Y,L)' comparison */ +/* The x and y parameter swap in memcmp() is needed to handle >, >=, <, <= operators */ +/* Output is limited to CK_MAX_ASSERT_MEM_PRINT_SIZE bytes */ +#ifndef CK_MAX_ASSERT_MEM_PRINT_SIZE +#define CK_MAX_ASSERT_MEM_PRINT_SIZE 64 +#endif + +#define _ck_assert_mem(X, OP, Y, L) do { \ + const uint8_t* _ck_x = (const uint8_t*)(X); \ + const uint8_t* _ck_y = (const uint8_t*)(Y); \ + size_t _ck_l = (L); \ + char _ck_x_str[CK_MAX_ASSERT_MEM_PRINT_SIZE * 2 + 1]; \ + char _ck_y_str[CK_MAX_ASSERT_MEM_PRINT_SIZE * 2 + 1]; \ + static const char _ck_hexdigits[] = "0123456789abcdef"; \ + size_t _ck_i; \ + size_t _ck_maxl = (_ck_l > CK_MAX_ASSERT_MEM_PRINT_SIZE) ? CK_MAX_ASSERT_MEM_PRINT_SIZE : _ck_l; \ + for (_ck_i = 0; _ck_i < _ck_maxl; _ck_i++) { \ + _ck_x_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_x[_ck_i] >> 4) & 0xF]; \ + _ck_y_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_y[_ck_i] >> 4) & 0xF]; \ + _ck_x_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_x[_ck_i] & 0xF]; \ + _ck_y_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_y[_ck_i] & 0xF]; \ + } \ + _ck_x_str[_ck_i * 2] = 0; \ + _ck_y_str[_ck_i * 2] = 0; \ + if (_ck_maxl != _ck_l) { \ + _ck_x_str[_ck_i * 2 - 2] = '.'; \ + _ck_y_str[_ck_i * 2 - 2] = '.'; \ + _ck_x_str[_ck_i * 2 - 1] = '.'; \ + _ck_y_str[_ck_i * 2 - 1] = '.'; \ + } \ + ck_assert_msg(0 OP memcmp(_ck_y, _ck_x, _ck_l), \ + "Assertion '%s' failed: %s == \"%s\", %s == \"%s\"", #X" "#OP" "#Y, #X, _ck_x_str, #Y, _ck_y_str); \ +} while (0) +/** + * Check two memory locations to determine if 0==memcmp(X,Y,L) + * + * If not 0==memcmp(X,Y,L), the test fails. + * + * @param X memory location + * @param Y memory location to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, ==, Y, L) +/** + * Check two memory locations to determine if 0!=memcmp(X,Y,L) + * + * If not 0!=memcmp(X,Y,L), the test fails. + * + * @param X memory location + * @param Y memory location to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, !=, Y, L) +/** + * Check two memory locations to determine if 00) + * + * If not 0=0) + * + * If not 0<=memcmp(X,Y,L), the test fails. + * + * @param X memory location + * @param Y memory location to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_mem_le(X, Y, L) _ck_assert_mem(X, <=, Y, L) +/** + * Check two memory locations to determine if 00) + * + * If not 0, Y, L) +/** + * Check two memory locations to determine if 0>=memcmp(X,Y,L) (e.g. memcmp(X,Y,L)<=0) + * + * If not 0>=memcmp(X,Y,L), the test fails. + * + * @param X memory location + * @param Y memory location to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_mem_ge(X, Y, L) _ck_assert_mem(X, >=, Y, L) + +/* Pointer comparison macros with improved output compared to ck_assert(). */ +/* OP may only be == or != */ +#define _ck_assert_ptr(X, OP, Y) do { \ + const void* _ck_x = (X); \ + const void* _ck_y = (Y); \ + ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s == %#lx, %s == %#lx", #X" "#OP" "#Y, #X, (unsigned long)(uintptr_t)_ck_x, #Y, (unsigned long)(uintptr_t)_ck_y); \ +} while (0) + +/* Pointer against NULL comparison macros with improved output + * compared to ck_assert(). */ +/* OP may only be == or != */ +#define _ck_assert_ptr_null(X, OP) do { \ + const void* _ck_x = (X); \ + ck_assert_msg(_ck_x OP NULL, \ + "Assertion '%s' failed: %s == %#lx", \ + #X" "#OP" NULL", \ + #X, (unsigned long)(uintptr_t)_ck_x); \ +} while (0) + +/** + * Check if two pointers are equal. + * + * If the two passed pointers are not equal, the test + * fails. + * + * @param X pointer + * @param Y pointer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_ptr_eq(X, Y) _ck_assert_ptr(X, ==, Y) + +/** + * Check if two pointers are not. + * + * If the two passed pointers are equal, the test fails. + * + * @param X pointer + * @param Y pointer to compare against X + * + * @since 0.9.10 + */ +#define ck_assert_ptr_ne(X, Y) _ck_assert_ptr(X, !=, Y) + +/** + * Check if a pointer is equal to NULL. + * + * If X != NULL, the test fails. + * + * @param X pointer to compare against NULL + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ptr_null(X) _ck_assert_ptr_null(X, ==) + +/** + * Check if a pointer is not equal to NULL. + * + * If X == NULL, the test fails. + * + * @param X pointer to compare against NULL + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ptr_nonnull(X) _ck_assert_ptr_null(X, !=) + +/** + * Mark the last point reached in a unit test. + * + * If the test throws a signal or exits, the location noted with the + * failure is the last location of a ck_assert*() or ck_abort() call. + * Use mark_point() to record intermediate locations (useful for tracking down + * crashes or exits). + * + * @since 0.6.0 +*/ +#define mark_point() _mark_point(__FILE__,__LINE__) + +/* Non macro version of #mark_point */ +CK_DLL_EXP void CK_EXPORT _mark_point(const char *file, int line); + +/** + * Enum describing the possible results of a test + */ +enum test_result +{ + CK_TEST_RESULT_INVALID, /**< Default value; should not encounter this */ + CK_PASS, /**< Test passed */ + CK_FAILURE, /**< Test completed but failed */ + CK_ERROR /**< Test failed to complete + (unexpected signal or non-zero early exit) */ +}; + +/** + * Enum specifying the verbosity of output a SRunner should produce + */ +enum print_output +{ + CK_SILENT, /**< No output */ + CK_MINIMAL, /**< Only summary output */ + CK_NORMAL, /**< All failed tests */ + CK_VERBOSE, /**< All tests */ + CK_ENV, /**< Look at environment var CK_VERBOSITY + for what verbosity to use, which can be + either "silent", "minimal", "normal", + or "verbose". If the environment variable + is not set, then CK_NORMAL will be used.*/ +#if 0 + CK_SUBUNIT, /**< Run as a subunit child process */ +#endif + CK_LAST /**< Not a valid option */ +}; + +/** + * Holds state for a running of a test suite + */ +typedef struct SRunner SRunner; + +/** + * Opaque type for a test failure + */ +typedef struct TestResult TestResult; + +/** + * Enum representing the types of contexts for a test + */ +enum ck_result_ctx +{ + CK_CTX_INVALID, /**< Default value; should not encounter this */ + CK_CTX_SETUP, /**< Setup before a test */ + CK_CTX_TEST, /**< Body of test itself */ + CK_CTX_TEARDOWN /**< Teardown after a test */ +}; + +/** + * Retrieve type of result that the given test result represents. + * + * This is a member of test_result, and can represent a + * pass, failure, or error. + * + * @param tr test result to retrieve result from + * + * @return result of given test + * + * @since 0.6.0 + */ +CK_DLL_EXP int CK_EXPORT tr_rtype(TestResult * tr); + +/** + * Retrieve context in which the result occurred for the given test result. + * + * The types of contents include the test setup, teardown, or the + * body of the test itself. + * + * @param tr test result to retrieve context from + * + * @return context to which the given test result applies + * + * @since 0.8.0 + */ +CK_DLL_EXP enum ck_result_ctx CK_EXPORT tr_ctx(TestResult * tr); + +/** + * Retrieve failure message from test result, if applicable. + * + * @return pointer to a message, if one exists. NULL otherwise. + * + * @since 0.6.0 + */ +CK_DLL_EXP const char *CK_EXPORT tr_msg(TestResult * tr); + +/** + * Retrieve line number at which a failure occurred, if applicable. + * + * @return If the test resulted in a failure, returns the line number + * that the failure occurred on; otherwise returns -1. + * + * @since 0.6.0 + */ +CK_DLL_EXP int CK_EXPORT tr_lno(TestResult * tr); + +/** + * Retrieve file name at which a failure occurred, if applicable. + * + * @return If the test resulted in a failure, returns a string + * containing the name of the file where the failure + * occurred; otherwise returns NULL. + * + * @since 0.6.0 + */ +CK_DLL_EXP const char *CK_EXPORT tr_lfile(TestResult * tr); + +/** + * Retrieve test case name in which a failure occurred, if applicable. + * + * @return If the test resulted in a failure, returns a string + * containing the name of the test suite where the failure + * occurred; otherwise returns NULL. + * + * @since 0.6.0 + */ +CK_DLL_EXP const char *CK_EXPORT tr_tcname(TestResult * tr); + +/** + * Creates a suite runner for the given suite. + * + * Once created, additional suites can be added to the + * suite runner using srunner_add_suite(), and the suite runner can be + * run with srunner_run_all(). Once finished, the suite runner + * must be freed with srunner_free(). + * + * @param s suite to generate a suite runner for + * + * @return suite runner for the given suite + * + * @since 0.6.0 + */ +CK_DLL_EXP SRunner *CK_EXPORT srunner_create(Suite * s); + +/** + * Add an additional suite to a suite runner. + * + * The first suite in a suite runner is always added in srunner_create(). + * This call adds additional suites to a suite runner. + * + * @param sr suite runner to add the given suite + * @param s suite to add to the given suite runner + * + * @since 0.7.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_add_suite(SRunner * sr, Suite * s); + +/** + * Frees a suite runner, including all contained suite and test cases. + * + * This call is responsible for freeing all resources related to a + * suite runner and all contained suites and test cases. Suite and + * test cases need not be freed individually, as this call handles that. + * + * @param sr suite runner to free + * + * @since 0.6.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_free(SRunner * sr); + +/** + * Runs a suite runner and all contained suite, printing results to + * stdout as specified by the print_mode. + * + * In addition to running all suites, if the suite runner has been + * configured to output to a log, that is also performed. + * + * Note that if the CK_RUN_CASE, CK_RUN_SUITE, CK_INCLUDE_TAGS and/or + * CK_EXCLUDE_TAGS environment variables are defined, then only the + * named suites or test cases will run. + * + * @param sr suite runner to run all suites from + * @param print_mode the verbosity in which to report results to stdout + * + * @since 0.6.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_run_all(SRunner * sr, + enum print_output print_mode); + +/** + * Run a specific suite or test case from a suite runner, printing results + * to stdout as specified by the print_mode. + * + * In addition to running any applicable suites or test cases, if the + * suite runner has been configured to output to a log, that is also + * performed. + * + * Note that if the sname and tcname parameters are passed as null + * then the function will fallback to using the environment variables + * CK_RUN_SUITE and CK_RUN_CASE respectively in order to select the + * suite/cases. + * + * Similarly if the CK_INCLUDE_TAGS and/or CK_EXCLUDE_TAGS environment + * variables are defined then these will further filter the test cases + * (see srunner_run_tagged, below). + * + * @param sr suite runner where the given suite or test case must be + * @param sname suite name to run. A NULL means use the value of the + * environment variable CK_RUN_SUITE if set, otherwise run "any/every + * suite". + * @param tcname test case name to run. A NULL means use the value of + * the environment variable CK_RUN_CASE if set, otherwise run + * "any/every case". + * @param print_mode the verbosity in which to report results to stdout + * + * @since 0.9.9 + */ +CK_DLL_EXP void CK_EXPORT srunner_run(SRunner * sr, const char *sname, + const char *tcname, + enum print_output print_mode); + + +/** + * Run a specific suite or test case or testcases with specific tags + * from a suite runner, printing results to stdout as specified by the + * print_mode. + * + * In addition to running any applicable suites or test cases, if the + * suite runner has been configured to output to a log, that is also + * performed. + * + * Note that if sname, tcname, include_tags, exclude_tags parameters + * are passed as NULL then if the environment variables CK_RUN_SUITE, + * CK_RUN_CASE, CK_INCLUDE_TAGS, CK_EXCLUDE_TAGS are defined then these + * values will be used instead. + * + * @param sr suite runner where the given suite or test case must be + * @param sname suite name to run. A NULL means use the value of the + * environment variable CK_RUN_SUITE if set, otherwise run "any/every + * suite". + * @param tcname test case name to run. A NULL means use the value of + * the environment variable CK_RUN_CASE if set, otherwise run + * "any/every case". + * @param include_tags space separate list of tags. Only run test + * cases that share one of these tags. A NULL means use the value of + * the environment variable CK_INCLUDE_TAGS if set, otherwise run + * "any/every test case". + * @param exclude_tags space separate list of tags. Only run test + * cases that do not share one of these tags even if they are selected + * by an included tag. A NULL means use the value of the environment + * variable CK_EXCLUDE_TAGS if set, otherwise run "any/every test + * case". + * @param print_mode the verbosity in which to report results to stdout + * + * @since 0.11.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_run_tagged(SRunner * sr, const char *sname, + const char *tcname, + const char *include_tags, + const char *exclude_tags, + enum print_output print_mode); + +/** + * Retrieve the number of failed tests executed by a suite runner. + * + * This value represents both test failures and errors. + * + * @param sr suite runner to query for all failed tests + * + * @return number of test failures and errors found by the suite runner + * + * @since 0.6.1 + */ +CK_DLL_EXP int CK_EXPORT srunner_ntests_failed(SRunner * sr); + +/** + * Retrieve the total number of tests run by a suite runner. + * + * @param sr suite runner to query for all tests run + * + * @return number of all tests run by the suite runner + * + * @since 0.6.1 + */ +CK_DLL_EXP int CK_EXPORT srunner_ntests_run(SRunner * sr); + +/** + * Return an array of results for all failures found by a suite runner. + * + * Number of results is equal to srunner_nfailed_tests(). + * + * Information about individual results can be queried using: + * tr_rtype(), tr_ctx(), tr_msg(), tr_lno(), tr_lfile(), and tr_tcname(). + * + * Memory is malloc'ed and must be freed; however free the entire structure + * instead of individual test cases. + * + * @param sr suite runner to retrieve results from + * + * @return array of TestResult objects + * + * @since 0.6.0 + */ +CK_DLL_EXP TestResult **CK_EXPORT srunner_failures(SRunner * sr); + +/** + * Return an array of results for all tests run by a suite runner. + * + * Number of results is equal to srunner_ntests_run(), and excludes + * failures due to setup function failure. + * + * Information about individual results can be queried using: + * tr_rtype(), tr_ctx(), tr_msg(), tr_lno(), tr_lfile(), and tr_tcname(). + * + * Memory is malloc'ed and must be freed; however free the entire structure + * instead of individual test cases. + * + * @param sr suite runner to retrieve results from + * + * @return array of TestResult objects + * + * @since 0.6.1 +*/ +CK_DLL_EXP TestResult **CK_EXPORT srunner_results(SRunner * sr); + +/** + * Print the results contained in an SRunner to stdout. + * + * @param sr suite runner to print results for to stdout + * @param print_mode the print_output (verbosity) to use to report + * the result + * + * @since 0.7.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_print(SRunner * sr, + enum print_output print_mode); + +/** + * Set the suite runner to output the result in log format to the + * given file. + * + * Note: log file setting is an initialize only operation -- it should + * be done immediately after SRunner creation, and the log file can't be + * changed after being set. + * + * This setting does not conflict with the other log output types; + * all logging types can occur concurrently if configured. + * + * @param sr suite runner to log results of in log format + * @param fname file name to output log results to + * + * @since 0.7.1 +*/ +CK_DLL_EXP void CK_EXPORT srunner_set_log(SRunner * sr, const char *fname); + +/** + * Checks if the suite runner is assigned a file for log output. + * + * @param sr suite runner to check + * + * @return 1 iff the suite runner currently is configured to output + * in log format; 0 otherwise + * + * @since 0.7.1 + */ +CK_DLL_EXP int CK_EXPORT srunner_has_log(SRunner * sr); + +/** + * Retrieves the name of the currently assigned file + * for log output, if any exists. + * + * @return the name of the log file, or NULL if none is configured + * + * @since 0.7.1 + */ +CK_DLL_EXP const char *CK_EXPORT srunner_log_fname(SRunner * sr); + +/** + * Set the suite runner to output the result in XML format to the + * given file. + * + * Note: XML file setting is an initialize only operation -- it should + * be done immediately after SRunner creation, and the XML file can't be + * changed after being set. + * + * This setting does not conflict with the other log output types; + * all logging types can occur concurrently if configured. + * + * @param sr suite runner to log results of in XML format + * @param fname file name to output XML results to + * + * @since 0.9.1 +*/ +CK_DLL_EXP void CK_EXPORT srunner_set_xml(SRunner * sr, const char *fname); + +/** + * Checks if the suite runner is assigned a file for XML output. + * + * @param sr suite runner to check + * + * @return 1 iff the suite runner currently is configured to output + * in XML format; 0 otherwise + * + * @since 0.9.1 + */ +CK_DLL_EXP int CK_EXPORT srunner_has_xml(SRunner * sr); + +/** + * Retrieves the name of the currently assigned file + * for XML output, if any exists. + * + * @return the name of the XML file, or NULL if none is configured + * + * @since 0.9.1 + */ +CK_DLL_EXP const char *CK_EXPORT srunner_xml_fname(SRunner * sr); + +/** + * Set the suite runner to output the result in TAP format to the + * given file. + * + * Note: TAP file setting is an initialize only operation -- it should + * be done immediately after SRunner creation, and the TAP file can't be + * changed after being set. + * + * This setting does not conflict with the other log output types; + * all logging types can occur concurrently if configured. + * + * @param sr suite runner to log results of in TAP format + * @param fname file name to output TAP results to + * + * @since 0.9.12 +*/ +CK_DLL_EXP void CK_EXPORT srunner_set_tap(SRunner * sr, const char *fname); + +/** + * Checks if the suite runner is assigned a file for TAP output. + * + * @param sr suite runner to check + * + * @return 1 iff the suite runner currently is configured to output + * in TAP format; 0 otherwise + * + * @since 0.9.12 + */ +CK_DLL_EXP int CK_EXPORT srunner_has_tap(SRunner * sr); + +/** + * Retrieves the name of the currently assigned file + * for TAP output, if any exists. + * + * @return the name of the TAP file, or NULL if none is configured + * + * @since 0.9.12 + */ +CK_DLL_EXP const char *CK_EXPORT srunner_tap_fname(SRunner * sr); + +/** + * Enum describing the current fork usage. + */ +enum fork_status +{ + CK_FORK_GETENV, /**< look in the environment for CK_FORK */ + CK_FORK, /**< call fork to run tests */ + CK_NOFORK /**< don't call fork */ +}; + +/** + * Retrieve the current fork status for the given suite runner + * + * @param sr suite runner to check fork status of + * + * @since 0.8.0 + */ +CK_DLL_EXP enum fork_status CK_EXPORT srunner_fork_status(SRunner * sr); + +/** + * Set the fork status for a given suite runner. + * + * The default fork status is CK_FORK_GETENV, which will look + * for the CK_FORK environment variable, which can be set to + * "yes" or "no". If the environment variable is not present, + * CK_FORK will be used if fork() is available on the system, + * otherwise CK_NOFORK is used. + * + * If set to CK_FORK or CK_NOFORK, the environment variable + * if defined is ignored. + * + * If Check is compiled without support for fork(), attempting + * to set the status to CK_FORK is ignored. + * + * @param sr suite runner to assign the fork status to + * @param fstat fork status to assign + * + * @since 0.8.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_set_fork_status(SRunner * sr, + enum fork_status fstat); + +/** + * Invoke fork() during a test and assign the child to the same + * process group that the rest of the test case uses. + * + * One can invoke fork() directly during a test; however doing so + * may not guarantee that any children processes are destroyed once + * the test finishes. Once a test has completed, all processes in + * the process group will be killed; using this wrapper will prevent + * orphan processes. + * + * If Check is compiled without fork() support this call simply + * return -1 and does nothing. + * + * @return On success, the PID of the child process is returned in + * the parent, and 0 is returned in the child. On failure, + * a value of -1 is returned to the parent process and no + * child process is created. + * + * @since 0.9.3 + */ +CK_DLL_EXP pid_t CK_EXPORT check_fork(void); + +/** + * Wait for the pid and exit. + * + * This is to be used in conjunction with check_fork(). When called, + * will wait for the given process to terminate. If the process + * exited without error, exit(EXIT_SUCCESS) is invoked; otherwise + * exit(EXIT_FAILURE) is invoked. + * + * If Check is compiled without support for fork(), this invokes + * exit(EXIT_FAILURE). + * + * @param pid process to wait for, created by check_fork() + * + * @since 0.9.3 + */ +CK_DLL_EXP void CK_EXPORT check_waitpid_and_exit(pid_t pid) CK_ATTRIBUTE_NORETURN; + +/** + * Set the maximal assertion message size. + * + * This protects the code against unintentional extremely large assertion messages + * (values of up to 4GB were seen in the wild). + * The usual size for a message is less than 80 bytes. + * + * If the environment variable CK_MAX_MSG_SIZE is defined to a positive value, it is used. + * Otherwise, if a positive maximal message size is set via this function, it is used. + * Otherwise, the maximal message size is one assigned at compile time (4K bytes). + * + * @param max_msg_size the maximal assertion message size. + * + * @since 0.12.0 + */ +CK_DLL_EXP void CK_EXPORT check_set_max_msg_size(size_t max_msg_size); + +#ifdef __cplusplus +CK_CPPEND +#endif + +#endif /* CHECK_H */ diff --git a/deps/windows/check_error.h b/deps/windows/check_error.h new file mode 100644 index 0000000..0dc5bb9 --- /dev/null +++ b/deps/windows/check_error.h @@ -0,0 +1,39 @@ +/* + * Check: a unit test framework for C + * Copyright (C) 2001, 2002 Arien Malec + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef ERROR_H +#define ERROR_H + +#include "../lib/libcompat.h" +#include + +extern jmp_buf error_jmp_buffer; + +/* Include stdlib.h beforehand */ + +/* Print error message and die + If fmt ends in colon, include system error information */ +void eprintf(const char *fmt, const char *file, int line, + ...) CK_ATTRIBUTE_NORETURN CK_ATTRIBUTE_FORMAT(printf, 1, 4); +/* malloc or die */ +void *emalloc(size_t n); +void *erealloc(void *, size_t n); + +#endif /*ERROR_H */ diff --git a/deps/windows/check_impl.h b/deps/windows/check_impl.h new file mode 100644 index 0000000..f4e8c59 --- /dev/null +++ b/deps/windows/check_impl.h @@ -0,0 +1,140 @@ +/* + * Check: a unit test framework for C + * Copyright (C) 2001, 2002 Arien Malec + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_IMPL_H +#define CHECK_IMPL_H + +/* This header should be included by any module that needs + to know the implementation details of the check structures + Include stdio.h, time.h, & list.h before this header +*/ + +#define US_PER_SEC 1000000 +#define NANOS_PER_SECONDS 1000000000 + +/** calculate the difference in useconds out of two "struct timespec"s */ +#define DIFF_IN_USEC(begin, end) \ + ( (((end).tv_sec - (begin).tv_sec) * US_PER_SEC) + \ + ((end).tv_nsec/1000) - ((begin).tv_nsec/1000) ) + +typedef struct TF +{ + const TTest * ttest; + int loop_start; + int loop_end; + int signal; + signed char allowed_exit_value; +} TF; + +struct Suite +{ + const char *name; + List *tclst; /* List of test cases */ +}; + +typedef struct Fixture +{ + int ischecked; + SFun fun; +} Fixture; + +struct TCase +{ + const char *name; + struct timespec timeout; + List *tflst; /* list of test functions */ + List *unch_sflst; + List *unch_tflst; + List *ch_sflst; + List *ch_tflst; + List *tags; +}; + +typedef struct TestStats +{ + int n_checked; + int n_failed; + int n_errors; +} TestStats; + +struct TestResult +{ + enum test_result rtype; /* Type of result */ + enum ck_result_ctx ctx; /* When the result occurred */ + char *file; /* File where the test occured */ + int line; /* Line number where the test occurred */ + int iter; /* The iteration value for looping tests */ + int duration; /* duration of this test in microseconds */ + const char *tcname; /* Test case that generated the result */ + const char *tname; /* Test that generated the result */ + char *msg; /* Failure message */ +}; + +TestResult *tr_create(void); +void tr_reset(TestResult * tr); +void tr_free(TestResult * tr); + +enum cl_event +{ + CLINITLOG_SR, /* Initialize log file */ + CLENDLOG_SR, /* Tests are complete */ + CLSTART_SR, /* Suite runner start */ + CLSTART_S, /* Suite start */ + CLEND_SR, /* Suite runner end */ + CLEND_S, /* Suite end */ + CLSTART_T, /* A test case is about to run */ + CLEND_T /* Test case end */ +}; + +typedef void (*LFun) (SRunner *, FILE *, enum print_output, + void *, enum cl_event); + +typedef struct Log +{ + FILE *lfile; + LFun lfun; + int close; + enum print_output mode; +} Log; + +struct SRunner +{ + List *slst; /* List of Suite objects */ + TestStats *stats; /* Run statistics */ + List *resultlst; /* List of unit test results */ + const char *log_fname; /* name of log file */ + const char *xml_fname; /* name of xml output file */ + const char *tap_fname; /* name of tap output file */ + List *loglst; /* list of Log objects */ + enum fork_status fstat; /* controls if suites are forked or not + NOTE: Don't use this value directly, + instead use srunner_fork_status */ +}; + + +void set_fork_status(enum fork_status fstat); +enum fork_status cur_fork_status(void); + +clockid_t check_get_clockid(void); + +unsigned int tcase_matching_tag(TCase *tc, List *check_for); +List *tag_string_to_list(const char *tags_string); + +#endif /* CHECK_IMPL_H */ diff --git a/deps/windows/check_list.h b/deps/windows/check_list.h new file mode 100644 index 0000000..e0b5c8c --- /dev/null +++ b/deps/windows/check_list.h @@ -0,0 +1,59 @@ +/* + * Check: a unit test framework for C + * Copyright (C) 2001, 2002 Arien Malec + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_LIST_H +#define CHECK_LIST_H + +typedef struct List List; + +/* Create an empty list */ +List *check_list_create(void); + +/* Is list at end? */ +int check_list_at_end(List * lp); + +/* Position list at front */ +void check_list_front(List * lp); + +/* Add a value to the front of the list, + positioning newly added value as current value. + More expensive than list_add_end, as it uses memmove. */ +void check_list_add_front(List * lp, void *val); + +/* Add a value to the end of the list, + positioning newly added value as current value */ +void check_list_add_end(List * lp, void *val); + +/* Give the value of the current node */ +void *check_list_val(List * lp); + +/* Position the list at the next node */ +void check_list_advance(List * lp); + +/* Free a list, but don't free values */ +void check_list_free(List * lp); + +void check_list_apply(List * lp, void (*fp) (void *)); + +/* Return true if the list contains the value, false otherwise */ +int check_list_contains(List * lp, void *val); + + +#endif /* CHECK_LIST_H */ diff --git a/deps/windows/check_log.h b/deps/windows/check_log.h new file mode 100644 index 0000000..7223b98 --- /dev/null +++ b/deps/windows/check_log.h @@ -0,0 +1,55 @@ +/* + * Check: a unit test framework for C + * Copyright (C) 2001, 2002 Arien Malec + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_LOG_H +#define CHECK_LOG_H + +void log_srunner_start(SRunner * sr); +void log_srunner_end(SRunner * sr); +void log_suite_start(SRunner * sr, Suite * s); +void log_suite_end(SRunner * sr, Suite * s); +void log_test_end(SRunner * sr, TestResult * tr); +void log_test_start(SRunner * sr, TCase * tc, TF * tfun); + +void stdout_lfun(SRunner * sr, FILE * file, enum print_output, + void *obj, enum cl_event evt); + +void lfile_lfun(SRunner * sr, FILE * file, enum print_output, + void *obj, enum cl_event evt); + +void xml_lfun(SRunner * sr, FILE * file, enum print_output, + void *obj, enum cl_event evt); + +void tap_lfun(SRunner * sr, FILE * file, enum print_output, + void *obj, enum cl_event evt); + +void subunit_lfun(SRunner * sr, FILE * file, enum print_output, + void *obj, enum cl_event evt); + +void srunner_register_lfun(SRunner * sr, FILE * lfile, int close, + LFun lfun, enum print_output); + +FILE *srunner_open_lfile(SRunner * sr); +FILE *srunner_open_xmlfile(SRunner * sr); +FILE *srunner_open_tapfile(SRunner * sr); +void srunner_init_logging(SRunner * sr, enum print_output print_mode); +void srunner_end_logging(SRunner * sr); + +#endif /* CHECK_LOG_H */ diff --git a/deps/windows/check_msg.h b/deps/windows/check_msg.h new file mode 100644 index 0000000..c66a35a --- /dev/null +++ b/deps/windows/check_msg.h @@ -0,0 +1,39 @@ +/* + * Check: a unit test framework for C + * Copyright (C) 2001, 2002 Arien Malec + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_MSG_NEW_H +#define CHECK_MSG_NEW_H + + +/* Functions implementing messaging during test runs */ + +void send_failure_info(const char *msg); +void send_loc_info(const char *file, int line); +void send_ctx_info(enum ck_result_ctx ctx); +void send_duration_info(int duration); + +TestResult *receive_test_result(int waserror); + +void setup_messaging(void); +void teardown_messaging(void); + +FILE *open_tmp_file(char **name); + +#endif /*CHECK_MSG_NEW_H */ diff --git a/deps/windows/check_pack.h b/deps/windows/check_pack.h new file mode 100644 index 0000000..3d469d2 --- /dev/null +++ b/deps/windows/check_pack.h @@ -0,0 +1,84 @@ +/* + * Check: a unit test framework for C + * Copyright (C) 2001, 2002 Arien Malec + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_PACK_H +#define CHECK_PACK_H + + +enum ck_msg_type +{ + CK_MSG_CTX, + CK_MSG_FAIL, + CK_MSG_LOC, + CK_MSG_DURATION, + CK_MSG_LAST +}; + +typedef struct CtxMsg +{ + enum ck_result_ctx ctx; +} CtxMsg; + +typedef struct LocMsg +{ + int line; + char *file; +} LocMsg; + +typedef struct FailMsg +{ + char *msg; +} FailMsg; + +typedef struct DurationMsg +{ + int duration; +} DurationMsg; + +typedef union +{ + CtxMsg ctx_msg; + FailMsg fail_msg; + LocMsg loc_msg; + DurationMsg duration_msg; +} CheckMsg; + +typedef struct RcvMsg +{ + enum ck_result_ctx lastctx; + enum ck_result_ctx failctx; + char *fixture_file; + int fixture_line; + char *test_file; + int test_line; + char *msg; + int duration; +} RcvMsg; + +void rcvmsg_free(RcvMsg * rmsg); + + +int pack(enum ck_msg_type type, char **buf, CheckMsg * msg); +int upack(char *buf, CheckMsg * msg, enum ck_msg_type *type); + +void ppack(FILE * fdes, enum ck_msg_type type, CheckMsg * msg); +RcvMsg *punpack(FILE * fdes); + +#endif /*CHECK_PACK_H */ diff --git a/deps/windows/check_print.h b/deps/windows/check_print.h new file mode 100644 index 0000000..eabd8b9 --- /dev/null +++ b/deps/windows/check_print.h @@ -0,0 +1,32 @@ +/* + * Check: a unit test framework for C + * Copyright (C) 2001, 2002 Arien Malec + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_PRINT_H +#define CHECK_PRINT_H + +/* escape XML special characters (" ' < > &) in str and print to file */ +void fprint_xml_esc(FILE * file, const char *str); +void tr_fprint(FILE * file, TestResult * tr, enum print_output print_mode); +void tr_xmlprint(FILE * file, TestResult * tr, enum print_output print_mode); +void srunner_fprint(FILE * file, SRunner * sr, enum print_output print_mode); +enum print_output get_env_printmode(void); + + +#endif /* CHECK_PRINT_H */ diff --git a/deps/windows/check_stdint.h b/deps/windows/check_stdint.h new file mode 100644 index 0000000..e4458bc --- /dev/null +++ b/deps/windows/check_stdint.h @@ -0,0 +1,41 @@ +/*-*- mode:C; -*- */ +/* + * Check: a unit test framework for C + * + * Copyright (C) 2013 Branden Archer + * Copyright (C) 2019 Mikko Johannes Koivunalho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _CHECK_CHECK_STDINT_H +#define _CHECK_CHECK_STDINT_H 1 +#ifndef _GENERATED_STDINT_H +#define _GENERATED_STDINT_H "Check 0.15.2" +/* generated using CMake 3.20.2 from file cmake/check_stdint.h.in */ + +/* Imported CMake variables created during build. */ +#define HAVE_STDINT_H 1 + +#ifdef HAVE_STDINT_H +#define _STDINT_HAVE_STDINT_H 1 +#include +#undef HAVE_STDINT_H +#endif /* defined HAVE_STDINT_H */ + +/* Define only once */ +#endif /* _GENERATED_STDINT_H */ +#endif /* _CHECK_CHECK_STDINT_H */ diff --git a/deps/windows/check_str.h b/deps/windows/check_str.h new file mode 100644 index 0000000..5f52e61 --- /dev/null +++ b/deps/windows/check_str.h @@ -0,0 +1,44 @@ +/* + * Check: a unit test framework for C + * Copyright (C) 2001, 2002 Arien Malec + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_STR_H +#define CHECK_STR_H + +#include "../lib/libcompat.h" + +/* Return a string representation of the given TestResult. Return + value has been malloc'd, and must be freed by the caller */ +char *tr_str(TestResult * tr); + +/* Return a string representation of the given TestResult message + without the test id or result type. This is suitable for separate + formatting of the test and the message. Return value has been + malloc'd, and must be freed by the caller */ +char *tr_short_str(TestResult * tr); + +/* Return a string representation of the given SRunner's run + statistics (% passed, num run, passed, errors, failures). Return + value has been malloc'd, and must be freed by the caller +*/ +char *sr_stat_str(SRunner * sr); + +char *ck_strdup_printf(const char *fmt, ...) CK_ATTRIBUTE_FORMAT(printf, 1, 2); + +#endif /* CHECK_STR_H */ diff --git a/gbemu/CMakeLists.txt b/gbemu/CMakeLists.txt new file mode 100644 index 0000000..cf34752 --- /dev/null +++ b/gbemu/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.10) +project(gbemu) +FILE(GLOB SRCS *.c) +add_executable(gbemu ${SRCS}) +target_include_directories(gbemu PUBLIC ../include) +target_link_libraries(gbemu PUBLIC Lib) \ No newline at end of file diff --git a/gbemu/main.c b/gbemu/main.c new file mode 100644 index 0000000..4f31466 --- /dev/null +++ b/gbemu/main.c @@ -0,0 +1,5 @@ +#include + +int main(int argc, char **argv) { + return emu_run(argc, argv); +} \ No newline at end of file diff --git a/include/bus.h b/include/bus.h new file mode 100644 index 0000000..4a5bfc6 --- /dev/null +++ b/include/bus.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +u8 bus_read(u16 address); +void bus_write(u16 address, u8 value); \ No newline at end of file diff --git a/include/cart.h b/include/cart.h new file mode 100644 index 0000000..b8bd113 --- /dev/null +++ b/include/cart.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +typedef struct { + u8 entry[4]; + u8 logo[0x30]; + + char title[16]; + u16 new_lic_code; + u8 sgb_flag; + u8 type; + u8 rom_size; + u8 ram_size; + u8 dest_code; + u8 lic_code; + u8 version; + u8 checksum; + u16 global_checksum; +} rom_header; + +bool cart_load(char *cart); \ No newline at end of file diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..2ed67ba --- /dev/null +++ b/include/common.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +#define BIT(a, n) ((a & (1 << n)) ? 1 : 0) +#define BIT_SET(a, n, on) (on ? (a) |= (1 << n) : (a) &= !(1 << n)) +#define BETWEEN(a, b, c) ((a >= b) && (a <= c)) + +void delay(u32 ms); \ No newline at end of file diff --git a/include/cpu.h b/include/cpu.h new file mode 100644 index 0000000..1aa4e62 --- /dev/null +++ b/include/cpu.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +void cpu_init(); +bool cpu_step(); \ No newline at end of file diff --git a/include/emu.h b/include/emu.h new file mode 100644 index 0000000..2b6da59 --- /dev/null +++ b/include/emu.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +typedef struct { + bool paused; + bool running; + u64 ticks; +} emu_context; + +int emu_run(int, char**); +emu_context *emu_get_context(); \ No newline at end of file diff --git a/include/ppu.h b/include/ppu.h new file mode 100644 index 0000000..f7c136c --- /dev/null +++ b/include/ppu.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +void ppu_init(); +void ppu_tick(); \ No newline at end of file diff --git a/include/timer.h b/include/timer.h new file mode 100644 index 0000000..eff6444 --- /dev/null +++ b/include/timer.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +void timer_init(); +void timer_tick(); \ No newline at end of file diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..a831290 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.10) +project(Lib) +file(GLOB SRCS *.c) +add_library(Lib STATIC ${SRCS}) +target_include_directories(Lib PUBLIC ../include ../deps/SDL/include ../deps/SDL_ttf) +target_link_libraries(Lib SDL2-static SDL2_ttf::SDL2_ttf-static) \ No newline at end of file diff --git a/lib/bus.c b/lib/bus.c new file mode 100644 index 0000000..e69de29 diff --git a/lib/cart.c b/lib/cart.c new file mode 100644 index 0000000..102f4a8 --- /dev/null +++ b/lib/cart.c @@ -0,0 +1,6 @@ +#include + +bool cart_load(char *cart) { + printf("Cart loading not implemented yet\n"); + return false; +} \ No newline at end of file diff --git a/lib/cpu.c b/lib/cpu.c new file mode 100644 index 0000000..dbb84fb --- /dev/null +++ b/lib/cpu.c @@ -0,0 +1,10 @@ +#include + +void cpu_init() { + +} + +bool cpu_step() { + printf("Cpu not yet implemented.\n"); + return false; +} \ No newline at end of file diff --git a/lib/emu.c b/lib/emu.c new file mode 100644 index 0000000..5eeb652 --- /dev/null +++ b/lib/emu.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include + +static emu_context ctx; + +emu_context *emu_get_context() { + return &ctx; +} + +void delay(u32 ms) { + SDL_Delay(ms); +} + +int emu_run(int argc, char **argv) { + if (argc < 2) { + printf("Usage: gbemu \n"); + return -1; + } + + if(!cart_load(argv[1])) { + printf("Failed to load ROM file: %s\n", argv[1]); + return -2; + } + + printf("Cart loaded..\n"); + + SDL_Init(SDL_INIT_VIDEO); + printf("SDL INIT\n"); + TTF_Init(); + printf("TTF INIT\n"); + + cpu_init(); + + ctx.running = true; + ctx.paused = false; + ctx.ticks = 0; + + while (ctx.running) { + if (ctx.paused) { + delay(10); + continue; + } + + if (!cpu_step()) { + printf("CPU stopped\n"); + return -3; + } + + ctx.ticks++; + } + + return 0; +} \ No newline at end of file diff --git a/lib/ppu.c b/lib/ppu.c new file mode 100644 index 0000000..d3ab571 --- /dev/null +++ b/lib/ppu.c @@ -0,0 +1,9 @@ +#include + +void ppu_init() { + +} + +void ppu_tick() { + +} \ No newline at end of file diff --git a/lib/timer.c b/lib/timer.c new file mode 100644 index 0000000..e81a980 --- /dev/null +++ b/lib/timer.c @@ -0,0 +1,10 @@ + +#include + +void timer_init() { + +} + +void timer_tick() { + +} \ No newline at end of file diff --git a/roms/01-special.gb b/roms/01-special.gb new file mode 100644 index 0000000000000000000000000000000000000000..ad3e9984f967b77b7ffdf768842ce3c04517d059 GIT binary patch literal 32768 zcmeI)+iw(A7y$5Zx80$Z?a~4dM`&TnrIv<M@$w=uCK3`2FB)GYyojYQGo9TnBOD?LkTIcgH`+#5Y&z&DBJTQ~SxVyN5AgC$ z=FIFj=klHNn@isc@IT+|W#Mz*8^+l>SX?y#V-STpsA*XJ+UpRze71LXdiska6BGOP z^v157oxXhJ{fY6rv_FZBU>pjr8QZ`6Q{6v4+|~eQtiEk&qx|dgI{D|M4Q4ZR*bx55 z&zvSm0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{ z0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2J|1AMqp1c%MZmd?| zT}pr&#L%`X4^^m7ti5y zCSPXpCX27N_$kxz`37sD5B~JBzQxO?<@iZ9;}5Zde}GN<2iX^Xie2=F*?B*k#AZVl zoAR>{Ji@N}+0O0k3g2b=XYS>9S>EiDQf)k(Ta;7mkn3kz)X(CD#j(BP7oM_Wwfre7 zr{H98CDNwq!^(}(t|W#-PGQDhySA-Z?G6_sxIhWlGQ*#*f!Q%Qf?3pUPEsm&skr9=F1Tw-yRWvJlB@(WNuEg@IFD_~FOp-tK+7 zU+NjGD10`ls%j}bId0i!C)tmcR#n)lzi*&tp%n`)Gz#i#s~_!@cRaZ9p+}+6Ty1Oc z?H{UZB0IWv$Xm8TAp}dao_~I5c76gAR7Yhm=pT_fw`_qz1HeV^4j-Kg!+2OOdk1s% zPs`th^miIwev$uT*>76e(5hdnk|$cF`OeZ?vTr%OK64%1+4{_J8z0DHb~7A`0sjWi zZ^X)Y)|MAnB6YFR)vgtrT)s2Io@|D9rRx0~)I1g%H=eOAhGQp*We23>8 z$9HdJb_6FQ-oDnR8NYd@+g4g6-{zI%)>^(b<9na9-`%^vP#K7iWpKiH#8I*{*PGm2 z4X#0xn^(Bf@;f8)4Q(Z^u7K|yX2oXM;?isR2R!GZXx!J*vSCBRO1EjnnuD0*TH*Yy z4-69v)`;Tp19W)FTnCQ>a7>kNDq@ye<;q_>vnn+`= zw4Rbgtm=A7v`>p>ih}J8v5T`NMdKo`*l(T{5Lpx^=8EZY$KRr7B@eC_^FQ0GYrt@T zv|&KXFvO16bzR4ClL^Bx5=qRjr*s|X6`Xa@biEf-0@h+T15`16rh+6k?1z2&u`e!F zY-z~Nl`iFSIWPv(Y3wNGi<=tc!v;Y-n7Aj1F{Q|_ig6H8Y$6YCK|VuO8Q@r#N^>}# zp^B-CdNGBH3+7uDbXx@-V)arOl0lq=`gkID>plRKOkKGds*;A|2fVm`5YoC>j~3*` z*hpjCsHBix^ug>A`q7 zpooPB#^S-l`zQor7>hLGzru)a;szr?N<6CpK;=5l2XAul{KObjM86DisA72iicAJRtiVPC5ef0$kIf%WY58UCBiFHDI~ zGb`PCbAn;$KmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2J tBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JB=Bz&_#K5wPf-8> literal 0 HcmV?d00001 diff --git a/roms/02-interrupts.gb b/roms/02-interrupts.gb new file mode 100644 index 0000000000000000000000000000000000000000..20895940ad31ca0229cb4ff8bb7c7ef79ca8db10 GIT binary patch literal 32768 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 literal 0 HcmV?d00001 diff --git a/roms/04-op r,imm.gb b/roms/04-op r,imm.gb new file mode 100644 index 0000000000000000000000000000000000000000..58ca7b8ac3c2b16efc9c8e401e790671c00022a2 GIT binary patch literal 32768 zcmeI4ZEO?g9l-x~k|Pbqu|w1yAuneVtPr4hD}zWgk1{}@y`p91iI-s1C}m)=&Ci}PS^)m|6_7tDiNZ`%vs1o!oe z{kL!2xc1Vyb332yci*{q~E)78){-D{jD zeGra=>Vuv*I6wB8Q-VZ*2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F z0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F z0z`la5P|t3>m;#d?jCJ;y z(NpT*EU`-esoHf)x?9lnDOH~z(_3PCdrUv8YL>nv_Rt1z3kfTxm(`eNg~hCOK+ISN z#T(Wk@tPG8-?WCrD^?1k^xKxD-l*yzZjSq=?kNHK+9yU_V%t^wK0^d!2$)W zC96Ld6P;zq=)J0jxn}io^-Is}-MeEuWEjMs8!uKH!OogBoj1jLKDU0Lf5*d_8e^a+ z7(1hG%Jj_o)`E(%V#KuN$4O6#bXy?OM>2rSBUr#FwTmp7AScq2w?mH!p0%GrK}Nw%0)h zkvx>7cI2|&euXTWYc*Ih*JfzAs*0^xdYiG+J6sl^>G-cVwl^OteOR31&o=GqtPeOXaO2HrJ}~XrpNYEHs`Z3v(ffb)Do!P z+_fG^n0+B z5|)BxFz2h%{Rg@U+jqG#k@o{&g|{*V?UW?oZv3NIRXH*&=H{Lau8qe>PJ04Q^gX@R zU)#nvetKcR^RN4UTbS?sYkNEPbnNcfzf5`~-m4DehkrHTzm^|4-eC^sNAWt6AH(Zt z6i*cWujBfb^ZKjfm2Cr%@!d;w<)$aQa(A&8C$o51+?!-uax;^-Snf~aYSfn|^^@bB z3o0fK$P}k1^_yxbEeXZD{4O(8S}L85l#9$_8(ElkdIBLL52QCyMV)>fbq^iM0=vqSBu;_VBs}j(Shq;o*Gw z@Zp+M-x&S=YewCKwf@_yyY6kMDgJiFvDoHKU4Obf)p$0ycGVk4JAV=A{mHY*l}~-S z_D9V>aDQ%k@6{uz>&dF$uk$4wt@oEBRy6qNu722&r(+5wdJ4g-;aBZTj|*pCX83~lE@ZY zjASj=z$9OjAvAufMw(#@vAPWI=!!CGOuS&OEogXTwip9`|B@x%g+@!$qC*&CI&br zlwdii;FKsv(P5Li#x2(j$dNKZ2`(*|q zI*2L?L==Vp@VP9@=r~cUaTKDX_?o>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0{;a9e+RrWAo2hJ literal 0 HcmV?d00001 diff --git a/roms/05-op rp.gb b/roms/05-op rp.gb new file mode 100644 index 0000000000000000000000000000000000000000..1c19d922f728bd11dcd8b289813fd0409f438157 GIT binary patch literal 32768 zcmeI4Uu;v?8Nfd~$t48iI3#12{2@0ucp<>J9fC!gIm##kRUOS<)=E`rZ#B5I!%6~Z zV2I;7$;7&8539O|@lu8+wVJfSkhbwpo33MQb7w9pT|pPENv{WHnnfeK)m?)L_P%o+ z*w$`&m^7){z9XM|&UeoD=X}3=&bfIC!2fwkG`p{UpsH7v!jhVUFaaJ|3iVB$uYM1_ z?_C+ZGc|Sd_{EERzd7i=du8gq<0mej-^e~eEQYen8B;yq_{7|2Ufj_Hn%CF6tX;a_ zvQ+vwoB*v0`V-*(%&(jlNCb!g5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la z5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la z5CI}U1c(3;_}?OskS1@`$#b1DTy?#D8T7N4ZT7xVqZPMEe|3b4u}ov{R!54u9Wi{` zD3|n4bI?U#6)R?qS>x7(ZYQtjx+W^y*FUxX>Gh`q^_jlRicD*#?0X?R^TCcIGv@}5 z&P+TrG9#^)ZU-u>4y@b1Za8}_UerhPZZndvF~wS@i*A<4yG-3KH(YvFGh8Mvfl2di zgVSb>wDuQUtTEowde2Jtin=kQ8O?E{BX0QP#sy8cjWzLyHrOpD?YL3V;<_CcbM_H2 zYabP->=E&%9TBhFqvAC?8Ai1uaWQQtw>~L;XeYPr6z>|(YIf$!#>RN@PGh;D&z)M7 zk`pe|PKq8oi33Z#yU)M7EADMDcEwXNE(S9ZHq^c*&y5X)Q9Pn&bGF~#o3AxT^L3b@ zfVt$1eR0uUfvmAp({ZgiV^aJ2iw6(x*$r6+iG7o$S~J*Fx25Nn*vRL$4Gr#jI8$d1 zl>~Ed^lZ;!v_uH_MD?=kDmSzXu?==%4C^@7i48pQNA(uIzC!Gxw5%|8L0VcEKQGl6 zCeBGUi2=A{nHwHAD)fk-`bM}qFcZ%`zOHMB6$uxLq_cp~U0<@m`aAY6_fMY8{+@er{j?R>Vg;<#RyQkR&|_B1r|{{?0ihnvd>FQg&7wOc(IAmY21y*@|1CA zvS&rr#0A;X?6h%9D`zC3bdUG4qvhq&g-AIi{W@_Xp0gKPL3VVZ+3-S>M;4kqy3pjv zLX+42b5nf@KpVhXfEs{i06)NDfE5610K8zVO?iF%Vev-+A9~lW)bswQ{W)y$5MEC{ z<=^h-1I1`IflwQhcn~39mp5Dpj!)d=(Tc^Wwjo)lP2y z>F+*wZtaQJQ+ zn+6Z#QR7y|?KCbJpXeo-D|MKuddz`IU9G0j@})XyjHQFkg)StwDu>hz_Ev3K3Q1KO9#S1^tFYs;Y*<7+;Af3a-m(6<~@oh#>)I z(M*LPU%nUwffuwxn_;xYRC$R)YNmW6l}dqnC>ljWzFsUrCmt#|@}baXN5+smevtb? zh`jJPSe$rjFen20x>24%e`=5~ozL?nRJmZhm5$j;=;zrBZU{Sa7<_%9)T8$RP}UTA zUJMEh{X2Luf8eAQo)2^4qO3+yZkHp7o!j6z6Oakw!uTTeVFY}SNFU2E!VB^I`y4Td z`gb`1Y^(a*AJ4xkM-;~&I^;6vfimBC_#Qa{FUmX&|F=urjK5$65aD~(0Z<*s_25f( z_K#N-Wp3w$M=ryn=)q;7p7P-v)vb$t0OM+k|Ft1+T0b-_9T;xle}34Oi;Y=so7MmQ zTb4MMHl9x#8#8!}17i8nxpAD(g9s1-B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U z1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CJ0a HUn1}~7IqB+ literal 0 HcmV?d00001 diff --git a/roms/06-ld r,r.gb b/roms/06-ld r,r.gb new file mode 100644 index 0000000000000000000000000000000000000000..d497bfd1275361bc847fa94dc87b43729f180b5d GIT binary patch literal 32768 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 literal 0 HcmV?d00001 diff --git a/roms/07-jr,jp,call,ret,rst.gb b/roms/07-jr,jp,call,ret,rst.gb new file mode 100644 index 0000000000000000000000000000000000000000..5c8d20bb3a1a0458f29afe40b8d3ca125b13a391 GIT binary patch literal 32768 zcmeI4Z){W76~K?3#H7JEf3-bALS7(vAxefRTZy#StF%K!)0(C02P#!X7!@8ZwUQ7J zIK=jxWa_$U8m%_9>pqlK>)0P{FeYsjvJZ9~+j%pOkq+1ck>t4$P%WC-pf?f&_Rf6{ ztm~$Hm^2Ah=jq*h-?{hvx##!pz0aR4DPUgG|EVo_e~9Zywe`%$vV3|OEG^m#!(fMH zP+HmW+IPWm`E>WS$;pdvkBsbkvDpE*sC2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko z0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko z0U|&IhyW2F0z`la5CJ0a*&+}TM=zAP?l!pKjOFY&C@01ZHmw$gGLMV@FonEY6=LTK zJsHLDsTCnVmlpmn;FB~I0a#uS>Vx`_KCBqg^D~XZ`KQ{x(YB@SsIxTDo>-o!ZE#g= z^Ui*}xqtTku7k6~&kf9qYs9P0{HngzJ*~aTiEu{or>vSURip{UOcAUslCo%ukt-W} zKBQVSoB|UU+A_0Es`1cAhESybBGht1oX;rgY)GvRtMy@Zbyz(WQVex%_`VH3W}-$| z&4=EBKfCbo6OZ@BIbc6m|kSCTWv z>eVf&V$Gi_!31rX%Z&O;Sg__Hsdk1Goa>A_8hU2?-n~0_K$1b^mCknMDrtPi4d?x^_=AlH#E}0bw+v+%Mg~~bv*G0uk(1#T%yy~wxOiK+wLU+c0*!&b1WP%VJQgPlV#(`k z*a5w%@lZnjVMq;x)$WAa6*5?n+7M#qx>5N`QGYXL=7OFKb^mB4awK8!8NVCKJ8ei%3$6GwMT!qd3D`D z?%Sf_MAw!Cw%DDAvv5$72syrM-4D?E4Qlgaa*<&5c{L!-~5(Q-7fidltK>J_G+ zyk5R5$`SNMor)O!a&*yfEiv*W|R}64R_;Tg`&cdVK4{x ztZ{8TK2pjT;aJymTb-p1eB&opxGMgA-*5Bsoqus}Q(x1brUR|w2a(QDPdfP99_PjM z;L#>Mm>$Ab%7I&tYFLiec z7t6gVT#f3pG4=Rp^YVg;1(MmhDfLPymk@2)dH$62=bjZ$`EoJw50S&+8Dp^-B>jtx zdKVk)Uu^K;VuJ&V4Nm;;rix&Za7{N`B$q{Mw@9P@Si~Ruvp@EMKX%C<8}r9b`(vs< zcFrHW?2m;c7?(hi;H(6i1Q#WU1N;TxZvfK(*8%e<*9WI7?@XPK%uPwRO0ARYd#BYyV_EAYuZzq&VD|XU+Go}SW(|`) zS*-%_yt(_W)Rt|JHpeHvCYRg}mY@2;6Cb|!leV_+_x-$j|1WpsUiuS%e&)@l zFDzD~mX&vkyvLhu=}o!UMI)@JSK{W`GBy;)Z_K`UBMdn}9l`c{jy$%kCba@j&s3ep z=2G>Vx^`T6p%H#;E5-$Xx2Z&&whBCVUS{9I0{^{~h?C5c>cYbpgP^~zyi(ac zZgWR%rM1<+TD1y2g-b;II;!j9>O)i*~v$IY%vy(6O>!_R5(S`a70Kd8<1 zGe+YIttGcad?b?-o6FSY<3{F>ZC~y_fSa3JsawWz!dRo1=uEa=i1(J^^Hp;Bv=ag}TS;+I!@$fZc94^&E9*SLcAg#qfCJGq)_n!F)0P?rt{&0UZQn8GN$LZ|rxw z-RRfrk!9KA#rSTY+l})wTQ@MbyBk9Sj-r_i5}&>xfsJ2ihc>-vi>dM}0I}KJg;*>G z^8P>o4f%ZWlFWFhV9NVFkC`%th_mC(Vnw^_k!%3i2w_rxB&2Y_72?OG5e8$8;11Q(Ie2AUf zU_Y}V6U2q_1!%_z_#TlyUcCs>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&Ih`?u;z&`;#5pP@o literal 0 HcmV?d00001 diff --git a/roms/08-misc instrs.gb b/roms/08-misc instrs.gb new file mode 100644 index 0000000000000000000000000000000000000000..4da139be35c0f82db12136c2b65b2571122a026b GIT binary patch literal 32768 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 literal 0 HcmV?d00001 diff --git a/roms/10-bit ops.gb b/roms/10-bit ops.gb new file mode 100644 index 0000000000000000000000000000000000000000..8988458ea0eff185d7f3bd78ff85bb7717edccfa GIT binary patch literal 32768 zcmeI4dvp_38oi~z4V`7uv(jXK=+9GPz|xr1ELesUV0gf$D8JyZD~1HQ(r%0 z>KxFJP~yPgDOtxSn`lru^G zR}QiOQb?^-m#I~1wXC_nYE7>WjUGI9@DqbS$cn~1?2Achrua$rwhIM|+jbQ#X{&y+ zv`ri!p2-Sj%o{X!P>J`5Ga#4y^qw+bghz;!WI->vd^(S;1!MM2a40$tr67sd`Gk<5>&2e_WqZUP{;J(# zw7+_n7~v{%C?2P4w=;*T?QZ{2yd<~Z9Xja)j|A#%)Z(axsAWl&)I#b2X_1+ro;=ew zeOe573CRsf>`z=qg_v)^|quv(Dl; zO$__#klm!7WHjZRip9CvSDf;8HS0b#OC6wQN&yP`qMGSB54TnP(5v zrmqj5d>3pldU9e`bQ;_Em~4vw$9+G^&UXH>`I+-F=VmS%B!1y4bQJq5w-sj{^Dp}# zQ?2w@(S4b}n(kE<^o^o?*PuMJPubkiwQT^r=~vx3zRM?ad{?M-oM@#li>oK3WZ$(D zv{*V%&}vlL_bVSZWcTed(Sf()@(Ja%BZ#7*;|d#j%Y*IWp0eP6affSzvsJrQ2Hx^p z&Dw7@x%gI-OKvq;daKDJ|GBA*`G6w;M*`jtI12CqzyiRZ13m~i2Jj)khXD%#ivS-1 zd=&68z+V794mb|*Nx<=dPXSHZf>z=?p904;!%0jB^?1)K&r9dHKVvw$-JX8}G3 zXak%LSPWPKI2Ujp;C#RZfX@RiqFn~K7;p(-DPS33Ip9*jO2B1+Re;riF97}u@YjGZ z0lo~l9Pl@QD*%5B_zK`kz*T^&0oMS&3iuk}8-Qy8YXE--_$J^wz~2LI0Ne=p7U0`} z?*MKB`~%>-fLj2!0@eb)2lzhVHo)zGe+2vx@FT#F0Y3rU0aypP3vf5!9>99QPXRvz z+zaRcbOJU2x&Ze9x&ikC9sra94+0`!6QBZk2=FlA5x_41zXWUs{0i`EKo8(Cz;6J* z1w0Pe0(cTo1@r=*0z3_P2Cxw|g&n1$rg&VBpGYWpOhG2GW(Zp$cs}C*x=*rfWds_@Urwv%HW_IMi)@#+|H9cl-F?Ro;^JG%g_jh+11`X?dEv0+X@QrcfT0JSVZA*70 zZdX}{Z-^nd4ju10PJbWo**XnnlKb?B1pn9UCWQj{G67=ll90FO&~z_{saH9;#LEer4muUR#Pv z*XsKWZ~kq!@tZ=U58fVKYuArCG|#(b++#0a?mRj+-$w$+odVlfsz_LJ8}Glb-SyS1#Vrxs}c4Ovkm@H z!Ih%sl$Fo@;T@O`RkS7MP`}(5qFze$CDVb&m*SBw`%*p1aTK0OhqZ=C z`i;7l86{q32Y_b{@pM#}DJ`W2|Gq_uEt1YxMCT<6LjH`LJ zKyQd8hxuT(&RJ-+nn7UpLIufeq5>*ng;)bUk4-V#DkxTkrOd!&v&B-z^edQ}$wc~A z_F=tbh|Obh+2?w10v5$2uv{rTeQ3-qyW&v26o1wniv$8WsIXe0%xYyHdTy~;$gkaI zwOVaZvn|-nL{CgX35M7W|qES1_Qguj%-TEmP%z;1vIt=k2W?of^}g< z1sSq@=`x4okwRErX!~hcrjRVYnfW1z>|$}~3dggW%>t0Gqro=vXEn3b**r_3iwni; z7dGn$`K)?_9_(S+4)J-m#+&Z}An34|u8U@aME=8gseWLjEvz0X9G7Hk1<5I@i-maso^$YjQYWVZ0= zJu(7Dl35t`zuA}>d%*;tjIGr$fUf715545@`Y{TEiP?q26PFS}h^4eh&vJ2n*V3gi zfYN@D{Yi4SY4DVp3&i4*`7!LT6iwAh%T&E4MgQ%{>v|8BYE&j1qK%v-1aIz~up55k z1ULasfD_;ZH~~(86W|0m0ZxDu-~>1UPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu-~>1U lPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu-~>1UPT)T!@K+QR9VGw& literal 0 HcmV?d00001 diff --git a/roms/11-op a,(hl).gb b/roms/11-op a,(hl).gb new file mode 100644 index 0000000000000000000000000000000000000000..0634b7fdd19bd62c16860ab1bad05760d6ac5965 GIT binary patch literal 32768 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 HpAz^7^EI)n literal 0 HcmV?d00001 diff --git a/roms/cpu_instrs.gb b/roms/cpu_instrs.gb new file mode 100644 index 0000000000000000000000000000000000000000..7b06221b23dcd84644e7910bb8ba91a957c9ba04 GIT binary patch literal 65536 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 MfFZyT_;UpQ3qRkrD*ylh literal 0 HcmV?d00001 diff --git a/roms/dmg-acid2.gb b/roms/dmg-acid2.gb new file mode 100644 index 0000000000000000000000000000000000000000..a25ef9485e1ab176c80415548f053ca950b3e4f5 GIT binary patch literal 32768 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 O5g-CYfCzlO2>cuVGucxB literal 0 HcmV?d00001 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..882f8df --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.10) +project(tests) +FILE(GLOB SRCS *.c) +add_executable(tests ${SRCS}) +target_include_directories(tests PUBLIC ../include ../build/deps/check/src ../build/deps/check) +target_link_libraries(tests PUBLIC Lib check) +add_test(NAME mytests COMMAND tests) \ No newline at end of file diff --git a/tests/test.c b/tests/test.c new file mode 100644 index 0000000..8311738 --- /dev/null +++ b/tests/test.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +#include + +START_TEST(test_nothing) { + bool b = cpu_step(); + ck_assert_uint_eq(b, false); +} END_TEST + +Suite *stack_suite() { + Suite *s = suite_create("emu"); + TCase *tc = tcase_create("core"); + + tcase_add_test(tc, test_nothing); + suite_add_tcase(s, tc); + + return s; +} + +int main(int argc, char **argv) { + Suite *s = stack_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + int nf = srunner_ntests_failed(sr); + srunner_free(sr); + return nf == 0 ? 0 : -1; +} \ No newline at end of file