ceedling 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. checksums.yaml +4 -4
  2. data/GIT_COMMIT_SHA +1 -1
  3. data/README.md +1 -1
  4. data/assets/fake_crash_test_fixture.rb +14 -0
  5. data/assets/partial_all_module.h +11 -0
  6. data/assets/run_with_ubsan.rb +15 -0
  7. data/assets/same_dir_pairing_module.c +4 -0
  8. data/assets/same_dir_pairing_module.h +8 -0
  9. data/assets/same_dir_pairing_module_func.h +6 -0
  10. data/assets/same_dir_pairing_other.c +4 -0
  11. data/assets/same_dir_pairing_other.h +8 -0
  12. data/assets/test_example_file_ub_shift_overflow.c +22 -0
  13. data/assets/test_partial_all_module.c +16 -0
  14. data/assets/test_same_dir_pairing.c +23 -0
  15. data/docs/Changelog.md +21 -1
  16. data/docs/mkdocs/configuration/reference/index.md +8 -0
  17. data/docs/mkdocs/configuration/reference/partials.md +38 -0
  18. data/examples/wondrous_forest/src/LightSensor.c +21 -4
  19. data/examples/wondrous_forest/src/LightSensor.h +12 -4
  20. data/examples/wondrous_forest/test/TestLightSensor.c +34 -4
  21. data/lib/ceedling/c_extractor/c_extractor.rb +37 -11
  22. data/lib/ceedling/c_extractor/c_extractor_constants.rb +0 -3
  23. data/lib/ceedling/c_extractor/c_extractor_declarations.rb +26 -25
  24. data/lib/ceedling/c_extractor/c_extractor_functions.rb +5 -12
  25. data/lib/ceedling/config/configurator.rb +1 -0
  26. data/lib/ceedling/config/configurator_setup.rb +26 -0
  27. data/lib/ceedling/defaults.rb +8 -0
  28. data/lib/ceedling/file_path_utils.rb +7 -0
  29. data/lib/ceedling/file_wrapper.rb +8 -0
  30. data/lib/ceedling/generators/generator.rb +15 -0
  31. data/lib/ceedling/generators/generator_helper.rb +25 -6
  32. data/lib/ceedling/generators/generator_partials.rb +84 -3
  33. data/lib/ceedling/generators/generator_test_results_backtrace.rb +183 -83
  34. data/lib/ceedling/includes/includes.rb +66 -11
  35. data/lib/ceedling/objects.yml +5 -0
  36. data/lib/ceedling/partials/partializer.rb +18 -3
  37. data/lib/ceedling/partials/partializer_utils.rb +6 -1
  38. data/lib/ceedling/preprocess/preprocessinator_includes_handler.rb +43 -16
  39. data/lib/ceedling/test_invoker/test_build_executor.rb +19 -8
  40. data/lib/version.rb +1 -1
  41. data/mkdocs.yml +1 -0
  42. data/site-local/404.html +30 -0
  43. data/site-local/configuration/environment-vars.html +30 -0
  44. data/site-local/configuration/global-collections.html +30 -0
  45. data/site-local/configuration/index.html +30 -0
  46. data/site-local/configuration/loading.html +30 -0
  47. data/site-local/configuration/mixins.html +30 -0
  48. data/site-local/configuration/parallel-builds.html +30 -0
  49. data/site-local/configuration/project-file.html +30 -0
  50. data/site-local/configuration/reference/cexception.html +30 -0
  51. data/site-local/configuration/reference/cmock.html +30 -0
  52. data/site-local/configuration/reference/defines.html +30 -0
  53. data/site-local/configuration/reference/environment.html +30 -0
  54. data/site-local/configuration/reference/extension.html +30 -0
  55. data/site-local/configuration/reference/files.html +30 -0
  56. data/site-local/configuration/reference/flags.html +30 -0
  57. data/site-local/configuration/reference/index.html +36 -0
  58. data/site-local/configuration/reference/libraries.html +30 -0
  59. data/site-local/configuration/reference/mixins.html +30 -0
  60. data/site-local/configuration/reference/partials.html +4257 -0
  61. data/site-local/configuration/reference/paths.html +30 -0
  62. data/site-local/configuration/reference/plugins.html +30 -0
  63. data/site-local/configuration/reference/project.html +30 -0
  64. data/site-local/configuration/reference/release-build.html +31 -1
  65. data/site-local/configuration/reference/test-build.html +31 -1
  66. data/site-local/configuration/reference/test-runner.html +30 -0
  67. data/site-local/configuration/reference/tools.html +30 -0
  68. data/site-local/configuration/reference/unity.html +30 -0
  69. data/site-local/configuration/which-ceedling.html +30 -0
  70. data/site-local/development/index.html +30 -0
  71. data/site-local/development/plugins/configuration.html +30 -0
  72. data/site-local/development/plugins/index.html +30 -0
  73. data/site-local/development/plugins/plugin-subclass.html +30 -0
  74. data/site-local/development/plugins/rake-tasks.html +30 -0
  75. data/site-local/development/workflow.html +30 -0
  76. data/site-local/getting-started/command-line.html +30 -0
  77. data/site-local/getting-started/example-projects/cipher-quest.html +30 -0
  78. data/site-local/getting-started/example-projects/index.html +30 -0
  79. data/site-local/getting-started/example-projects/temp-sensor.html +30 -0
  80. data/site-local/getting-started/example-projects/wondrous-forest.html +30 -0
  81. data/site-local/getting-started/index.html +30 -0
  82. data/site-local/getting-started/installation.html +30 -0
  83. data/site-local/getting-started/quick-start.html +30 -0
  84. data/site-local/help.html +30 -0
  85. data/site-local/index.html +30 -0
  86. data/site-local/overview/build-system.html +30 -0
  87. data/site-local/overview/index.html +30 -0
  88. data/site-local/overview/test-environments.html +30 -0
  89. data/site-local/overview/tools-and-frameworks.html +30 -0
  90. data/site-local/plugins/beep.html +30 -0
  91. data/site-local/plugins/bullseye.html +30 -0
  92. data/site-local/plugins/command-hooks.html +30 -0
  93. data/site-local/plugins/compile-commands-json-db.html +30 -0
  94. data/site-local/plugins/cppcheck.html +30 -0
  95. data/site-local/plugins/dependencies.html +30 -0
  96. data/site-local/plugins/fff.html +30 -0
  97. data/site-local/plugins/gcov/examples.html +30 -0
  98. data/site-local/plugins/gcov/gcovr.html +30 -0
  99. data/site-local/plugins/gcov/index.html +30 -0
  100. data/site-local/plugins/gcov/overview.html +30 -0
  101. data/site-local/plugins/gcov/reportgenerator.html +30 -0
  102. data/site-local/plugins/gcov/reporting.html +30 -0
  103. data/site-local/plugins/gcov/setup.html +30 -0
  104. data/site-local/plugins/gcov/tool-versions.html +30 -0
  105. data/site-local/plugins/gcov/troubleshooting.html +30 -0
  106. data/site-local/plugins/index.html +30 -0
  107. data/site-local/plugins/module-generator.html +30 -0
  108. data/site-local/plugins/report-build-warnings-log.html +30 -0
  109. data/site-local/plugins/report-tests-gtestlike-stdout.html +30 -0
  110. data/site-local/plugins/report-tests-ide-stdout.html +30 -0
  111. data/site-local/plugins/report-tests-log-factory.html +30 -0
  112. data/site-local/plugins/report-tests-pretty-stdout.html +30 -0
  113. data/site-local/plugins/report-tests-raw-output-log.html +30 -0
  114. data/site-local/plugins/report-tests-teamcity-stdout.html +30 -0
  115. data/site-local/plugins/valgrind.html +30 -0
  116. data/site-local/project/release-history.html +30 -0
  117. data/site-local/project/upgrade.html +30 -0
  118. data/site-local/reference/build-directives.html +30 -0
  119. data/site-local/reference/command-line.html +30 -0
  120. data/site-local/reference/environment-vars.html +30 -0
  121. data/site-local/reference/gcov-plugin.html +30 -0
  122. data/site-local/reference/global-collections.html +30 -0
  123. data/site-local/reference/index.html +30 -0
  124. data/site-local/reference/partials-macros.html +30 -0
  125. data/site-local/reference/project-configuration.html +30 -0
  126. data/site-local/sitemap.xml.gz +0 -0
  127. data/site-local/snapshot/examples/cipher_quest/index.html +30 -0
  128. data/site-local/snapshot/examples/temp_sensor/index.html +30 -0
  129. data/site-local/snapshot/examples/wondrous_forest/index.html +30 -0
  130. data/site-local/testing-guide/build-directives.html +30 -0
  131. data/site-local/testing-guide/conventions.html +30 -0
  132. data/site-local/testing-guide/frameworks.html +30 -0
  133. data/site-local/testing-guide/index.html +30 -0
  134. data/site-local/testing-guide/partials/configuration.html +30 -0
  135. data/site-local/testing-guide/partials/conventions.html +30 -0
  136. data/site-local/testing-guide/partials/directives.html +30 -0
  137. data/site-local/testing-guide/partials/example.html +30 -0
  138. data/site-local/testing-guide/partials/index.html +30 -0
  139. data/site-local/testing-guide/partials/overview.html +30 -0
  140. data/site-local/testing-guide/partials/variables.html +30 -0
  141. data/site-local/testing-guide/test-cases.html +30 -0
  142. data/site-local/testing-guide/test-sample.html +30 -0
  143. data/site-local/testing-guide/test-suite-anatomy.html +30 -0
  144. data/spec/support/system/spec_system_helper.rb +25 -0
  145. data/spec/system/deployment_as_gem_spec.rb +12 -0
  146. data/spec/system/deployment_as_vendor_spec.rb +17 -0
  147. data/spec/system/encoding_stress_spec.rb +4 -4
  148. data/spec/system/example_wondrous_forest_spec.rb +2 -2
  149. data/spec/system/support/common_test_cases.rb +137 -0
  150. data/spec/units/c_extractor/c_extractor_declarations_spec.rb +27 -4
  151. data/spec/units/c_extractor/c_extractor_functions_spec.rb +1 -11
  152. data/spec/units/c_extractor/c_extractor_integration_spec.rb +18 -11
  153. data/spec/units/c_extractor/c_extractor_spec.rb +57 -1
  154. data/spec/units/config/configurator_setup_spec.rb +61 -0
  155. data/spec/units/file_path_utils_spec.rb +17 -0
  156. data/spec/units/generators/generator_helper_spec.rb +34 -7
  157. data/spec/units/generators/generator_partials_spec.rb +120 -12
  158. data/spec/units/generators/generator_test_results_backtrace_spec.rb +200 -37
  159. data/spec/units/includes/include_spec.rb +30 -18
  160. data/spec/units/includes/includes_spec.rb +100 -10
  161. data/spec/units/partials/partializer_spec.rb +113 -1
  162. data/spec/units/partials/partializer_utils_spec.rb +11 -0
  163. data/spec/units/preprocess/preprocessinator_includes_handler_spec.rb +96 -7
  164. data/spec/units/system_wrapper_spec.rb +72 -0
  165. metadata +19 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8aabde4baeef95fad89e87cf3bd6226ffa3f10df9e54708270c82f237f3efe49
4
- data.tar.gz: '08693e70f80deab8cb70f11677291f368a159df04b35f7a8d9fec8025522063a'
3
+ metadata.gz: d8c20196572fb2d9730237fb04f7ab5d18869180b185e14649d1212669b1fd3f
4
+ data.tar.gz: b363d61a395c3a788fbe4566196d2ce6f6c49e5a8b00423f49c4df3fc2e3f2e1
5
5
  SHA512:
6
- metadata.gz: ab5f32d7896199850b29f6328c9e3fbaea63c0f5bf3dff665434ee0bd488992f971b18afd1bcf194e5c6f2ca66636cd72e38ab26fed3e74904cb374094f9c2b7
7
- data.tar.gz: fab7cf5fe911d2dbc24bdb16add93551bfe8d9b7a668b888735ccfe199d04431707d5e01ec2d5ce345ee518db9b8f34376e16b92788ba1780e2ed20b8a32832c
6
+ metadata.gz: 1c30b50264e5a459a19c0fca20b57fdc1e2e3cc6282b504f5789c2cec47fd9dc11d49cd05c5ecb8e09c47c6e1bb9b7029d74ce7714249abc9e00456ead5d1002
7
+ data.tar.gz: a83eddeb44b9049e361f94ef0280809f157f304c96631ef75ee7341302a34faed50ed4e616d1744e220dccad496872e0c2282b8f7d5e6c4c1e58c5be28fddf32
data/GIT_COMMIT_SHA CHANGED
@@ -1 +1 @@
1
- 049a9d7
1
+ e44173e
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Ceedling ![CI](https://github.com/ThrowTheSwitch/Ceedling/workflows/CI/badge.svg)
2
2
  ========
3
3
 
4
- **Ceedling 1.1.3** is the latest and greatest.
4
+ **Ceedling 1.1.4** is the latest and greatest.
5
5
 
6
6
  See [_Release Notes_][release-notes], [_Changelog_](docs/Changelog.md),
7
7
  [_Breaking Changes_][breaking-changes], and [_Known Issues_][known-issues].
@@ -0,0 +1,14 @@
1
+ # =========================================================================
2
+ # Ceedling - Test-Centered Build System for C
3
+ # ThrowTheSwitch.org
4
+ # Copyright (c) 2010-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
5
+ # SPDX-License-Identifier: MIT
6
+ # =========================================================================
7
+
8
+ # Deliberately ignores the real test executable path it's given and never runs it --
9
+ # simulates a custom :test_fixture wrapper whose own crash-detection machinery (e.g. a
10
+ # sanitizer's halt_on_error) kills the process before Unity ever gets to print its
11
+ # summary. Exists to reproduce issue #1198 without needing a real sanitizer toolchain:
12
+ # a diagnostic backtrace retry left at its default configuration runs the real
13
+ # executable directly instead, unaffected by this fixture, and legitimately passes.
14
+ exit 1
@@ -0,0 +1,11 @@
1
+ #ifndef PARTIAL_ALL_MODULE_H
2
+ #define PARTIAL_ALL_MODULE_H
3
+
4
+ void PartialAllModule_Init(int value);
5
+
6
+ static inline int PartialAllModule_DoubleValue(int value)
7
+ {
8
+ return value * 2;
9
+ }
10
+
11
+ #endif
@@ -0,0 +1,15 @@
1
+ # =========================================================================
2
+ # Ceedling - Test-Centered Build System for C
3
+ # ThrowTheSwitch.org
4
+ # Copyright (c) 2010-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
5
+ # SPDX-License-Identifier: MIT
6
+ # =========================================================================
7
+
8
+ # Enables UBSan's halt-on-error, then execs the real test executable in this script's
9
+ # own place rather than as a child process -- this process's PID becomes the test
10
+ # executable's PID, so the real Process::Status Ceedling observes is the test
11
+ # executable's own. Regression fixture for issue #1198: a diagnostic backtrace retry
12
+ # runs through a separate, unwrapped default tool that never sees this setting, so it
13
+ # can legitimately recover from the same undefined behavior instead of halting on it.
14
+ ENV['UBSAN_OPTIONS'] = 'halt_on_error=1'
15
+ exec(*ARGV)
@@ -0,0 +1,4 @@
1
+ #include "same_dir_pairing_module_func.h"
2
+
3
+ void SameDirPairingModuleInit(void) {
4
+ }
@@ -0,0 +1,8 @@
1
+ #ifndef SAME_DIR_PAIRING_MODULE_H
2
+ #define SAME_DIR_PAIRING_MODULE_H
3
+
4
+ typedef struct {
5
+ int value;
6
+ } same_dir_pairing_module_t;
7
+
8
+ #endif
@@ -0,0 +1,6 @@
1
+ #ifndef SAME_DIR_PAIRING_MODULE_FUNC_H
2
+ #define SAME_DIR_PAIRING_MODULE_FUNC_H
3
+
4
+ void SameDirPairingModuleInit(void);
5
+
6
+ #endif
@@ -0,0 +1,4 @@
1
+ #include "same_dir_pairing_other.h"
2
+
3
+ void SameDirPairingOtherThing(void) {
4
+ }
@@ -0,0 +1,8 @@
1
+ #ifndef SAME_DIR_PAIRING_OTHER_H
2
+ #define SAME_DIR_PAIRING_OTHER_H
3
+
4
+ #include "same_dir_pairing_module.h"
5
+
6
+ void SameDirPairingOtherThing(void);
7
+
8
+ #endif
@@ -0,0 +1,22 @@
1
+ /* =========================================================================
2
+ Ceedling - Test-Centered Build System for C
3
+ ThrowTheSwitch.org
4
+ Copyright (c) 2010-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
5
+ SPDX-License-Identifier: MIT
6
+ ========================================================================= */
7
+
8
+ #include <stdint.h>
9
+
10
+ #include "unity.h"
11
+
12
+ void setUp(void) {}
13
+ void tearDown(void) {}
14
+
15
+ /* Left-shifting a value past its type's bit width is undefined behavior --
16
+ UBSan's -fsanitize=undefined flags it at runtime without a real crash
17
+ occurring at the OS level. */
18
+ void test_shift_overflow(void) {
19
+ volatile uint8_t value = 128;
20
+ volatile uint32_t result = value << 24;
21
+ (void)result;
22
+ }
@@ -0,0 +1,16 @@
1
+ #include "unity.h"
2
+ #include "ceedling.h"
3
+
4
+ #include MOCK_PARTIAL_ALL_MODULE(partial_all_module)
5
+
6
+ void setUp(void) {}
7
+ void tearDown(void) {}
8
+
9
+ void test_all_module_should_mock_both_a_plain_prototype_and_a_static_inline_function(void)
10
+ {
11
+ PartialAllModule_Init_Expect(3);
12
+ PartialAllModule_Init(3);
13
+
14
+ PartialAllModule_DoubleValue_ExpectAndReturn(3, 6);
15
+ TEST_ASSERT_EQUAL_INT(6, PartialAllModule_DoubleValue(3));
16
+ }
@@ -0,0 +1,23 @@
1
+ /* =========================================================================
2
+ Ceedling - Test-Centered Build System for C
3
+ ThrowTheSwitch.org
4
+ Copyright (c) 2010-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
5
+ SPDX-License-Identifier: MIT
6
+ ========================================================================= */
7
+
8
+ // `same_dir_pairing_other.h` transitively includes `same_dir_pairing_module.h` (types
9
+ // only), which shares a filename stem with `same_dir_pairing_module.c` -- the same
10
+ // source file that implements the differently-named header mocked below. Auto
11
+ // source-pairing must not pull that real source file into this build alongside its mock.
12
+
13
+ #include "unity.h"
14
+ #include "mock_same_dir_pairing_module_func.h"
15
+ #include "same_dir_pairing_other.h"
16
+
17
+ void setUp(void) {}
18
+ void tearDown(void) {}
19
+
20
+ void test_SameDirPairingOtherThing_should_not_explode(void) {
21
+ SameDirPairingOtherThing();
22
+ TEST_PASS();
23
+ }
data/docs/Changelog.md CHANGED
@@ -1,4 +1,4 @@
1
- # 🌱 Ceedling Changelog
1
+ p# 🌱 Ceedling Changelog
2
2
 
3
3
  This format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
4
 
@@ -10,6 +10,24 @@ This changelog is complemented by three other documents:
10
10
 
11
11
  ---
12
12
 
13
+ # [1.1.4] — 2026-08-13
14
+
15
+ ## 💪 Fixed
16
+
17
+ - [#1198](https://github.com/ThrowTheSwitch/Ceedling/issues/1198) Fixed a crash that could go unnoticed. If a test crashed but `:use_backtrace`'s diagnostic retry ran cleanly instead of reproducing the crash, Ceedling trusted that clean retry over the real crash and reported the test as passing, with a successful exit code.
18
+ - [#1197](https://github.com/ThrowTheSwitch/Ceedling/issues/1197) Fixed edge case of includes extraction where header files in the same directory as a file being preprocessed were erroneously discovered as depth 0 `#include`s in the preprocessed file. The cause is a quirk of GCC search path defaults. The impact was greatest on certain test file organizations.
19
+
20
+ ### Partials
21
+
22
+ - [#1203](https://github.com/ThrowTheSwitch/Ceedling/issues/1203) Fixed `MOCK_PARTIAL_ALL_MODULE()` (and `MOCK_PARTIAL_PUBLIC_MODULE()`/`MOCK_PARTIAL_PRIVATE_MODULE()`) silently omitting a function from the mock interface in certain cases where no function body could be found in the module.
23
+ - [#1189](https://github.com/ThrowTheSwitch/Ceedling/issues/1189)/[#1187](https://github.com/ThrowTheSwitch/Ceedling/issues/1187) Fixed `const`/`volatile`/`restrict` qualifiers stripped from a Partial's generated `extern` declaration and definition for a promoted variable.
24
+ - Fixed C variable extraction discarding a pointer's own qualifier (e.g. the second `const` in `const uint8_t* const ptr;`) whenever the same qualifier keyword also led the declaration.
25
+ - [#1190](https://github.com/ThrowTheSwitch/Ceedling/issues/1190)/[#1187](https://github.com/ThrowTheSwitch/Ceedling/issues/1187) Fixed a module's typedefs and aggregate (struct/enum/union) definitions being generated into both its Test Partial and Mock Partial headers, causing a redefinition error when a test file uses both for the same module. Such content is now generated once into a shared header with unique include guard that both Partial headers, in turn, include.
26
+ - [#1188](https://github.com/ThrowTheSwitch/Ceedling/issues/1188)/[#1187](https://github.com/ThrowTheSwitch/Ceedling/issues/1187) Fixed a long C declaration silently vanishing from a Partial (and everything textually after it in the same file) once it exceeded an internal, fixed sized buffer length. Refactored to rely on a different dynamically resized buffer with a configurable size ceiling (new `:partials` ↳ `:max_extraction_length`). C feature extraction now raises a clear error if the limit is exceeded.
27
+ - [#1194](https://github.com/ThrowTheSwitch/Ceedling/issues/1194) Fixed generated Partials stripping directory components from system include directives (e.g. `<sys/stat.h>` becoming `<stat.h>`).
28
+
29
+ ---
30
+
13
31
  # [1.1.3] — 2026-08-06
14
32
 
15
33
  ## 💪 Fixed
@@ -18,6 +36,8 @@ This changelog is complemented by three other documents:
18
36
  - Ensure compilation symbols needed for Partials are injected when `:preprocess` defines are configured.
19
37
  - Fixed use of Thor’s Actions#directory to ensure a single options hash.
20
38
 
39
+ ---
40
+
21
41
  # [1.1.2] — 2026-07-27
22
42
 
23
43
  ## 💪 Fixed
@@ -26,6 +26,13 @@ All top-level keys of the Ceedling project configuration file, each on its own p
26
26
 
27
27
  Assembly file support for test suite builds.
28
28
 
29
+ - :material-book-open-variant: **[`:partials` — Partials Settings][ref-partials]**
30
+
31
+ ---
32
+
33
+ Bound how large a single C construct may grow during extraction before
34
+ Partial generation fails outright rather than searching indefinitely.
35
+
29
36
  - :material-book-open-variant: **[`:release_build` — Release Build Settings][ref-release-build]**
30
37
 
31
38
  ---
@@ -150,6 +157,7 @@ All top-level keys of the Ceedling project configuration file, each on its own p
150
157
  [ref-project]: project.md
151
158
  [ref-mixins]: mixins.md
152
159
  [ref-test-build]: test-build.md
160
+ [ref-partials]: partials.md
153
161
  [ref-release-build]: release-build.md
154
162
  [ref-paths]: paths.md
155
163
  [ref-files]: files.md
@@ -0,0 +1,38 @@
1
+ # `:partials`
2
+
3
+ **Configuring C feature extraction for Partials**
4
+
5
+ ## Example `:partials` YAML
6
+
7
+ ```yaml
8
+ :partials:
9
+ # Ceiling of 1000 character blocks for buffer growth
10
+ # 8000 = a max buffer growth to 8,000,000 characters
11
+ :max_extraction_length: 8000
12
+ ```
13
+
14
+ ## `:max_extraction_length`
15
+
16
+ Notes:
17
+ - The default should be sufficient for nearly all test builds. Modification should only be necessary on error.
18
+ - This configuration option is only available in Ceedling 1.1.4+.
19
+
20
+ Building a Partial requires Ceedling to extract each C construct — a
21
+ variable declaration, a function, a macro, and so on — from your source
22
+ files one at a time. Extraction reads a construct into a growing buffer
23
+ until it finds that construct's natural end (a terminating `;`, a closing
24
+ `}`, etc.). This setting bounds how large that buffer may grow before
25
+ extraction fails outright, rather than continuing to search indefinitely
26
+ into whatever else follows in the file.
27
+
28
+ The value is a multiplier of 1000 characters, not a raw character count —
29
+ `8000` means 8,000,000 characters. It must be a whole number no smaller
30
+ than `10` (10,000 characters).
31
+
32
+ Raise this value if Ceedling reports an extraction failure for a
33
+ legitimately large single construct in your codebase — a sizable generated
34
+ lookup table, for instance. There's ordinarily no reason to lower it.
35
+
36
+ **Default**: 5000 (5,000,000 characters)
37
+
38
+ <br/><br/>
@@ -9,8 +9,9 @@
9
9
  #include "LightSensor.h"
10
10
  #include "SensorHal.h"
11
11
 
12
- static uint32 s_lux_value;
13
- static uint32 s_nighttime_threshold_lux;
12
+ static uint32 s_lux_value;
13
+ static uint32 s_nighttime_threshold_lux;
14
+ static LightLevel_t s_light_level;
14
15
 
15
16
  /* Full-scale 4095 counts = 100 000 lux. */
16
17
  PRIVATE uint32 LightSensor__ConvertRawToLux(uint16 raw_counts)
@@ -23,10 +24,20 @@ PRIVATE_INLINE bool LightSensor__IsNighttime(uint32 lux)
23
24
  return lux < s_nighttime_threshold_lux;
24
25
  }
25
26
 
27
+ /* Three-way classification of a lux reading, coarser than the raw value itself
28
+ * and handy for display or logging without exposing the underlying threshold math. */
29
+ PRIVATE LightLevel_t LightSensor__ClassifyLux(uint32 lux)
30
+ {
31
+ if (lux < 50u) { return LIGHT_LEVEL_DARK; }
32
+ if (lux < 5000u) { return LIGHT_LEVEL_DIM; }
33
+ return LIGHT_LEVEL_BRIGHT;
34
+ }
35
+
26
36
  void LightSensor_Init(uint32 nighttime_threshold_lux)
27
37
  {
28
38
  s_lux_value = 0u;
29
39
  s_nighttime_threshold_lux = nighttime_threshold_lux;
40
+ s_light_level = LIGHT_LEVEL_DARK;
30
41
  SensorHal_StartConversion(SENSOR_CHANNEL_LIGHT);
31
42
  }
32
43
 
@@ -34,8 +45,9 @@ bool LightSensor_Sample(void)
34
45
  {
35
46
  if (!SensorHal_IsChannelReady(SENSOR_CHANNEL_LIGHT)) { return false; }
36
47
 
37
- uint16 raw = SensorHal_ReadChannel(SENSOR_CHANNEL_LIGHT);
38
- s_lux_value = LightSensor__ConvertRawToLux(raw);
48
+ uint16 raw = SensorHal_ReadChannel(SENSOR_CHANNEL_LIGHT);
49
+ s_lux_value = LightSensor__ConvertRawToLux(raw);
50
+ s_light_level = LightSensor__ClassifyLux(s_lux_value);
39
51
  SensorHal_StartConversion(SENSOR_CHANNEL_LIGHT);
40
52
  return true;
41
53
  }
@@ -49,3 +61,8 @@ bool LightSensor_IsNighttime(void)
49
61
  {
50
62
  return LightSensor__IsNighttime(s_lux_value);
51
63
  }
64
+
65
+ LightLevel_t LightSensor_GetLightLevel(void)
66
+ {
67
+ return s_light_level;
68
+ }
@@ -10,9 +10,17 @@
10
10
 
11
11
  #include "Types.h"
12
12
 
13
- void LightSensor_Init(uint32 nighttime_threshold_lux);
14
- bool LightSensor_Sample(void);
15
- uint32 LightSensor_GetLux(void);
16
- bool LightSensor_IsNighttime(void);
13
+ typedef enum
14
+ {
15
+ LIGHT_LEVEL_DARK = 0,
16
+ LIGHT_LEVEL_DIM = 1,
17
+ LIGHT_LEVEL_BRIGHT = 2
18
+ } LightLevel_t;
19
+
20
+ void LightSensor_Init(uint32 nighttime_threshold_lux);
21
+ bool LightSensor_Sample(void);
22
+ uint32 LightSensor_GetLux(void);
23
+ bool LightSensor_IsNighttime(void);
24
+ LightLevel_t LightSensor_GetLightLevel(void);
17
25
 
18
26
  #endif /* LIGHT_SENSOR_H */
@@ -6,10 +6,13 @@
6
6
  ========================================================================= */
7
7
 
8
8
  /* Partials pattern: TEST_PARTIAL_PUBLIC_MODULE + MOCK_PARTIAL_PRIVATE_MODULE
9
- * Tests the public interface (LightSensor_Sample, GetLux, IsNighttime)
10
- * while mocking the private helpers LightSensor__ConvertRawToLux() and
11
- * LightSensor__IsNighttime(). SensorHal is mocked traditionally.
12
- * This demonstrates testing public behavior while isolating private logic. */
9
+ * Tests the public interface (LightSensor_Sample, GetLux, IsNighttime,
10
+ * GetLightLevel) while mocking the private helpers LightSensor__ConvertRawToLux(),
11
+ * LightSensor__IsNighttime(), and LightSensor__ClassifyLux(). SensorHal is mocked
12
+ * traditionally. This demonstrates testing public behavior while isolating private
13
+ * logic. LightSensor.h's LightLevel_t enum is needed by both a tested public
14
+ * function's return type and a mocked private function's return type, so this
15
+ * module also exercises a type shared between the generated test and mock headers. */
13
16
 
14
17
  #include "unity.h"
15
18
  #include "ceedling.h"
@@ -48,6 +51,7 @@ void test_Sample_CallsConvertHelperAndStoresResult(void)
48
51
  SensorHal_IsChannelReady_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, true);
49
52
  SensorHal_ReadChannel_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, 2000u);
50
53
  LightSensor__ConvertRawToLux_ExpectAndReturn(2000u, 48840u);
54
+ LightSensor__ClassifyLux_ExpectAndReturn(48840u, LIGHT_LEVEL_BRIGHT);
51
55
  SensorHal_StartConversion_Expect(SENSOR_CHANNEL_LIGHT);
52
56
 
53
57
  TEST_ASSERT_TRUE(LightSensor_Sample());
@@ -59,6 +63,7 @@ void test_IsNighttime_ReturnsTrueWhenPrivateHelperReturnsTrue(void)
59
63
  SensorHal_IsChannelReady_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, true);
60
64
  SensorHal_ReadChannel_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, 10u);
61
65
  LightSensor__ConvertRawToLux_ExpectAndReturn(10u, 244u);
66
+ LightSensor__ClassifyLux_ExpectAndReturn(244u, LIGHT_LEVEL_DIM);
62
67
  SensorHal_StartConversion_Expect(SENSOR_CHANNEL_LIGHT);
63
68
  LightSensor_Sample();
64
69
 
@@ -71,9 +76,34 @@ void test_IsNighttime_ReturnsFalseWhenPrivateHelperReturnsFalse(void)
71
76
  SensorHal_IsChannelReady_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, true);
72
77
  SensorHal_ReadChannel_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, 3000u);
73
78
  LightSensor__ConvertRawToLux_ExpectAndReturn(3000u, 73260u);
79
+ LightSensor__ClassifyLux_ExpectAndReturn(73260u, LIGHT_LEVEL_BRIGHT);
74
80
  SensorHal_StartConversion_Expect(SENSOR_CHANNEL_LIGHT);
75
81
  LightSensor_Sample();
76
82
 
77
83
  LightSensor__IsNighttime_ExpectAndReturn(73260u, false);
78
84
  TEST_ASSERT_FALSE(LightSensor_IsNighttime());
79
85
  }
86
+
87
+ void test_Sample_ClassifiesLuxAsDark(void)
88
+ {
89
+ SensorHal_IsChannelReady_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, true);
90
+ SensorHal_ReadChannel_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, 1u);
91
+ LightSensor__ConvertRawToLux_ExpectAndReturn(1u, 20u);
92
+ LightSensor__ClassifyLux_ExpectAndReturn(20u, LIGHT_LEVEL_DARK);
93
+ SensorHal_StartConversion_Expect(SENSOR_CHANNEL_LIGHT);
94
+
95
+ TEST_ASSERT_TRUE(LightSensor_Sample());
96
+ TEST_ASSERT_EQUAL(LIGHT_LEVEL_DARK, LightSensor_GetLightLevel());
97
+ }
98
+
99
+ void test_Sample_ClassifiesLuxAsBright(void)
100
+ {
101
+ SensorHal_IsChannelReady_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, true);
102
+ SensorHal_ReadChannel_ExpectAndReturn(SENSOR_CHANNEL_LIGHT, 4000u);
103
+ LightSensor__ConvertRawToLux_ExpectAndReturn(4000u, 97680u);
104
+ LightSensor__ClassifyLux_ExpectAndReturn(97680u, LIGHT_LEVEL_BRIGHT);
105
+ SensorHal_StartConversion_Expect(SENSOR_CHANNEL_LIGHT);
106
+
107
+ TEST_ASSERT_TRUE(LightSensor_Sample());
108
+ TEST_ASSERT_EQUAL(LIGHT_LEVEL_BRIGHT, LightSensor_GetLightLevel());
109
+ }
@@ -18,7 +18,7 @@ class CExtractor
18
18
  include CExtractorConstants
19
19
  include CExtractorTypes
20
20
 
21
- constructor :c_extractor_code_text, :c_extractor_functions, :c_extractor_declarations, :c_extractor_preprocessing, :c_extractor_definitions
21
+ constructor :c_extractor_code_text, :c_extractor_functions, :c_extractor_declarations, :c_extractor_preprocessing, :c_extractor_definitions, :configurator, :loginator
22
22
 
23
23
  attr_writer :chunk_size, :max_buffer_length
24
24
 
@@ -31,7 +31,7 @@ class CExtractor
31
31
  @definitions = @c_extractor_definitions
32
32
 
33
33
  @chunk_size = DEFAULT_CHUNK_SIZE
34
- @max_buffer_length = DEFAULT_MAX_FUNCTION_LENGTH
34
+ @max_buffer_length = default_max_buffer_length
35
35
  end
36
36
 
37
37
  # Extract C module contents from a source file on disk.
@@ -58,26 +58,36 @@ class CExtractor
58
58
  # Parameters:
59
59
  # content: String containing C source code to extract from
60
60
  # chunk_size: (Optional) Size of chunks to read at a time (default: 16 KB)
61
- # max_buffer_length: (Optional) Maximum allowed function size (default: 5 MB)
62
- # max_line_length: (Optional) Maximum allowed line length (default: 1000 chars)
61
+ # max_buffer_length: (Optional) Maximum allowed feature size in characters. Defaults to
62
+ # whatever setup() already established (project configuration if
63
+ # available, otherwise the built-in default) rather than a literal
64
+ # value here, so an explicit-override-free call doesn't clobber that.
63
65
  #
64
66
  # Returns: CModule struct containing all features extracted.
65
67
  def from_string(
66
68
  content:,
67
69
  chunk_size: DEFAULT_CHUNK_SIZE,
68
- max_buffer_length: DEFAULT_MAX_FUNCTION_LENGTH,
69
- max_line_length: DEFAULT_MAX_LINE_LENGTH
70
+ max_buffer_length: nil
70
71
  )
71
72
  @chunk_size = chunk_size
72
- @max_buffer_length = max_buffer_length
73
- @functions.max_line_length = max_line_length
74
- @declarations.max_line_length = max_line_length
73
+ @max_buffer_length = max_buffer_length unless max_buffer_length.nil?
75
74
 
76
75
  return extract_contents( StringIO.new( content ), nil )
77
76
  end
78
77
 
79
78
  private
80
79
 
80
+ # `:configurator` is absent for direct/test construction of this class (only Ceedling's
81
+ # DI container supplies it in production), so this falls back to the built-in default in
82
+ # that case rather than requiring every caller to know about project configuration.
83
+ # The configured value is a small integer multiplier of 1000 characters (project-file
84
+ # ergonomics -- `5000` reads more clearly than `5000000`), so it's scaled up here to the
85
+ # actual character count this class works in internally.
86
+ def default_max_buffer_length()
87
+ return DEFAULT_MAX_FUNCTION_LENGTH unless @configurator.respond_to?(:partials_max_extraction_length)
88
+ return @configurator.partials_max_extraction_length * 1000
89
+ end
90
+
81
91
  # Extracts all C code features from the given IO source.
82
92
  #
83
93
  # Parameters:
@@ -276,9 +286,25 @@ class CExtractor
276
286
  # Expand the buffer with the new chunk
277
287
  buffer << chunk
278
288
 
279
- # Safety check -- don't let buffer grow indefinitely
289
+ # Safety check -- don't let buffer grow indefinitely. This is the single ceiling for every
290
+ # feature type (directives, typedefs, functions, variable declarations, etc.) -- individual
291
+ # extractors don't enforce their own separate, smaller limits, since any of them scanning
292
+ # to the end of an ever-growing buffer without finding a terminator is exactly this same
293
+ # condition and belongs to this one check.
294
+ #
295
+ # Which of the several extractors tried at this file position is active when this fires
296
+ # isn't reported: extract_contents tries each one in a fixed order at every position, and
297
+ # an extractor that rejects content outright (e.g. text not starting with '#' for a
298
+ # directive) rejects it the same way regardless of how much more the buffer grows, so the
299
+ # first extractor in that fixed order is always the one still running when the buffer
300
+ # finally crosses this ceiling -- naming it here would misattribute the failure to it
301
+ # rather than to whatever construct actually caused the overrun.
280
302
  if buffer.length > max_length
281
- raise CeedlingException.new("Feature extraction exceeded maximum length of #{max_length} characters")
303
+ @loginator.log(
304
+ "Extraction starting at file position #{chunk_start_pos} exceeded maximum length of #{max_length} characters",
305
+ Verbosity::DEBUG
306
+ ) if @loginator
307
+ raise CeedlingException.new("Extraction exceeded maximum length of #{max_length} characters, starting at file position #{chunk_start_pos}")
282
308
  end
283
309
 
284
310
  # Create a new scanner for the current buffer
@@ -6,9 +6,6 @@
6
6
  # =========================================================================
7
7
 
8
8
  module CExtractorConstants
9
- # 1000 character safety limit
10
- DEFAULT_MAX_LINE_LENGTH = 1000
11
-
12
9
  # 16 KB -- enough for most functions
13
10
  DEFAULT_CHUNK_SIZE = (16 * 1024)
14
11
 
@@ -16,12 +16,9 @@ class CExtractorDeclarations
16
16
 
17
17
  constructor :c_extractor_code_text
18
18
 
19
- attr_writer :max_line_length
20
-
21
19
  def setup()
22
20
  # Aliases
23
- @code_text = @c_extractor_code_text
24
- @max_line_length = DEFAULT_MAX_LINE_LENGTH
21
+ @code_text = @c_extractor_code_text
25
22
  end
26
23
 
27
24
  # Attempts to extract a complete variable declaration from the scanner
@@ -58,11 +55,14 @@ class CExtractorDeclarations
58
55
  # On failure: Resets scanner position to starting position
59
56
  #
60
57
  # Safety:
61
- # Enforces max_line_length limit to prevent infinite loops on malformed input
58
+ # A declaration with no terminating semicolon runs the scan to the end of
59
+ # whatever buffer the caller (CExtractor#extract_next_feature) has grown so
60
+ # far; that caller is the one place enforcing an overall length ceiling,
61
+ # since only it knows how much more of the file remains to try growing into.
62
62
  def try_extract_variable(scanner)
63
63
  start_pos = scanner.pos
64
64
 
65
- # Tracks paren, bracket, and brace depth simultaneously with inline string state machine and max_line_length guard — not suitable for collect_balanced()
65
+ # Tracks paren, bracket, and brace depth simultaneously with an inline string state machine — not suitable for collect_balanced()
66
66
  paren_depth = 0
67
67
  bracket_depth = 0
68
68
  brace_depth = 0
@@ -74,12 +74,6 @@ class CExtractorDeclarations
74
74
  until scanner.eos?
75
75
  char = scanner.peek(1)
76
76
 
77
- # Safety check -- prevent infinite loops on malformed input
78
- if (scanner.pos - start_pos) > @max_line_length
79
- scanner.pos = start_pos
80
- return [false, nil]
81
- end
82
-
83
77
  # Handle string literals
84
78
  if in_string
85
79
  if char == '\\'
@@ -302,8 +296,8 @@ class CExtractorDeclarations
302
296
  #
303
297
  # Returns: CVariableDeclaration
304
298
  def parse_declaration(individual_text, original_text)
305
- decorators = extract_decorators(individual_text)
306
- clean_text = strip_decorators(individual_text, decorators)
299
+ decorators, remaining = extract_decorators(individual_text)
300
+ clean_text = normalize_declaration_whitespace(remaining)
307
301
  # Strip compiler extensions for name/type/array_suffix extraction only;
308
302
  # clean_text (stored as .text) retains attributes for correct compilation.
309
303
  extraction_text = @code_text.strip_compiler_extensions(clean_text)
@@ -321,9 +315,17 @@ class CExtractorDeclarations
321
315
  )
322
316
  end
323
317
 
324
- # Scan leading whole-word tokens against DECORATOR_KEYWORDS
318
+ # Storage-class specifiers and base-type qualifiers precede a C declaration's type as a
319
+ # contiguous run of keywords -- `static`, `extern`, and a `const`/`volatile` that qualifies
320
+ # the type itself all appear here (e.g. `static const int MAX;`). A qualifier bound to a
321
+ # pointer level instead, such as the second `const` in `char * const p;`, sits after the
322
+ # type and its `*` tokens rather than in this leading run, so it is grammatically part of
323
+ # the declarator, not a decorator. Peeling keywords off one at a time from the front, and
324
+ # stopping at the first non-keyword token, naturally separates the two: the same keyword
325
+ # (e.g. `const`) can appear once here and again later in the declarator without the two
326
+ # occurrences being confused with each other, since only the leading run is ever consumed.
325
327
  #
326
- # Returns: Array<String> ordered decorator keywords found at start of text
328
+ # Returns: [Array<String> ordered decorator keywords found at start of text, String remaining text after that run]
327
329
  def extract_decorators(text)
328
330
  decorators = []
329
331
  remaining = text.strip
@@ -339,18 +341,17 @@ class CExtractorDeclarations
339
341
  end
340
342
  break unless matched
341
343
  end
342
- decorators
344
+ [decorators, remaining]
343
345
  end
344
346
 
345
- # Remove decorator keywords from text and normalize whitespace
347
+ # A declaration with its leading decorator run already removed (see extract_decorators)
348
+ # still carries whatever whitespace and line breaks appeared in the source between its
349
+ # remaining tokens. This collapses that whitespace to single spaces and guarantees a
350
+ # trailing semicolon, so `.text` is stable, single-line C ready to compile.
346
351
  #
347
- # Returns: String with decorators removed, whitespace normalized, semicolon retained
348
- def strip_decorators(text, decorators)
349
- result = text.dup
350
- decorators.each do |kw|
351
- result.gsub!(/\b#{Regexp.escape(kw)}\b\s*/, '')
352
- end
353
- # Normalize whitespace but preserve semicolon
352
+ # Returns: String with whitespace normalized, semicolon retained
353
+ def normalize_declaration_whitespace(remaining)
354
+ result = remaining.dup
354
355
  result.gsub!(/\r\n|\r|\n|\t/, ' ')
355
356
  result.gsub!(/\s+/, ' ')
356
357
  result.strip!