From 699a391c7859f5d76db20a33af5aa3191a0409af Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Mon, 13 Feb 2023 15:55:47 +0100 Subject: [PATCH 01/31] Updates to Meson build system: 1. Use cross-platform `/` operator for path construction. 2. Use `meson.project_source_root()` for correct path resolution of generate_test_runner.rb path when used as a subproject. 3. Bump the minimum required Meson version to '0.56.0' as this is needed for the above changes. --- meson.build | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index fbb9444..94138f5 100644 --- a/meson.build +++ b/meson.build @@ -5,21 +5,22 @@ # license: MIT # project('unity', 'c', - license: 'MIT', - meson_version: '>=0.37.0', - default_options: ['werror=true', 'c_std=c11']) + license: 'MIT', + # `meson.project_source_root()` introduced in 0.56.0 + meson_version: '>=0.56.0', + default_options: [ + 'werror=true', + 'c_std=c11' + ] +) subdir('src') unity_dep = declare_dependency(link_with: unity_lib, include_directories: unity_dir) - -# Get the generate_test_runner script relative to itself or the parent project if it is being used as a subproject -# NOTE: This could be (and probably is) a complete hack - but I haven't yet been able to find a better way.... -if meson.is_subproject() -gen_test_runner_path = find_program(meson.source_root() / 'subprojects/unity/auto/generate_test_runner.rb') -else -gen_test_runner_path = find_program('subprojects/unity/auto/generate_test_runner.rb') -endif - -# Create a generator that we can access from the parent project -gen_test_runner = generator(gen_test_runner_path, output: '@BASENAME@_Runner.c', arguments: ['@INPUT@', '@OUTPUT@'] ) +# Create a generator that can be used by consumers of our build system to generate +# test runners. +gen_test_runner = generator( + find_program(meson.project_source_root() / 'auto' / 'generate_test_runner.rb'), + output: '@BASENAME@_Runner.c', + arguments: ['@INPUT@', '@OUTPUT@'] +) From cd80a79db525d3456ae7a80c3252b314119536fd Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Mon, 13 Feb 2023 16:19:39 +0100 Subject: [PATCH 02/31] Add Meson example based on Owen Torres' example. --- .gitignore | 1 + examples/example_1/meson.build | 48 +++++++++++++++++++++++ examples/example_1/readme.txt | 9 ++++- examples/example_1/subprojects/unity.wrap | 3 ++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 examples/example_1/meson.build create mode 100644 examples/example_1/subprojects/unity.wrap diff --git a/.gitignore b/.gitignore index 7500c74..211683a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ build/ builddir/ test/sandbox .DS_Store +examples/example_1/subprojects/unity examples/example_1/test1.exe examples/example_1/test2.exe examples/example_2/all_tests.exe diff --git a/examples/example_1/meson.build b/examples/example_1/meson.build new file mode 100644 index 0000000..645eeb9 --- /dev/null +++ b/examples/example_1/meson.build @@ -0,0 +1,48 @@ +project('Unity example', 'c', + license: 'MIT', + default_options: [ + 'c_std=c99', + 'warning_level=3', + ], + meson_version: '>= 0.49.0' +) + +unity_subproject = subproject('unity') +unity_dependency = unity_subproject.get_variable('unity_dep') +unity_gen_runner = unity_subproject.get_variable('gen_test_runner') + +src1 = files([ + 'src' / 'ProductionCode.c', + 'test' / 'TestProductionCode.c', +]) + +src2 = files([ + 'src' / 'ProductionCode2.c', + 'test' / 'TestProductionCode2.c', +]) + +inc = include_directories('src') + +test1 = executable('test1', + sources: [ + src1, + unity_gen_runner.process('test' / 'TestProductionCode.c') + ], + include_directories: [ inc ], + dependencies: [ unity_dependency ], +) + +test('test1', test1, + should_fail: true) + +test2 = executable('test2', + sources: [ + src2, + unity_gen_runner.process('test' / 'TestProductionCode2.c') + ], + include_directories: [ inc ], + dependencies: [ unity_dependency ], +) + +test('test2', test2) + diff --git a/examples/example_1/readme.txt b/examples/example_1/readme.txt index dfed815..ddddd36 100644 --- a/examples/example_1/readme.txt +++ b/examples/example_1/readme.txt @@ -2,4 +2,11 @@ Example 1 ========= Close to the simplest possible example of Unity, using only basic features. -Run make to build & run the example tests. \ No newline at end of file + +Build and run with Make +--- +Just run `make`. + +Build and run with Meson +--- +Run `meson setup build` to create the build directory, and then `meson test -C build` to build and run the tests. diff --git a/examples/example_1/subprojects/unity.wrap b/examples/example_1/subprojects/unity.wrap new file mode 100644 index 0000000..6df241b --- /dev/null +++ b/examples/example_1/subprojects/unity.wrap @@ -0,0 +1,3 @@ +[wrap-git] +url = https://github.com/ThrowTheSwitch/Unity.git +revision = head From 44bc9e6dbe40e92b0e9f44cc00c65938f23984b1 Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Mon, 13 Feb 2023 17:22:52 +0100 Subject: [PATCH 03/31] Update Meson build system The following features from the CMake build have been implemented: * Library version retrieved from unity.h. * Extension support. * Library, header, and package configuration file installation. This commit is entirely based on existing work by Owen Torres. --- auto/extract_version.py | 15 +++++++++ extras/fixture/src/meson.build | 8 +++++ extras/memory/src/meson.build | 7 +++++ meson.build | 56 +++++++++++++++++++++++++++++++++- meson_options.txt | 2 ++ src/meson.build | 12 +++++--- 6 files changed, 94 insertions(+), 6 deletions(-) create mode 100755 auto/extract_version.py create mode 100644 extras/fixture/src/meson.build create mode 100644 extras/memory/src/meson.build create mode 100644 meson_options.txt diff --git a/auto/extract_version.py b/auto/extract_version.py new file mode 100755 index 0000000..1d137e5 --- /dev/null +++ b/auto/extract_version.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +import re +import sys + +ver_re = re.compile(r"^#define\s+UNITY_VERSION_(?:MAJOR|MINOR|BUILD)\s+(\d+)$") +version = [] + +with open(sys.argv[1], "r") as f: + for line in f: + m = ver_re.match(line) + if m: + version.append(m.group(1)) + +print(".".join(version)) + diff --git a/extras/fixture/src/meson.build b/extras/fixture/src/meson.build new file mode 100644 index 0000000..5d11470 --- /dev/null +++ b/extras/fixture/src/meson.build @@ -0,0 +1,8 @@ +unity_inc += include_directories('.') +unity_src += files('unity_fixture.c') + +install_headers( + 'unity_fixture.h', + 'unity_fixture_internals.h', + subdir: meson.project_name() +) diff --git a/extras/memory/src/meson.build b/extras/memory/src/meson.build new file mode 100644 index 0000000..53a66ca --- /dev/null +++ b/extras/memory/src/meson.build @@ -0,0 +1,7 @@ +unity_inc += include_directories('.') +unity_src += files('unity_memory.c') + +install_headers( + 'unity_memory.h', + subdir: meson.project_name() +) diff --git a/meson.build b/meson.build index 94138f5..1a56f27 100644 --- a/meson.build +++ b/meson.build @@ -6,6 +6,17 @@ # project('unity', 'c', license: 'MIT', + + # Set project version to value extracted from unity.h header + version: run_command( + [ + find_program('python', 'python3'), + 'auto' / 'extract_version.py', + 'src' / 'unity.h' + ], + check: true + ).stdout().strip(), + # `meson.project_source_root()` introduced in 0.56.0 meson_version: '>=0.56.0', default_options: [ @@ -14,8 +25,41 @@ project('unity', 'c', ] ) +build_fixture = get_option('extension_fixture').enabled() +build_memory = get_option('extension_memory').enabled() + +unity_src = [] +unity_inc = [] + subdir('src') -unity_dep = declare_dependency(link_with: unity_lib, include_directories: unity_dir) + +if build_fixture + # Building the fixture extension implies building the memory + # extension. + build_memory = true + subdir('extras/fixture/src') +endif + +if build_memory + subdir('extras/memory/src') +endif + +unity_lib = static_library(meson.project_name(), + sources: unity_src, + include_directories: unity_inc, + install: true +) + +unity_dep = declare_dependency( + link_with: unity_lib, + include_directories: unity_inc +) + +# Generate pkg-config file. +pkg = import('pkgconfig') +pkg.generate(unity_lib, + description: 'C Unit testing framework.' +) # Create a generator that can be used by consumers of our build system to generate # test runners. @@ -24,3 +68,13 @@ gen_test_runner = generator( output: '@BASENAME@_Runner.c', arguments: ['@INPUT@', '@OUTPUT@'] ) + +# Summarize. +summary( + { + 'Fixture extension': build_fixture, + 'Memory extension': build_memory, + }, + section: 'Extensions', + bool_yn: true +) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..10b136f --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,2 @@ +option('extension_fixture', type: 'feature', value: 'disabled', description: 'Whether to use the fixture extension.') +option('extension_memory', type: 'feature', value: 'disabled', description: 'Whether to use the memory extension.') diff --git a/src/meson.build b/src/meson.build index fbe4b5b..4d7751f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,10 +4,12 @@ # # license: MIT # -unity_dir = include_directories('.') -unity_lib = static_library(meson.project_name(), - 'unity.c', - include_directories: unity_dir, - native: true +unity_inc += include_directories('.') +unity_src += files('unity.c') + +install_headers( + 'unity.h', + 'unity_internals.h', + subdir: meson.project_name() ) From 43378c4262a83572615ad241d0c2af0c47c0d844 Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Tue, 14 Feb 2023 09:18:13 +0100 Subject: [PATCH 04/31] Implement review feedback for Meson updates. 1. Call the version extraction script directly instead of through a Python returned from `find_program()`. 2. We don't need to use `meson.project_source_root()` as `find_program()` will search relative to the current meson.build script. 3. Lower the required version back to `>= 0.37.0`, and modify some things to get rid of warnings with this version selected. The use of `summary()`, `dict`, and positional arguments in `pkgconfig.generate()` generate warnings with this version so remove `summary()` and dict()`, also pass keyword arguments to `pkgconfig.generate()`. --- meson.build | 29 ++++++++++------------------- meson_options.txt | 4 ++-- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/meson.build b/meson.build index 1a56f27..312c4e3 100644 --- a/meson.build +++ b/meson.build @@ -10,23 +10,21 @@ project('unity', 'c', # Set project version to value extracted from unity.h header version: run_command( [ - find_program('python', 'python3'), - 'auto' / 'extract_version.py', - 'src' / 'unity.h' + 'auto/extract_version.py', + 'src/unity.h' ], check: true ).stdout().strip(), - # `meson.project_source_root()` introduced in 0.56.0 - meson_version: '>=0.56.0', + meson_version: '>=0.37.0', default_options: [ 'werror=true', 'c_std=c11' ] ) -build_fixture = get_option('extension_fixture').enabled() -build_memory = get_option('extension_memory').enabled() +build_fixture = get_option('extension_fixture') +build_memory = get_option('extension_memory') unity_src = [] unity_inc = [] @@ -57,24 +55,17 @@ unity_dep = declare_dependency( # Generate pkg-config file. pkg = import('pkgconfig') -pkg.generate(unity_lib, +pkg.generate( + name: meson.project_name(), + version: meson.project_version(), + libraries: [ unity_lib ], description: 'C Unit testing framework.' ) # Create a generator that can be used by consumers of our build system to generate # test runners. gen_test_runner = generator( - find_program(meson.project_source_root() / 'auto' / 'generate_test_runner.rb'), + find_program('auto/generate_test_runner.rb'), output: '@BASENAME@_Runner.c', arguments: ['@INPUT@', '@OUTPUT@'] ) - -# Summarize. -summary( - { - 'Fixture extension': build_fixture, - 'Memory extension': build_memory, - }, - section: 'Extensions', - bool_yn: true -) diff --git a/meson_options.txt b/meson_options.txt index 10b136f..fbb66d7 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1,2 @@ -option('extension_fixture', type: 'feature', value: 'disabled', description: 'Whether to use the fixture extension.') -option('extension_memory', type: 'feature', value: 'disabled', description: 'Whether to use the memory extension.') +option('extension_fixture', type: 'boolean', value: 'false', description: 'Whether to enable the fixture extension.') +option('extension_memory', type: 'boolean', value: 'false', description: 'Whether to enable the memory extension.') From fba6be17c744faa71718b4abd675b42f11b471c6 Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Tue, 14 Feb 2023 17:53:03 +0100 Subject: [PATCH 05/31] Bump meson_version to '0.47.0' The use of the check kwarg in run_command() was introduced in meson version 0.47.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 312c4e3..708b295 100644 --- a/meson.build +++ b/meson.build @@ -16,7 +16,7 @@ project('unity', 'c', check: true ).stdout().strip(), - meson_version: '>=0.37.0', + meson_version: '>=0.47.0', default_options: [ 'werror=true', 'c_std=c11' From 18482abd9ee11b7bf1e6aef0e4b81eda33a372f7 Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Tue, 21 Feb 2023 01:26:54 +0200 Subject: [PATCH 06/31] Don't install anything when building as subproject When a project is consuming unity as as subproject, unity headers, static library and pkg config files are installed by `meson install`. This can be fixed by using `meson install --skip-subprojects`, but this must be repeated in all the distros packaging a project. Fixed by disabling install when building as a subproject. Fixes: #661 --- extras/fixture/src/meson.build | 12 +++++++----- extras/memory/src/meson.build | 10 ++++++---- meson.build | 18 ++++++++++-------- src/meson.build | 12 +++++++----- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/extras/fixture/src/meson.build b/extras/fixture/src/meson.build index 5d11470..224911d 100644 --- a/extras/fixture/src/meson.build +++ b/extras/fixture/src/meson.build @@ -1,8 +1,10 @@ unity_inc += include_directories('.') unity_src += files('unity_fixture.c') -install_headers( - 'unity_fixture.h', - 'unity_fixture_internals.h', - subdir: meson.project_name() -) +if not meson.is_subproject() + install_headers( + 'unity_fixture.h', + 'unity_fixture_internals.h', + subdir: meson.project_name() + ) +endif diff --git a/extras/memory/src/meson.build b/extras/memory/src/meson.build index 53a66ca..650ba32 100644 --- a/extras/memory/src/meson.build +++ b/extras/memory/src/meson.build @@ -1,7 +1,9 @@ unity_inc += include_directories('.') unity_src += files('unity_memory.c') -install_headers( - 'unity_memory.h', - subdir: meson.project_name() -) +if not meson.is_subproject() + install_headers( + 'unity_memory.h', + subdir: meson.project_name() + ) +endif diff --git a/meson.build b/meson.build index 708b295..c5cf971 100644 --- a/meson.build +++ b/meson.build @@ -45,7 +45,7 @@ endif unity_lib = static_library(meson.project_name(), sources: unity_src, include_directories: unity_inc, - install: true + install: not meson.is_subproject(), ) unity_dep = declare_dependency( @@ -54,13 +54,15 @@ unity_dep = declare_dependency( ) # Generate pkg-config file. -pkg = import('pkgconfig') -pkg.generate( - name: meson.project_name(), - version: meson.project_version(), - libraries: [ unity_lib ], - description: 'C Unit testing framework.' -) +if not meson.is_subproject() + pkg = import('pkgconfig') + pkg.generate( + name: meson.project_name(), + version: meson.project_version(), + libraries: [ unity_lib ], + description: 'C Unit testing framework.' + ) +endif # Create a generator that can be used by consumers of our build system to generate # test runners. diff --git a/src/meson.build b/src/meson.build index 4d7751f..5365227 100644 --- a/src/meson.build +++ b/src/meson.build @@ -8,8 +8,10 @@ unity_inc += include_directories('.') unity_src += files('unity.c') -install_headers( - 'unity.h', - 'unity_internals.h', - subdir: meson.project_name() -) +if not meson.is_subproject() + install_headers( + 'unity.h', + 'unity_internals.h', + subdir: meson.project_name() + ) +endif From 40b573a7846267fe6173287ef7ea5a5aa53487b2 Mon Sep 17 00:00:00 2001 From: Dave Hart Date: Wed, 15 Mar 2023 09:11:08 -0400 Subject: [PATCH 07/31] Use __attribute__((__noreturn__)) instead of __attribute__((noreturn)) to avoid issue with FreeBSD #define noreturn _Noreturn --- src/unity_internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unity_internals.h b/src/unity_internals.h index 30e0966..54c6853 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -77,7 +77,7 @@ #endif #endif #ifndef UNITY_NORETURN - #define UNITY_NORETURN UNITY_FUNCTION_ATTR(noreturn) + #define UNITY_NORETURN UNITY_FUNCTION_ATTR(__noreturn__) #endif /*------------------------------------------------------- From 91ff8c3ee8f48421a1e6c8704960d57f3dea16f8 Mon Sep 17 00:00:00 2001 From: Torgny Lyon Date: Wed, 15 Mar 2023 19:29:58 +0100 Subject: [PATCH 08/31] Fix delta cast for UINT8_ARRAY_WITHIN --- src/unity_internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unity_internals.h b/src/unity_internals.h index 54c6853..98e298f 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -953,7 +953,7 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_ARRAY) -#define UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_ARRAY) From 6a8e03b5a9bfbc442729701f57d8dbbdb1715e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Hangh=C3=B8j=20Henneberg?= Date: Mon, 17 Apr 2023 18:19:51 +0200 Subject: [PATCH 09/31] Fix filename sanitization with command line option When enabling the command line option the file name added to the runner did not escape the slashes on windows in the same way other paths where sanitized. Copied the sanitization from the other filename uses. --- auto/generate_test_runner.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index aa0f351..ace5930 100755 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -389,7 +389,7 @@ class UnityTestRunnerGenerator output.puts(' {') output.puts(' if (parse_status < 0)') output.puts(' {') - output.puts(" UnityPrint(\"#{filename.gsub('.c', '')}.\");") + output.puts(" UnityPrint(\"#{filename.gsub('.c', '').gsub(/\\/, '\\\\\\')}.\");") output.puts(' UNITY_PRINT_EOL();') tests.each do |test| if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty? From b35f6b0851d1c5086dc61b0eb382d634ba7aeb2c Mon Sep 17 00:00:00 2001 From: nfarid <54642193+nfarid@users.noreply.github.com> Date: Tue, 30 May 2023 11:40:39 +0100 Subject: [PATCH 10/31] Add CMAKE_INSTALL_INCLUDEDIR to INSTALL_INTERFACE's include directory This allows one to #include --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 348266d..f706219 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ target_include_directories(${PROJECT_NAME} $ $ $ + $ $:${CMAKE_CURRENT_SOURCE_DIR}/extras/memory/src>> $:${CMAKE_CURRENT_SOURCE_DIR}/extras/fixture/src>> ) From 9e6e6fcb4434c4b468c8b81c7b4348909822813b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?0xHiro=20/=20=E3=83=92=E3=83=AD?= <90010840+0xhiro@users.noreply.github.com> Date: Sun, 4 Jun 2023 12:24:18 +0900 Subject: [PATCH 11/31] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e71527b..b5b723b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Welcome to the Unity Test Project, one of the main projects of ThrowTheSwitch.or Unity Test is a unit testing framework built for C, with a focus on working with embedded toolchains. This project is made to test code targetting microcontrollers big and small. -The core project is a single C file and a pair of headers, allowing it to the added to your existing build setup without too much headache. +The core project is a single C file and a pair of headers, allowing it to be added to your existing build setup without too much headache. You may use any compiler you wish, and may use most existing build systems including Make, CMake, etc. If you'd like to leave the hard work to us, you might be interested in Ceedling, a build tool also by ThrowTheSwitch.org. From 4d64a170278d4238b75c2022a776430ede773d6a Mon Sep 17 00:00:00 2001 From: Mike Karlesky Date: Mon, 12 Jun 2023 09:58:19 -0400 Subject: [PATCH 12/31] Documentation improvements * Fixed a broken markdown bulleted list * Replaced a missing document link (from the original source of this documentation) with a full sentence explaining the relation of `assert()` to static analysis. * Typographic fixes * Replaced single and double straight quotes with smart quotes where appropriate * Replaced three periods with ellipses where appropriate --- docs/UnityAssertionsReference.md | 105 +++++++++++++++---------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/docs/UnityAssertionsReference.md b/docs/UnityAssertionsReference.md index 99880d8..0a0e51b 100644 --- a/docs/UnityAssertionsReference.md +++ b/docs/UnityAssertionsReference.md @@ -10,46 +10,46 @@ Upon boolean False, an assertion stops execution and reports the failure. and easily execute those assertions. - The structure of Unity allows you to easily separate test assertions from source code in, well, test code. -- Unity's assertions: -- Come in many, many flavors to handle different C types and assertion cases. -- Use context to provide detailed and helpful failure messages. -- Document types, expected values, and basic behavior in your source code for +- Unity’s assertions: + - Come in many, many flavors to handle different C types and assertion cases. + - Use context to provide detailed and helpful failure messages. + - Document types, expected values, and basic behavior in your source code for free. -### Unity Is Several Things But Mainly It's Assertions +### Unity Is Several Things But Mainly It’s Assertions One way to think of Unity is simply as a rich collection of assertions you can use to establish whether your source code behaves the way you think it does. Unity provides a framework to easily organize and execute those assertions in test code separate from your source code. -### What's an Assertion? +### What’s an Assertion? At their core, assertions are an establishment of truth - boolean truth. Was this thing equal to that thing? Does that code doohickey have such-and-such property -or not? You get the idea. Assertions are executable code (to appreciate the big -picture on this read up on the difference between -[link:Dynamic Verification and Static Analysis]). A failing assertion stops -execution and reports an error through some appropriate I/O channel (e.g. -stdout, GUI, file, blinky light). +or not? You get the idea. Assertions are executable code. Static analysis is a +valuable approach to improving code quality, but it is not executing your code +in the way an assertion can. A failing assertion stops execution and reports an +error through some appropriate I/O channel (e.g. stdout, GUI, output file, +blinky light). Fundamentally, for dynamic verification all you need is a single assertion -mechanism. In fact, that's what the [assert() macro][] in C's standard library +mechanism. In fact, that’s what the [assert() macro][] in C’s standard library is for. So why not just use it? Well, we can do far better in the reporting -department. C's `assert()` is pretty dumb as-is and is particularly poor for +department. C’s `assert()` is pretty dumb as-is and is particularly poor for handling common data types like arrays, structs, etc. And, without some other -support, it's far too tempting to litter source code with C's `assert()`'s. It's +support, it’s far too tempting to litter source code with C’s `assert()`’s. It’s generally much cleaner, manageable, and more useful to separate test and source code in the way Unity facilitates. -### Unity's Assertions: Helpful Messages _and_ Free Source Code Documentation +### Unity’s Assertions: Helpful Messages _and_ Free Source Code Documentation Asserting a simple truth condition is valuable, but using the context of the -assertion is even more valuable. For instance, if you know you're comparing bit +assertion is even more valuable. For instance, if you know you’re comparing bit flags and not just integers, then why not use that context to give explicit, readable, bit-level feedback when an assertion fails? -That's what Unity's collection of assertions do - capture context to give you +That’s what Unity’s collection of assertions do - capture context to give you helpful, meaningful assertion failure messages. In fact, the assertions themselves also serve as executable documentation about types and values in your source code. So long as your tests remain current with your source and all those @@ -73,12 +73,12 @@ a simple null check). - `Actual` is the value being tested and unlike the other parameters in an assertion construction is the only parameter present in all assertion variants. - `Modifiers` are masks, ranges, bit flag specifiers, floating point deltas. -- `Expected` is your expected value (duh) to compare to an `actual` value; it's +- `Expected` is your expected value (duh) to compare to an `actual` value; it’s marked as an optional parameter because some assertions only need a single `actual` parameter (e.g. null check). - `Size/count` refers to string lengths, number of array elements, etc. -Many of Unity's assertions are clear duplications in that the same data type +Many of Unity’s assertions are clear duplications in that the same data type is handled by several assertions. The differences among these are in how failure messages are presented. For instance, a `_HEX` variant of an assertion prints the expected and actual values of that assertion formatted as hexadecimal. @@ -99,7 +99,7 @@ _Example:_ TEST_ASSERT_X( {modifiers}, {expected}, actual, {size/count} ) ``` -becomes messageified like thus... +becomes messageified like thus… ```c TEST_ASSERT_X_MESSAGE( {modifiers}, {expected}, actual, {size/count}, message ) @@ -108,7 +108,7 @@ TEST_ASSERT_X_MESSAGE( {modifiers}, {expected}, actual, {size/count}, message ) Notes: - The `_MESSAGE` variants intentionally do not support `printf` style formatting - since many embedded projects don't support or avoid `printf` for various reasons. + since many embedded projects don’t support or avoid `printf` for various reasons. It is possible to use `sprintf` before the assertion to assemble a complex fail message, if necessary. - If you want to output a counter value within an assertion fail message (e.g. from @@ -119,7 +119,7 @@ Notes: Unity provides a collection of assertions for arrays containing a variety of types. These are documented in the Array section below. These are almost on par -with the `_MESSAGE`variants of Unity's Asserts in that for pretty much any Unity +with the `_MESSAGE`variants of Unity’s Asserts in that for pretty much any Unity type assertion you can tack on `_ARRAY` and run assertions on an entire block of memory. @@ -144,7 +144,7 @@ Notes: Unity provides a collection of assertions for arrays containing a variety of types which can be compared to a single value as well. These are documented in the Each Equal section below. these are almost on par with the `_MESSAGE` -variants of Unity's Asserts in that for pretty much any Unity type assertion you +variants of Unity’s Asserts in that for pretty much any Unity type assertion you can inject `_EACH_EQUAL` and run assertions on an entire block of memory. ```c @@ -203,7 +203,7 @@ code then verifies as a final step. #### `TEST_PASS_MESSAGE("message")` This will abort the remainder of the test, but count the test as a pass. Under -normal circumstances, it is not necessary to include this macro in your tests... +normal circumstances, it is not necessary to include this macro in your tests… a lack of failure will automatically be counted as a `PASS`. It is occasionally useful for tests with `#ifdef`s and such. @@ -392,7 +392,7 @@ Asserts that the pointers point to the same memory location. #### `TEST_ASSERT_EQUAL_STRING (expected, actual)` -Asserts that the null terminated (`'\0'`)strings are identical. If strings are +Asserts that the null terminated (`’\0’`)strings are identical. If strings are of different lengths or any portion of the strings before their terminators differ, the assertion fails. Two NULL strings (i.e. zero length) are considered equivalent. @@ -561,7 +561,7 @@ Asserts that the `actual` value is NOT within +/- `delta` of the `expected` valu #### `TEST_ASSERT_EQUAL_FLOAT (expected, actual)` -Asserts that the `actual` value is "close enough to be considered equal" to the +Asserts that the `actual` value is “close enough to be considered equal” to the `expected` value. If you are curious about the details, refer to the Advanced Asserting section for more details on this. Omitting a user-specified delta in a floating point assertion is both a shorthand convenience and a requirement of @@ -569,7 +569,7 @@ code generation conventions for CMock. #### `TEST_ASSERT_NOT_EQUAL_FLOAT (expected, actual)` -Asserts that the `actual` value is NOT "close enough to be considered equal" to the +Asserts that the `actual` value is NOT “close enough to be considered equal” to the `expected` value. #### `TEST_ASSERT_FLOAT_ARRAY_WITHIN (delta, expected, actual, num_elements)` @@ -662,7 +662,7 @@ Asserts that the `actual` value is NOT within +/- `delta` of the `expected` valu #### `TEST_ASSERT_EQUAL_DOUBLE (expected, actual)` -Asserts that the `actual` value is "close enough to be considered equal" to the +Asserts that the `actual` value is “close enough to be considered equal” to the `expected` value. If you are curious about the details, refer to the Advanced Asserting section for more details. Omitting a user-specified delta in a floating point assertion is both a shorthand convenience and a requirement of @@ -670,7 +670,7 @@ code generation conventions for CMock. #### `TEST_ASSERT_NOT_EQUAL_DOUBLE (expected, actual)` -Asserts that the `actual` value is NOT "close enough to be considered equal" to the +Asserts that the `actual` value is NOT “close enough to be considered equal” to the `expected` value. #### `TEST_ASSERT_DOUBLE_ARRAY_WITHIN (delta, expected, actual, num_elements)` @@ -753,7 +753,7 @@ Not A Number floating point representations. This section helps you understand how to deal with some of the trickier assertion situations you may run into. It will give you a glimpse into some of -the under-the-hood details of Unity's assertion mechanisms. If you're one of +the under-the-hood details of Unity’s assertion mechanisms. If you’re one of those people who likes to know what is going on in the background, read on. If not, feel free to ignore the rest of this document until you need it. @@ -768,9 +768,9 @@ mathematical operations might result in a representation of 8 x 2-2 that also evaluates to a value of 2. At some point repeated operations cause equality checks to fail. -So Unity doesn't do direct floating point comparisons for equality. Instead, it -checks if two floating point values are "really close." If you leave Unity -running with defaults, "really close" means "within a significant bit or two." +So Unity doesn’t do direct floating point comparisons for equality. Instead, it +checks if two floating point values are “really close.” If you leave Unity +running with defaults, “really close” means “within a significant bit or two.” Under the hood, `TEST_ASSERT_EQUAL_FLOAT` is really `TEST_ASSERT_FLOAT_WITHIN` with the `delta` parameter calculated on the fly. For single precision, delta is the expected value multiplied by 0.00001, producing a very small proportional @@ -779,28 +779,27 @@ range around the expected value. If you are expecting a value of 20,000.0 the delta is calculated to be 0.2. So any value between 19,999.8 and 20,000.2 will satisfy the equality check. This works out to be roughly a single bit of range for a single-precision number, and -that's just about as tight a tolerance as you can reasonably get from a floating +that’s just about as tight a tolerance as you can reasonably get from a floating point value. -So what happens when it's zero? Zero - even more than other floating point -values - can be represented many different ways. It doesn't matter if you have -0 x 20 or 0 x 263.It's still zero, right? Luckily, if you -subtract these values from each other, they will always produce a difference of -zero, which will still fall between 0 plus or minus a delta of 0. So it still -works! +So what happens when it’s zero? Zero - even more than other floating point +values - can be represented many different ways. It doesn’t matter if you have +0x20 or 0x263. It’s still zero, right? Luckily, if you subtract these +values from each other, they will always produce a difference of zero, which +will still fall between 0 plus or minus a delta of 0. So it still works! Double precision floating point numbers use a much smaller multiplier, again approximating a single bit of error. -If you don't like these ranges and you want to make your floating point equality +If you don’t like these ranges and you want to make your floating point equality assertions less strict, you can change these multipliers to whatever you like by defining UNITY_FLOAT_PRECISION and UNITY_DOUBLE_PRECISION. See Unity documentation for more. ### How do we deal with targets with non-standard int sizes? -It's "fun" that C is a standard where something as fundamental as an integer -varies by target. According to the C standard, an `int` is to be the target's +It’s “fun” that C is a standard where something as fundamental as an integer +varies by target. According to the C standard, an `int` is to be the target’s natural register size, and it should be at least 16-bits and a multiple of a byte. It also guarantees an order of sizes: @@ -814,7 +813,7 @@ and this remains perfectly standard C. To make things even more interesting, there are compilers and targets out there that have a hard choice to make. What if their natural register size is 10-bits -or 12-bits? Clearly they can't fulfill _both_ the requirement to be at least +or 12-bits? Clearly they can’t fulfill _both_ the requirement to be at least 16-bits AND the requirement to match the natural register size. In these situations, they often choose the natural register size, leaving us with something like this: @@ -823,24 +822,24 @@ something like this: char (8 bit) <= short (12 bit) <= int (12 bit) <= long (16 bit) ``` -Um... yikes. It's obviously breaking a rule or two... but they had to break SOME +Um… yikes. It’s obviously breaking a rule or two… but they had to break SOME rules, so they made a choice. When the C99 standard rolled around, it introduced alternate standard-size types. It also introduced macros for pulling in MIN/MAX values for your integer types. -It's glorious! Unfortunately, many embedded compilers can't be relied upon to +It’s glorious! Unfortunately, many embedded compilers can’t be relied upon to use the C99 types (Sometimes because they have weird register sizes as described -above. Sometimes because they don't feel like it?). +above. Sometimes because they don’t feel like it?). A goal of Unity from the beginning was to support every combination of -microcontroller or microprocessor and C compiler. Over time, we've gotten really +microcontroller or microprocessor and C compiler. Over time, we’ve gotten really close to this. There are a few tricks that you should be aware of, though, if -you're going to do this effectively on some of these more idiosyncratic targets. +you’re going to do this effectively on some of these more idiosyncratic targets. -First, when setting up Unity for a new target, you're going to want to pay +First, when setting up Unity for a new target, you’re going to want to pay special attention to the macros for automatically detecting types (where available) or manually configuring them yourself. You can get information -on both of these in Unity's documentation. +on both of these in Unity’s documentation. What about the times where you suddenly need to deal with something odd, like a 24-bit `int`? The simplest solution is to use the next size up. If you have a @@ -848,9 +847,9 @@ What about the times where you suddenly need to deal with something odd, like a `int`, configure Unity to use 16 bits. There are two ways this is going to affect you: -1. When Unity displays errors for you, it's going to pad the upper unused bits +1. When Unity displays errors for you, it’s going to pad the upper unused bits with zeros. -2. You're going to have to be careful of assertions that perform signed +2. You’re going to have to be careful of assertions that perform signed operations, particularly `TEST_ASSERT_INT_WITHIN`. Such assertions might wrap your `int` in the wrong place, and you could experience false failures. You can always back down to a simple `TEST_ASSERT` and do the operations yourself. From e271a76a11df631702af5b2e3e4e5a27a08388cd Mon Sep 17 00:00:00 2001 From: James Browning Date: Tue, 4 Jul 2023 15:16:47 -0700 Subject: [PATCH 13/31] Squash warnings about unhandled enumeration. --- src/unity.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unity.c b/src/unity.c index 3e4bc04..8c946eb 100644 --- a/src/unity.c +++ b/src/unity.c @@ -1115,6 +1115,7 @@ void UnityAssertFloatSpecial(const UNITY_FLOAT actual, is_trait = !isinf(actual) && !isnan(actual); break; + case UNITY_FLOAT_INVALID_TRAIT: /* Supress warning */ default: /* including UNITY_FLOAT_INVALID_TRAIT */ trait_index = 0; trait_names[0] = UnityStrInvalidFloatTrait; @@ -1341,6 +1342,7 @@ void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, is_trait = !isinf(actual) && !isnan(actual); break; + case UNITY_FLOAT_INVALID_TRAIT: /* Supress warning */ default: /* including UNITY_FLOAT_INVALID_TRAIT */ trait_index = 0; trait_names[0] = UnityStrInvalidFloatTrait; From 30b1a05c33cda2489ea2ff1259d3c12f05c2b93c Mon Sep 17 00:00:00 2001 From: Alex Overchenko Date: Sat, 8 Jul 2023 23:15:15 +0300 Subject: [PATCH 14/31] Fix TEST_CASE description typo --- docs/UnityHelperScriptsGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/UnityHelperScriptsGuide.md b/docs/UnityHelperScriptsGuide.md index 06c34ea..8b1e637 100644 --- a/docs/UnityHelperScriptsGuide.md +++ b/docs/UnityHelperScriptsGuide.md @@ -220,7 +220,7 @@ If we use replace comment before test function with the following code: ```C TEST_CASE(1, 2, 5) -TEST_CASE(3, 7, 20) +TEST_CASE(10, 7, 20) ``` script will generate 2 test calls: From 8a5918b81d313fc902c7b51fdf7070f7d09435d0 Mon Sep 17 00:00:00 2001 From: Jason Heeris Date: Thu, 13 Jul 2023 14:53:21 +0800 Subject: [PATCH 15/31] Expose double support as an option. --- meson.build | 7 +++++++ meson_options.txt | 1 + 2 files changed, 8 insertions(+) diff --git a/meson.build b/meson.build index c5cf971..6585129 100644 --- a/meson.build +++ b/meson.build @@ -25,7 +25,9 @@ project('unity', 'c', build_fixture = get_option('extension_fixture') build_memory = get_option('extension_memory') +support_double = get_option('support_double') +unity_args = [] unity_src = [] unity_inc = [] @@ -42,8 +44,13 @@ if build_memory subdir('extras/memory/src') endif +if support_double + unity_args += '-DUNITY_INCLUDE_DOUBLE' +endif + unity_lib = static_library(meson.project_name(), sources: unity_src, + c_args: unity_args, include_directories: unity_inc, install: not meson.is_subproject(), ) diff --git a/meson_options.txt b/meson_options.txt index fbb66d7..8e66784 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1,3 @@ option('extension_fixture', type: 'boolean', value: 'false', description: 'Whether to enable the fixture extension.') option('extension_memory', type: 'boolean', value: 'false', description: 'Whether to enable the memory extension.') +option('support_double', type: 'boolean', value: 'false', description: 'Whether to enable double precision floating point assertions.') From d59381763041ba09ac2387793275477d2f86b387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Hangh=C3=B8j=20Henneberg?= Date: Thu, 13 Jul 2023 22:35:53 +0200 Subject: [PATCH 16/31] Add TEST_MATIX option for parameterization Added matrix option for parameterization that generates cases based on the product of the given arguments. --- auto/generate_test_runner.rb | 49 +++++++++++++++++++++++------------- src/unity.h | 2 +- src/unity_internals.h | 3 +++ 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index ace5930..4fc83f6 100755 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -132,8 +132,8 @@ class UnityTestRunnerGenerator lines.each_with_index do |line, _index| # find tests - next unless line =~ /^((?:\s*(?:TEST_CASE|TEST_RANGE)\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m - next unless line =~ /^((?:\s*(?:TEST_CASE|TEST_RANGE)\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]})\w*)\s*\(\s*(.*)\s*\)/m + next unless line =~ /^((?:\s*(?:TEST_(?:CASE|RANGE|MATRIX))\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m + next unless line =~ /^((?:\s*(?:TEST_(?:CASE|RANGE|MATRIX))\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]})\w*)\s*\(\s*(.*)\s*\)/m arguments = Regexp.last_match(1) name = Regexp.last_match(2) @@ -143,25 +143,38 @@ class UnityTestRunnerGenerator if @options[:use_param_tests] && !arguments.empty? args = [] - type_and_args = arguments.split(/TEST_(CASE|RANGE)/) + type_and_args = arguments.split(/TEST_(CASE|RANGE|MATRIX)/) for i in (1...type_and_args.length).step(2) - if type_and_args[i] == "CASE" + case type_and_args[i] + when "CASE" args << type_and_args[i + 1].sub(/^\s*\(\s*(.*?)\s*\)\s*$/m, '\1') - next - end - # RANGE - args += type_and_args[i + 1].scan(/(\[|<)\s*(-?\d+.?\d*)\s*,\s*(-?\d+.?\d*)\s*,\s*(-?\d+.?\d*)\s*(\]|>)/m).map do |arg_values_str| - exclude_end = arg_values_str[0] == '<' && arg_values_str[-1] == '>' - arg_values_str[1...-1].map do |arg_value_str| - arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i - end.push(exclude_end) - end.map do |arg_values| - Range.new(arg_values[0], arg_values[1], arg_values[3]).step(arg_values[2]).to_a - end.reduce(nil) do |result, arg_range_expanded| - result.nil? ? arg_range_expanded.map { |a| [a] } : result.product(arg_range_expanded) - end.map do |arg_combinations| - arg_combinations.flatten.join(', ') + when "RANGE" + args += type_and_args[i + 1].scan(/(\[|<)\s*(-?\d+.?\d*)\s*,\s*(-?\d+.?\d*)\s*,\s*(-?\d+.?\d*)\s*(\]|>)/m).map do |arg_values_str| + exclude_end = arg_values_str[0] == '<' && arg_values_str[-1] == '>' + arg_values_str[1...-1].map do |arg_value_str| + arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i + end.push(exclude_end) + end.map do |arg_values| + Range.new(arg_values[0], arg_values[1], arg_values[3]).step(arg_values[2]).to_a + end.reduce(nil) do |result, arg_range_expanded| + result.nil? ? arg_range_expanded.map { |a| [a] } : result.product(arg_range_expanded) + end.map do |arg_combinations| + arg_combinations.flatten.join(', ') + end + + when "MATRIX" + single_arg_regex_string = /(?:(?:"(?:\\"|[^\\])*?")+|(?:'\\?.')+|(?:[^\s\]\["'\,]|\[[\d\S_-]+\])+)/.source + args_regex = /\[((?:\s*#{single_arg_regex_string}\s*,?)*(?:\s*#{single_arg_regex_string})?\s*)\]/m + arg_elements_regex = /\s*(#{single_arg_regex_string})\s*,\s*/m + + args += type_and_args[i + 1].scan(args_regex).flatten.map do |arg_values_str| + (arg_values_str + ',').scan(arg_elements_regex) + end.reduce do |result, arg_range_expanded| + result.product(arg_range_expanded) + end.map do |arg_combinations| + arg_combinations.flatten.join(', ') + end end end end diff --git a/src/unity.h b/src/unity.h index e321a1d..e4db314 100644 --- a/src/unity.h +++ b/src/unity.h @@ -89,7 +89,7 @@ void verifyTest(void); * - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script * Parameterized Tests - * - you'll want to create a define of TEST_CASE(...) and/or TEST_RANGE(...) which basically evaluates to nothing + * - you'll want to create a define of TEST_CASE(...), TEST_RANGE(...) and/or TEST_MATRIX(...) which basically evaluates to nothing * Tests with Arguments * - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity diff --git a/src/unity_internals.h b/src/unity_internals.h index 98e298f..9f89eda 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -793,6 +793,9 @@ extern const char UnityStrErrShorthand[]; #if !defined(TEST_RANGE) && !defined(UNITY_EXCLUDE_TEST_RANGE) #define TEST_RANGE(...) #endif + #if !defined(TEST_MATRIX) && !defined(UNITY_EXCLUDE_TEST_MATRIX) + #define TEST_MATRIX(...) + #endif #endif #endif From 5dd2be96fa64d2c09cc040f531ce9c384690746c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Hangh=C3=B8j=20Henneberg?= Date: Thu, 13 Jul 2023 23:01:13 +0200 Subject: [PATCH 17/31] Add TEST_MATRIX to docs --- docs/UnityConfigurationGuide.md | 4 +- docs/UnityHelperScriptsGuide.md | 87 +++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/docs/UnityConfigurationGuide.md b/docs/UnityConfigurationGuide.md index d5e4098..88603fc 100644 --- a/docs/UnityConfigurationGuide.md +++ b/docs/UnityConfigurationGuide.md @@ -448,7 +448,7 @@ To enable it, use the following example: #define UNITY_SUPPORT_TEST_CASES ``` -You can manually provide required `TEST_CASE` or `TEST_RANGE` macro definitions +You can manually provide required `TEST_CASE`, `TEST_RANGE` or `TEST_MATRIX` macro definitions before including `unity.h`, and they won't be redefined. If you provide one of the following macros, some of default definitions will not be defined: @@ -456,8 +456,10 @@ defined: |---|---| | `UNITY_EXCLUDE_TEST_CASE` | `TEST_CASE` | | `UNITY_EXCLUDE_TEST_RANGE` | `TEST_RANGE` | +| `UNITY_EXCLUDE_TEST_MATRIX` | `TEST_MATRIX` | | `TEST_CASE` | `TEST_CASE` | | `TEST_RANGE` | `TEST_RANGE` | +| `TEST_MATRIX` | `TEST_MATRIX` | `UNITY_EXCLUDE_TEST_*` defines is not processed by test runner generator script. If you exclude one of them from definition, you should provide your own definition diff --git a/docs/UnityHelperScriptsGuide.md b/docs/UnityHelperScriptsGuide.md index 8b1e637..3c32133 100644 --- a/docs/UnityHelperScriptsGuide.md +++ b/docs/UnityHelperScriptsGuide.md @@ -296,6 +296,93 @@ TEST_CASE(4, 8, 30) TEST_CASE(4, 6, 30) ``` +##### `TEST_MATRIX` + +Test matix is an advanced generator. It single call can be converted to zero, +one or few `TEST_CASE` equivalent commands. + +That generator will create tests for all cobinations of the provided list. Each argument has to be given as a list of one or more elements in the format `[, , ..., , ]`. + +All parameters supported by the `TEST_CASE` is supported as arguments: +- Numbers incl type specifiers e.g. `<1>`, `<1u>`, `<1l>`, `<2.3>`, or `<2.3f>` +- Strings incl string concatianion e.g. `<"string">`, or `<"partial" "string">` +- Chars e.g. `<'c'>` +- Enums e.g. `` +- Elements of arrays e.g. `` + +Let's use our `test_demoParamFunction` test for checking, what ranges +will be generated for our single `TEST_RANGE` row: + +```C +TEST_MATRIX([3, 4, 7], [10, 8, 2, 1],[30u, 20.0f]) +``` + +Tests execution output will be similar to that text: + +```Log +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 10, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 10, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 8, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 8, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 2, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 2, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 1, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 1, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 10, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 10, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 8, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 8, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 2, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 2, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 1, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 1, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 10, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 10, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 8, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 8, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 2, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 2, 20.0f):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 1, 30u):PASS +tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 1, 20.0f):PASS +``` + +As we can see: + +| Parameter | Format | Count of values | +|---|---|---| +| `a` | `[3, 4, 7]` | 2 | +| `b` | `[10, 8, 2, 1]` | 4 | +| `c` | `[30u, 20.0f]` | 2 | + +We totally have 2 * 4 * 2 = 16 equal test cases, that can be written as following: + +```C +TEST_CASE(3, 10, 30u) +TEST_CASE(3, 10, 20.0f) +TEST_CASE(3, 8, 30u) +TEST_CASE(3, 8, 20.0f) +TEST_CASE(3, 2, 30u) +TEST_CASE(3, 2, 20.0f) +TEST_CASE(3, 1, 30u) +TEST_CASE(3, 1, 20.0f) +TEST_CASE(4, 10, 30u) +TEST_CASE(4, 10, 20.0f) +TEST_CASE(4, 8, 30u) +TEST_CASE(4, 8, 20.0f) +TEST_CASE(4, 2, 30u) +TEST_CASE(4, 2, 20.0f) +TEST_CASE(4, 1, 30u) +TEST_CASE(4, 1, 20.0f) +TEST_CASE(7, 10, 30u) +TEST_CASE(7, 10, 20.0f) +TEST_CASE(7, 8, 30u) +TEST_CASE(7, 8, 20.0f) +TEST_CASE(7, 2, 30u) +TEST_CASE(7, 2, 20.0f) +TEST_CASE(7, 1, 30u) +TEST_CASE(7, 1, 20.0f) +``` + ### `unity_test_summary.rb` A Unity test file contains one or more test case functions. From c97a2705b36a23f4a09228daddaae9d94d41fc1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Hangh=C3=B8j=20Henneberg?= Date: Thu, 13 Jul 2023 22:36:23 +0200 Subject: [PATCH 18/31] Add tests for TEST_MATRIX --- test/tests/test_unity_parameterized.c | 90 +++++++++++++++++++++++ test/tests/test_unity_parameterizedDemo.c | 4 + test/tests/types_for_test.h | 14 ++++ 3 files changed, 108 insertions(+) create mode 100644 test/tests/types_for_test.h diff --git a/test/tests/test_unity_parameterized.c b/test/tests/test_unity_parameterized.c index 6b8aeb7..24e1f9c 100644 --- a/test/tests/test_unity_parameterized.c +++ b/test/tests/test_unity_parameterized.c @@ -7,6 +7,7 @@ #include #include #include "unity.h" +#include "types_for_test.h" /* Include Passthroughs for Linking Tests */ void putcharSpy(int c) { (void)putchar(c);} @@ -209,6 +210,14 @@ TEST_RANGE([2, TEST_CASE( 6 , 7) +TEST_MATRIX([7, + 8 , + + 9, 10], + [ + 11] + + ) void test_SpaceInTestCase(unsigned index, unsigned bigger) { TEST_ASSERT_EQUAL_UINT32(NextExpectedSpaceIndex, index); @@ -216,3 +225,84 @@ void test_SpaceInTestCase(unsigned index, unsigned bigger) NextExpectedSpaceIndex++; } + +TEST_MATRIX([1, 5, (2*2)+1, 4]) +void test_SingleMatix(unsigned value) +{ + TEST_ASSERT_LESS_OR_EQUAL(10, value); +} + +TEST_MATRIX([2, 5l, 4u+3, 4ul], [-2, 3]) +void test_TwoMatrices(unsigned first, signed second) +{ + static unsigned idx = 0; + static const unsigned expected[] = + { + // -2 3 + -4, 6, // 2 + -10, 15, // 5 + -14, 21, // 7 + -8, 12, // 4 + }; + TEST_ASSERT_EQUAL_INT(expected[idx++], first * second); +} + +TEST_MATRIX(["String1", "String,2", "Stri" "ng3", "String[4]", "String\"5\""], [-5, 12.5f]) +void test_StringsAndNumbersMatrices(const char* str, float number) +{ + static unsigned idx = 0; + static const char* expected[] = + { + "String1_-05.00", + "String1_+12.50", + "String,2_-05.00", + "String,2_+12.50", + "String3_-05.00", + "String3_+12.50", + "String[4]_-05.00", + "String[4]_+12.50", + "String\"5\"_-05.00", + "String\"5\"_+12.50", + }; + char buf[200] = {0}; + snprintf(buf, sizeof(buf), "%s_%+06.2f", str, number); + TEST_ASSERT_EQUAL_STRING(expected[idx++], buf); +} + +TEST_MATRIX( + [ENUM_A, ENUM_4, ENUM_C], + [test_arr[0], 7.8f, test_arr[2]], + ['a', 'f', '[', ']', '\'', '"'], +) +void test_EnumCharAndArrayMatrices(test_enum_t e, float n, char c) +{ + static unsigned enum_idx = 0; + static const test_enum_t exp_enum[3] = { + ENUM_A, ENUM_4, ENUM_C, + }; + + static unsigned float_idx = 0; + float exp_float[3] = {0}; + exp_float[0] = test_arr[0]; + exp_float[1] = 7.8f; + exp_float[2] = test_arr[2]; + + static unsigned char_idx = 0; + static const test_enum_t exp_char[] = { + 'a', 'f', '[', ']', '\'', '"' + }; + + TEST_ASSERT_EQUAL_INT(exp_enum[enum_idx], e); + TEST_ASSERT_EQUAL_FLOAT(exp_float[float_idx], n); + TEST_ASSERT_EQUAL_CHAR(exp_char[char_idx], c); + + char_idx = (char_idx + 1) % 6; + if (char_idx == 0.0f) + { + float_idx = (float_idx + 1) % 3; + if (float_idx == 0.0f) + { + enum_idx = (enum_idx + 1) % 3; + } + } +} \ No newline at end of file diff --git a/test/tests/test_unity_parameterizedDemo.c b/test/tests/test_unity_parameterizedDemo.c index 2e2efc8..83dfad6 100644 --- a/test/tests/test_unity_parameterizedDemo.c +++ b/test/tests/test_unity_parameterizedDemo.c @@ -7,10 +7,14 @@ #ifndef TEST_RANGE #define TEST_RANGE(...) #endif +#ifndef TEST_MATRIX +#define TEST_MATRIX(...) +#endif TEST_CASE(1, 2, 5) TEST_CASE(10, 7, 20) TEST_RANGE([3, 4, 1], [10, 5, -2], <30, 31, 1>) +TEST_MATRIX([3, 4, 7], [10, 8, 2, 1],[30u, 20.0f]) void test_demoParamFunction(int a, int b, int c) { TEST_ASSERT_GREATER_THAN_INT(a + b, c); diff --git a/test/tests/types_for_test.h b/test/tests/types_for_test.h new file mode 100644 index 0000000..8bae1ec --- /dev/null +++ b/test/tests/types_for_test.h @@ -0,0 +1,14 @@ +#pragma once + +typedef enum { + ENUM_A, + ENUM_2, + ENUM_C, + ENUM_4, +} test_enum_t; + +static const float test_arr[] = { + 1.2f, + 2.3f, + 3.4f, +}; \ No newline at end of file From 5baa4580eebdbebc7eba4797cb46a5df17016470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Hangh=C3=B8j=20Henneberg?= Date: Sat, 15 Jul 2023 22:19:46 +0200 Subject: [PATCH 19/31] Fix file endings --- test/tests/test_unity_parameterized.c | 2 +- test/tests/types_for_test.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/tests/test_unity_parameterized.c b/test/tests/test_unity_parameterized.c index 24e1f9c..aa9f9c1 100644 --- a/test/tests/test_unity_parameterized.c +++ b/test/tests/test_unity_parameterized.c @@ -305,4 +305,4 @@ void test_EnumCharAndArrayMatrices(test_enum_t e, float n, char c) enum_idx = (enum_idx + 1) % 3; } } -} \ No newline at end of file +} diff --git a/test/tests/types_for_test.h b/test/tests/types_for_test.h index 8bae1ec..6da4e51 100644 --- a/test/tests/types_for_test.h +++ b/test/tests/types_for_test.h @@ -11,4 +11,4 @@ static const float test_arr[] = { 1.2f, 2.3f, 3.4f, -}; \ No newline at end of file +}; From aa3ca2d5728ed91a9f20581533f749b8b2e470df Mon Sep 17 00:00:00 2001 From: Michael Karlesky Date: Sat, 29 Jul 2023 20:20:33 -0400 Subject: [PATCH 20/31] Add/update build directives * Renamed macro `TEST_FILE()` to `TEST_SOURCE_FILE()` * Added macro `TEST_INCLUDE_PATH()` * Added full comment block for documentation --- src/unity.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/unity.h b/src/unity.h index e321a1d..d849a3f 100644 --- a/src/unity.h +++ b/src/unity.h @@ -113,9 +113,19 @@ void verifyTest(void); #define TEST_PASS() TEST_ABORT() #define TEST_PASS_MESSAGE(message) do { UnityMessage((message), __LINE__); TEST_ABORT(); } while (0) -/* This macro does nothing, but it is useful for build tools (like Ceedling) to make use of this to figure out - * which files should be linked to in order to perform a test. Use it like TEST_FILE("sandwiches.c") */ -#define TEST_FILE(a) +/*------------------------------------------------------- + * Build Directives + *------------------------------------------------------- + + * These macros do nothing, but they are useful for additional build context. + * Tools (like Ceedling) can scan for these directives and make use of them for + * per-test-executable #include search paths and linking. */ + +/* Add source files to a test executable's compilation and linking. Ex: TEST_SOURCE_FILE("sandwiches.c") */ +#define TEST_SOURCE_FILE(a) + +/* Customize #include search paths for a test executable's compilation. Ex: TEST_INCLUDE_PATH("src/module_a/inc") */ +#define TEST_INCLUDE_PATH(a) /*------------------------------------------------------- * Test Asserts (simple) From 7a9e25b445ecc3d744bc46a97b4f05f87dcc614e Mon Sep 17 00:00:00 2001 From: epsilonrt Date: Tue, 8 Aug 2023 22:15:56 +0200 Subject: [PATCH 21/31] fix: fixes TEST_PRINTF() expansion error #691 fixes TEST_PRINTF() expansion error when no variadic arguments are passed --- src/unity.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unity.h b/src/unity.h index e321a1d..77dfc12 100644 --- a/src/unity.h +++ b/src/unity.h @@ -105,7 +105,7 @@ void verifyTest(void); #define TEST_MESSAGE(message) UnityMessage((message), __LINE__) #define TEST_ONLY() #ifdef UNITY_INCLUDE_PRINT_FORMATTED -#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), __VA_ARGS__) +#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), ##__VA_ARGS__) #endif /* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails. From 5109be3881f5f2304e801b1df06a99157167cca7 Mon Sep 17 00:00:00 2001 From: Mike Karlesky Date: Tue, 15 Aug 2023 21:16:02 -0400 Subject: [PATCH 22/31] Missed renames of TEST_FILE() directive --- auto/generate_test_runner.rb | 2 +- test/testdata/testRunnerGeneratorSmall.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index ace5930..30d4107 100755 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -197,7 +197,7 @@ class UnityTestRunnerGenerator includes = { local: source.scan(/^\s*#include\s+\"\s*(.+\.#{@options[:include_extensions]})\s*\"/).flatten, system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" }, - linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+\.#{@options[:source_extensions]})\s*\"/).flatten + linkonly: source.scan(/^TEST_SOURCE_FILE\(\s*\"\s*(.+\.#{@options[:source_extensions]})\s*\"/).flatten } includes end diff --git a/test/testdata/testRunnerGeneratorSmall.c b/test/testdata/testRunnerGeneratorSmall.c index dc687ba..58bc65c 100644 --- a/test/testdata/testRunnerGeneratorSmall.c +++ b/test/testdata/testRunnerGeneratorSmall.c @@ -4,7 +4,7 @@ #include "unity.h" #include "Defs.h" -TEST_FILE("some_file.c") +TEST_SOURCE_FILE("some_file.c") /* Notes about prefixes: test - normal default prefix. these are "always run" tests for this procedure From f3b2de4da260b67e36a515844ecc34a131ae86ff Mon Sep 17 00:00:00 2001 From: cmachida Date: Fri, 25 Aug 2023 17:14:55 +0000 Subject: [PATCH 23/31] fix: TEST_PRINTF(): printing 64-bit hex numbers or pointers --- src/unity.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/unity.c b/src/unity.c index 8c946eb..b6c08b7 100644 --- a/src/unity.c +++ b/src/unity.c @@ -2031,15 +2031,29 @@ static void UnityPrintFVA(const char* format, va_list va) UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int); UNITY_OUTPUT_CHAR('0'); UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex(number, 8); + if (length_mod == UNITY_LENGTH_MODIFIER_LONG_LONG) + { + UnityPrintNumberHex(number, 16); + } + else + { + UnityPrintNumberHex(number, 8); + } break; } case 'p': { - const unsigned int number = va_arg(va, unsigned int); + UNITY_UINT number; + char nibbles_to_print = 8; + if (UNITY_POINTER_WIDTH == 64) + { + length_mod = UNITY_LENGTH_MODIFIER_LONG_LONG; + nibbles_to_print = 16; + } + UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int); UNITY_OUTPUT_CHAR('0'); UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((UNITY_UINT)number, 8); + UnityPrintNumberHex((UNITY_UINT)number, nibbles_to_print); break; } case 'c': From 710bb58c6a91dfbd605973e0c38c4f624cd13776 Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Tue, 29 Aug 2023 13:46:18 +0200 Subject: [PATCH 24/31] Allow user-defined TEST_PROTECT & TEST_ABORT macros However rare, this update covers real-world use cases where: - Unity is used to provide the assertion macros only, and an external test harness/runner is used for test orchestration/reporting. - Calling longjmp on a given platform is possible, but has a platform-specific (or implementation-specific) set of prerequisites, e.g. privileged access level. Enable project-specific customisation of TEST_PROTECT and TEST_ABORT macros. - Use the user-defined UNITY_TEST_ABORT if available; fall back to default behaviour otherwise. - Use the user-defined UNITY_TEST_PROTECT if available; fall back to default behaviour otherwise. - These may be defined independently. --- docs/UnityConfigurationGuide.md | 62 +++++++++++++++++++++++++++++++++ src/unity_internals.h | 14 +++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/docs/UnityConfigurationGuide.md b/docs/UnityConfigurationGuide.md index 88603fc..e56b4a4 100644 --- a/docs/UnityConfigurationGuide.md +++ b/docs/UnityConfigurationGuide.md @@ -399,6 +399,68 @@ _Example:_ #define UNITY_EXCLUDE_SETJMP ``` +#### `UNITY_TEST_PROTECT` + +#### `UNITY_TEST_ABORT` + +Unity handles test failures via `setjmp`/`longjmp` pair by default. As mentioned above, you can disable this with `UNITY_EXCLUDE_SETJMP`. You can also customise what happens on every `TEST_PROTECT` and `TEST_ABORT` call. This can be accomplished by providing user-defined `UNITY_TEST_PROTECT` and `UNITY_TEST_ABORT` macros (and these may be defined independently). + +`UNITY_TEST_PROTECT` is used as an `if` statement expression, and has to evaluate to `true` on the first call (when saving stack environment with `setjmp`), and to `false` when it returns as a result of a `TEST_ABORT` (when restoring the stack environment with `longjmp`). + +Whenever an assert macro fails, `TEST_ABORT` is used to restore the stack environment previously set by `TEST_PROTECT`. This part may be overriden with `UNITY_TEST_ABORT`, e.g. if custom failure handling is needed. + +_Example 1:_ + +Calling `longjmp` on your target is possible, but has a platform-specific (or implementation-specific) set of prerequisites, e.g. privileged access level. You can extend the default behaviour of `TEST_PROTECT` and `TEST_ABORT` as: + +`unity_config.h`: + +```C +#include "my_custom_test_handlers.h" + +#define UNITY_TEST_PROTECT() custom_test_protect() +#define UNITY_TEST_ABORT() custom_test_abort() +``` + +`my_custom_test_handlers.c`: + +```C +int custom_test_protect(void) { + platform_specific_code(); + return setjmp(Unity.AbortFrame) == 0; +} + +UNITY_NORETURN void custom_test_abort(void) { + more_platform_specific_code(); + longjmp(Unity.AbortFrame, 1); +} +``` + +_Example 2:_ + +Unity is used to provide the assertion macros only, and an external test harness/runner is used for test orchestration/reporting. In this case you can easily plug your code by overriding `TEST_ABORT` as: + +`unity_config.h`: + +```C +#include "my_custom_test_handlers.h" + +#define UNITY_TEST_PROTECT() 1 +#define UNITY_TEST_ABORT() custom_test_abort() +``` + +`my_custom_test_handlers.c`: + +```C +void custom_test_abort(void) { + if (Unity.CurrentTestFailed == 1) { + custom_failed_test_handler(); + } else if (Unity.CurrentTestIgnored == 1) { + custom_ignored_test_handler(); + } +} +``` + #### `UNITY_OUTPUT_COLOR` If you want to add color using ANSI escape codes you can use this define. diff --git a/src/unity_internals.h b/src/unity_internals.h index 9f89eda..11d9abb 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -759,13 +759,25 @@ extern const char UnityStrErrShorthand[]; * Test Running Macros *-------------------------------------------------------*/ +#ifdef UNITY_TEST_PROTECT +#define TEST_PROTECT() UNITY_TEST_PROTECT() +#else #ifndef UNITY_EXCLUDE_SETJMP_H #define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) -#define TEST_ABORT() longjmp(Unity.AbortFrame, 1) #else #define TEST_PROTECT() 1 +#endif +#endif + +#ifdef UNITY_TEST_ABORT +#define TEST_ABORT() UNITY_TEST_ABORT() +#else +#ifndef UNITY_EXCLUDE_SETJMP_H +#define TEST_ABORT() longjmp(Unity.AbortFrame, 1) +#else #define TEST_ABORT() return #endif +#endif /* Automatically enable variadic macros support, if it not enabled before */ #ifndef UNITY_SUPPORT_VARIADIC_MACROS From 955809048c3a7fbe04481abbfd9d0deeee2b7784 Mon Sep 17 00:00:00 2001 From: "Michael Gene Brockus (Dreamer)" <55331536+dreamer-coding-555@users.noreply.github.com> Date: Fri, 15 Sep 2023 09:53:34 -0600 Subject: [PATCH 25/31] Create bdd.h --- extras/bdd/src/bdd.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 extras/bdd/src/bdd.h diff --git a/extras/bdd/src/bdd.h b/extras/bdd/src/bdd.h new file mode 100644 index 0000000..35f177d --- /dev/null +++ b/extras/bdd/src/bdd.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2023 Michael Gene Brockus (Dreamer) and Contributed to Unity Project + * ========================================== + * Unity Project - A Test Framework for C + * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + * [Released under MIT License. Please refer to license.txt for details] + * ========================================== */ + +#ifndef UNITY_BDD_TEST_H_ +#define UNITY_BDD_TEST_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Macros for defining a Behavior-Driven Development (BDD) structure with descriptions. + * + * These macros provide a way to structure and describe different phases (Given, When, Then) of a + * test scenario in a BDD-style format. However, they don't have functional behavior by themselves + * and are used for descriptive purposes. + */ +#define GIVEN(description) \ + if (0) { \ + printf("Given %s\n", description); \ + } else + +#define WHEN(description) \ + if (0) { \ + printf("When %s\n", description); \ + } else + +#define THEN(description) \ + if (0) { \ + printf("Then %s\n", description); \ + } else + +#ifdef __cplusplus +} +#endif + +#endif From cf13244043603803a8fefc84162e8efd06dfc471 Mon Sep 17 00:00:00 2001 From: "Michael Gene Brockus (Dreamer)" <55331536+dreamer-coding-555@users.noreply.github.com> Date: Fri, 15 Sep 2023 09:54:32 -0600 Subject: [PATCH 26/31] adding stdio --- extras/bdd/src/bdd.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extras/bdd/src/bdd.h b/extras/bdd/src/bdd.h index 35f177d..d91b3f1 100644 --- a/extras/bdd/src/bdd.h +++ b/extras/bdd/src/bdd.h @@ -13,6 +13,8 @@ extern "C" { #endif +#include + /** * @brief Macros for defining a Behavior-Driven Development (BDD) structure with descriptions. * From de387ef0731219dd50119f008e0f9e99810bb220 Mon Sep 17 00:00:00 2001 From: "Michael Gene Brockus (Dreamer)" <55331536+dreamer-coding-555@users.noreply.github.com> Date: Fri, 15 Sep 2023 10:12:34 -0600 Subject: [PATCH 27/31] Create test_bdd.c --- extras/bdd/test/test_bdd.c | 128 +++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 extras/bdd/test/test_bdd.c diff --git a/extras/bdd/test/test_bdd.c b/extras/bdd/test/test_bdd.c new file mode 100644 index 0000000..4f41585 --- /dev/null +++ b/extras/bdd/test/test_bdd.c @@ -0,0 +1,128 @@ +/* ========================================== + * Unity Project - A Test Framework for C + * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + * [Released under MIT License. Please refer to license.txt for details] + * ========================================== */ + +#include "unity.h" +#include "unity_bdd.h" + +void test_bdd_logic_test(void) { + GIVEN("a valid statement is passed") + { + // Set up the context + bool givenExecuted = true; + + WHEN("a statement is true") + { + // Perform the login action + bool whenExecuted = true; + + THEN("we validate everything was worked") + { + // Check the expected outcome + bool thenExecuted = true; + + TEST_ASSERT_TRUE(givenExecuted); + TEST_ASSERT_TRUE(whenExecuted); + TEST_ASSERT_TRUE(thenExecuted); + } + } + } +} // end of case + +void test_bdd_user_account(void) { + GIVEN("a user's account with sufficient balance") + { + // Set up the context + float accountBalance = 500.0; + float withdrawalAmount = 200.0; + + WHEN("the user requests a withdrawal of $200") + { + // Perform the withdrawal action + if (accountBalance >= withdrawalAmount) + { + accountBalance -= withdrawalAmount; + } // end if + THEN("the withdrawal amount should be deducted from the account balance") + { + // Check the expected outcome + + // Simulate the scenario + float compareBalance = 500.0; + TEST_ASSERT_LESS_THAN_FLOAT(accountBalance, compareBalance); + } + } + } +} // end of case + +void test_bdd_empty_cart(void) { + GIVEN("a user with an empty shopping cart") + { + // Set up the context + int cartItemCount = 0; + + WHEN("the user adds a product to the cart") + { + // Perform the action of adding a product + + THEN("the cart item count should increase by 1") + { + // Check the expected outcome + cartItemCount++; + + TEST_ASSERT_EQUAL_INT(cartItemCount, 1); + } + } + } +} // end of case + +void test_bdd_valid_login(void) { + GIVEN("a registered user with valid credentials") + { + // Set up the context + const char* validUsername = "user123"; + const char* validPassword = "pass456"; + + WHEN("the user provides correct username and password") + { + // Perform the action of user login + const char* inputUsername = "user123"; + const char* inputPassword = "pass456"; + + THEN("the login should be successful") + { + // Check the expected outcome + // Simulate login validation + TEST_ASSERT_EQUAL_STRING(inputUsername, validUsername); + TEST_ASSERT_EQUAL_STRING(inputPassword, validPassword); + } + } + + WHEN("the user provides incorrect password") + { + // Perform the action of user login + const char* inputUsername = "user123"; + const char* inputPassword = "wrongpass"; + + THEN("the login should fail with an error message") + { + // Check the expected outcome + // Simulate login validation + TEST_ASSERT_EQUAL_STRING(inputUsername, validUsername); + // TEST_ASSERT_NOT_EQUAL_STRING(inputPassword, validPassword); + } + } + } +} // end of case + +int main(void) +{ + UnityBegin("test_bdd.c"); + RUN_TEST(test_bdd_logic_test); + RUN_TEST(test_bdd_user_account); + RUN_TEST(test_bdd_empty_cart); + RUN_TEST(test_bdd_valid_login); + return UnityEnd(); +} From a4d0150758aa8bcd25563c727fe04d845e3399a3 Mon Sep 17 00:00:00 2001 From: "Michael Gene Brockus (Dreamer)" <55331536+dreamer-coding-555@users.noreply.github.com> Date: Fri, 15 Sep 2023 10:13:06 -0600 Subject: [PATCH 28/31] Rename bdd.h to unity_bdd.h --- extras/bdd/src/{bdd.h => unity_bdd.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename extras/bdd/src/{bdd.h => unity_bdd.h} (100%) diff --git a/extras/bdd/src/bdd.h b/extras/bdd/src/unity_bdd.h similarity index 100% rename from extras/bdd/src/bdd.h rename to extras/bdd/src/unity_bdd.h From 24c175f64f31a6b2d5fcc25de1e5f32897f6118d Mon Sep 17 00:00:00 2001 From: "Michael Gene Brockus (Dreamer)" <55331536+dreamer-coding-555@users.noreply.github.com> Date: Fri, 15 Sep 2023 10:20:26 -0600 Subject: [PATCH 29/31] Create readme.md --- extras/bdd/readme.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 extras/bdd/readme.md diff --git a/extras/bdd/readme.md b/extras/bdd/readme.md new file mode 100644 index 0000000..e703588 --- /dev/null +++ b/extras/bdd/readme.md @@ -0,0 +1,40 @@ +# Unity Project - BDD Feature + +Unity's Behavior-Driven Development (BDD) test feature. It allows developers to structure and describe various phases (Given, When, Then) of a test scenario in a BDD-style format. + +## Introduction + +This project is based on the Unity framework originally created by Mike Karlesky, Mark VanderVoord, and Greg Williams in 2007. The project extends Unity by providing macros to define BDD structures with descriptive elements. Feature added by Michael Gene Brockus (Dreamer). + +## License + +This project is distributed under the MIT License. See the [license.txt](license.txt) file for more information. + +## Usage + +### BDD Macros + +The provided BDD macros allow you to structure your test scenarios in a descriptive manner. These macros are for descriptive purposes only and do not have functional behavior. + +- `GIVEN(description)`: Describes the "Given" phase of a test scenario. +- `WHEN(description)`: Describes the "When" phase of a test scenario. +- `THEN(description)`: Describes the "Then" phase of a test scenario. + +Example usage: + +```c +GIVEN("a valid input") { + // Test setup and context + // ... + + WHEN("the input is processed") { + // Perform the action + // ... + + THEN("the expected outcome occurs") { + // Assert the outcome + // ... + } + } +} +``` From 4403d97d1420d0638150486ea1cfde3130d6b097 Mon Sep 17 00:00:00 2001 From: "Michael Gene Brockus (Dreamer)" <55331536+dreamer-coding-555@users.noreply.github.com> Date: Fri, 15 Sep 2023 10:22:26 -0600 Subject: [PATCH 30/31] Create meson.build --- extras/bdd/test/meson.build | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 extras/bdd/test/meson.build diff --git a/extras/bdd/test/meson.build b/extras/bdd/test/meson.build new file mode 100644 index 0000000..fcdafff --- /dev/null +++ b/extras/bdd/test/meson.build @@ -0,0 +1,9 @@ +project('BDD Tester', 'c') + +# Add Unity as a dependency +unity_dep = dependency('unity') + +# Define your source files +sources = files('test_bdd.c') + +executable('tester', sources, dependencies : unity_dep) From 7d0bcc892ec8517c4d97c605711e9a5cd43c23d8 Mon Sep 17 00:00:00 2001 From: SteveBroshar Date: Sun, 8 Oct 2023 15:47:22 -0500 Subject: [PATCH 31/31] use null check instead of pointer compar --- src/unity.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unity.c b/src/unity.c index b6c08b7..e455f57 100644 --- a/src/unity.c +++ b/src/unity.c @@ -1609,8 +1609,8 @@ void UnityAssertEqualString(const char* expected, } } else - { /* handle case of one pointers being null (if both null, test should pass) */ - if (expected != actual) + { /* fail if either null but not if both */ + if (expected || actual) { Unity.CurrentTestFailed = 1; } @@ -1649,8 +1649,8 @@ void UnityAssertEqualStringLen(const char* expected, } } else - { /* handle case of one pointers being null (if both null, test should pass) */ - if (expected != actual) + { /* fail if either null but not if both */ + if (expected || actual) { Unity.CurrentTestFailed = 1; }