ceedling 1.1.5 → 1.1.7
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.
- checksums.yaml +4 -4
- data/GIT_COMMIT_SHA +1 -1
- data/Gemfile +4 -0
- data/Gemfile.lock +2 -0
- data/README.md +4 -1
- data/assets/tests_with_conditional_includes/src/feature_config.h +13 -0
- data/assets/tests_with_conditional_includes/src/feature_extra.h +13 -0
- data/assets/tests_with_conditional_includes/src/local_flag_extra.h +13 -0
- data/assets/tests_with_conditional_includes/src/nested_extra.h +13 -0
- data/assets/tests_with_conditional_includes/src/nested_wrapper.h +16 -0
- data/assets/tests_with_conditional_includes/src/project_flag_extra.h +13 -0
- data/assets/tests_with_conditional_includes/src/widget.c +48 -0
- data/assets/tests_with_conditional_includes/src/widget.h +15 -0
- data/assets/tests_with_conditional_includes/src/widget_feature.c +29 -0
- data/assets/tests_with_conditional_includes/src/widget_feature.h +13 -0
- data/assets/tests_with_conditional_includes/test/test_widget.c +44 -0
- data/assets/tests_with_conditional_includes/test/test_widget_feature.c +31 -0
- data/docs/Changelog.md +31 -1
- data/docs/KnownIssues.md +1 -0
- data/docs/mkdocs/configuration/project-file.md +25 -7
- data/docs/mkdocs/configuration/reference/cexception.md +1 -1
- data/docs/mkdocs/configuration/reference/cmock.md +1 -1
- data/docs/mkdocs/configuration/reference/unity.md +1 -1
- data/docs/mkdocs/getting-started/quick-start.md +11 -8
- data/docs/mkdocs/plugins/gcov/gcovr.md +324 -189
- data/docs/mkdocs/plugins/gcov/reportgenerator.md +113 -31
- data/docs/mkdocs/reference/gcov-plugin.md +21 -3
- data/docs/mkdocs/snapshot/plugins/gcov/config/defaults.yml +0 -1
- data/examples/wondrous_forest/src/SensorHal.h +13 -0
- data/examples/wondrous_forest/src/TemperatureSensor.c +12 -5
- data/examples/wondrous_forest/src/TemperatureSensor.h +5 -4
- data/examples/wondrous_forest/test/TestTemperatureSensor.c +32 -3
- data/lib/ceedling/generators/generator_test_results_backtrace.rb +16 -8
- data/lib/ceedling/generators/generator_test_runner.rb +25 -1
- data/lib/ceedling/partials/partializer.rb +8 -1
- data/lib/ceedling/plugins/plugin_reportinator.rb +9 -0
- data/lib/ceedling/plugins/report_tests_stdout_plugin.rb +1 -1
- data/lib/ceedling/preprocess/preprocessinator.rb +22 -0
- data/lib/ceedling/preprocess/preprocessinator_includes_handler.rb +33 -0
- data/lib/version.rb +1 -1
- data/plugins/gcov/config/defaults.yml +0 -1
- data/plugins/gcov/lib/gcov.rb +35 -16
- data/plugins/gcov/lib/gcovr_reportinator.rb +31 -1
- data/plugins/valgrind/lib/valgrind.rb +1 -1
- data/site-local/configuration/project-file.html +78 -8
- data/site-local/configuration/reference/cexception.html +5 -5
- data/site-local/configuration/reference/cmock.html +5 -5
- data/site-local/configuration/reference/unity.html +5 -5
- data/site-local/getting-started/quick-start.html +13 -9
- data/site-local/plugins/gcov/gcovr.html +1215 -255
- data/site-local/plugins/gcov/reportgenerator.html +404 -46
- data/site-local/reference/gcov-plugin.html +40 -7
- data/site-local/sitemap.xml.gz +0 -0
- data/site-local/snapshot/plugins/gcov/config/defaults.yml +0 -1
- data/spec/support/system/spec_system_helper.rb +11 -0
- data/spec/support/system/system_context.rb +25 -12
- data/spec/system/conditional_include_macro_visibility_spec.rb +152 -0
- data/spec/system/deployment_as_gem_spec.rb +2 -0
- data/spec/system/deployment_as_vendor_spec.rb +2 -0
- data/spec/system/encoding_stress_spec.rb +4 -4
- data/spec/system/example_wondrous_forest_spec.rb +2 -2
- data/spec/system/gcov_deployment_spec.rb +2 -0
- data/spec/system/support/common_test_cases.rb +47 -1
- data/spec/system/support/gcov_common_test_cases.rb +52 -0
- data/spec/system/test_runner_system_include_spec.rb +90 -0
- data/spec/units/generators/generator_test_results_backtrace_spec.rb +51 -0
- data/spec/units/generators/generator_test_runner_spec.rb +69 -0
- data/spec/units/partials/partializer_spec.rb +69 -0
- data/spec/units/plugin_reportinator_spec.rb +38 -0
- data/spec/units/preprocess/preprocessinator_includes_handler_spec.rb +61 -0
- data/spec/units/preprocess/preprocessinator_spec.rb +136 -0
- data/vendor/c_exception/lib/CException.h +1 -1
- data/vendor/c_exception/project.yml +2 -2
- data/vendor/c_exception/test/TestException.c +1 -1
- data/vendor/c_exception/test/support/CExceptionConfig.h +5 -11
- data/vendor/cmock/docs/CMockChangeLog.md +23 -22
- data/vendor/cmock/scripts/create_makefile.rb +4 -3
- data/vendor/cmock/src/cmock.h +1 -1
- data/vendor/cmock/vendor/c_exception/lib/CException.h +1 -1
- data/vendor/cmock/vendor/c_exception/project.yml +2 -2
- data/vendor/cmock/vendor/c_exception/test/TestException.c +1 -1
- data/vendor/cmock/vendor/c_exception/test/support/CExceptionConfig.h +5 -11
- data/vendor/cmock/vendor/unity/auto/generate_test_runner.rb +85 -29
- data/vendor/cmock/vendor/unity/docs/UnityChangeLog.md +1 -0
- data/vendor/cmock/vendor/unity/examples/unity_config.h +8 -0
- data/vendor/cmock/vendor/unity/src/unity.c +9 -1
- data/vendor/cmock/vendor/unity/src/unity.h +1 -1
- data/vendor/cmock/vendor/unity/test/rakefile +2 -1
- data/vendor/cmock/vendor/unity/test/testdata/testRunnerGeneratorEmpty.c +13 -0
- data/vendor/cmock/vendor/unity/test/tests/test_generate_test_runner.rb +31 -0
- data/vendor/unity/auto/generate_test_runner.rb +63 -57
- data/vendor/unity/docs/UnityChangeLog.md +1 -0
- data/vendor/unity/examples/unity_config.h +8 -0
- data/vendor/unity/src/unity.c +9 -1
- data/vendor/unity/src/unity.h +1 -1
- data/vendor/unity/test/rakefile +2 -1
- data/vendor/unity/test/tests/test_generate_test_runner.rb +20 -0
- metadata +23 -3
- data/vendor/cmock/vendor/unity/auto/run_test.erb +0 -37
|
@@ -4,55 +4,137 @@ The `ReportGenerator` utility may be configured with the following configuration
|
|
|
4
4
|
|
|
5
5
|
All generated reports are found in `<build root>/artifacts/gcov/ReportGenerator/`.
|
|
6
6
|
|
|
7
|
+
## Example configuration
|
|
8
|
+
|
|
7
9
|
```yaml
|
|
8
10
|
:gcov:
|
|
9
11
|
:report_generator:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
:
|
|
12
|
+
:history_directory: build/artifacts/gcov/history
|
|
13
|
+
:file_filters: "-./vendor/*;-./build/*;-./test/*;+./src/*"
|
|
14
|
+
:verbosity: Warning
|
|
15
|
+
:tag: "release-1.4.0"
|
|
16
|
+
:num_parallel_threads: 4
|
|
17
|
+
:gcov_exclude:
|
|
18
|
+
- some_excluded_file
|
|
19
|
+
:custom_args:
|
|
20
|
+
- "-title:MyProject"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Plugin configuration
|
|
24
|
+
|
|
25
|
+
### `:history_directory`
|
|
26
|
+
|
|
27
|
+
Optional directory for storing persistent coverage information. Can be used
|
|
28
|
+
in future reports to show coverage evolution.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
### `:plugins`
|
|
33
|
+
|
|
34
|
+
Optional plugin files for custom reports or custom history storage (separated
|
|
35
|
+
by semicolon).
|
|
36
|
+
|
|
37
|
+
**Example:** `plugin.dll;*.dll`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### `:assembly_filters`
|
|
42
|
+
|
|
43
|
+
Optional list of assemblies that should be included or excluded in the
|
|
44
|
+
report (separated by semicolon). Exclusion filters take precedence over
|
|
45
|
+
inclusion filters. Wildcards are allowed, but not regular expressions.
|
|
46
|
+
|
|
47
|
+
**Example:** `+<included>;-<excluded>`
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### `:class_filters`
|
|
52
|
+
|
|
53
|
+
Optional list of classes that should be included or excluded in the report
|
|
54
|
+
(separated by semicolon). Exclusion filters take precedence over inclusion
|
|
55
|
+
filters. Wildcards are allowed, but not regular expressions.
|
|
56
|
+
|
|
57
|
+
**Example:** `+<included>;-<excluded>`
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
### `:file_filters`
|
|
62
|
+
|
|
63
|
+
Optional list of files that should be included or excluded in the report
|
|
64
|
+
(separated by semicolon). Exclusion filters take precedence over inclusion
|
|
65
|
+
filters. Wildcards are allowed, but not regular expressions. Ceedling places
|
|
66
|
+
your own patterns first, ahead of the exclusions it generates automatically
|
|
67
|
+
for test paths, the build root, and (when Partials are in use) Partial
|
|
68
|
+
source files, so your patterns take precedence.
|
|
13
69
|
|
|
14
|
-
|
|
15
|
-
:plugins: <plugin.dll>;<*.dll>
|
|
70
|
+
**Example:** `"-./vendor/*;-./build/*;-./test/*;-./lib/*;+./src/*"`
|
|
16
71
|
|
|
17
|
-
|
|
18
|
-
# Exclusion filters take precedence over inclusion filters.
|
|
19
|
-
# Wildcards are allowed, but not regular expressions.
|
|
20
|
-
:assembly_filters: +<included>;-<excluded>
|
|
72
|
+
---
|
|
21
73
|
|
|
22
|
-
|
|
23
|
-
# Exclusion filters take precedence over inclusion filters.
|
|
24
|
-
# Wildcards are allowed, but not regular expressions.
|
|
25
|
-
:class_filters: +<included>;-<excluded>
|
|
74
|
+
### `:verbosity`
|
|
26
75
|
|
|
27
|
-
|
|
28
|
-
# Exclusion filters take precedence over inclusion filters.
|
|
29
|
-
# Wildcards are allowed, but not regular expressions.
|
|
30
|
-
# Example: "-./vendor/*;-./build/*;-./test/*;-./lib/*;+./src/*"
|
|
31
|
-
:file_filters: +<included>;-<excluded>
|
|
76
|
+
The verbosity level of the log messages.
|
|
32
77
|
|
|
33
|
-
|
|
34
|
-
# Values: Verbose, Info, Warning, Error, Off (defaults to Warning)
|
|
35
|
-
:verbosity: <level>
|
|
78
|
+
**Values:** `Verbose`, `Info`, `Warning`, `Error`, `Off`
|
|
36
79
|
|
|
37
|
-
|
|
38
|
-
:tag: <tag>
|
|
80
|
+
**Default:** `Warning`
|
|
39
81
|
|
|
40
|
-
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### `:tag`
|
|
85
|
+
|
|
86
|
+
Optional tag or build version.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### `:gcov_exclude`
|
|
91
|
+
|
|
92
|
+
Optional list of one or more regular expressions to exclude gcov notes
|
|
93
|
+
(`.gcno`) files that match these filters from coverage processing — these
|
|
94
|
+
files are never run through `gcov` at all. A trailing `.gcov` or `.gcno`
|
|
95
|
+
suffix on a pattern is stripped automatically, so either form works.
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
:gcov:
|
|
99
|
+
:report_generator:
|
|
41
100
|
:gcov_exclude:
|
|
42
101
|
- <regex>
|
|
43
102
|
- ...
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Default:** `[]`
|
|
44
106
|
|
|
45
|
-
|
|
46
|
-
:threads: <count>
|
|
107
|
+
---
|
|
47
108
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
109
|
+
### `:num_parallel_threads`
|
|
110
|
+
|
|
111
|
+
Optionally set the number of threads ReportGenerator uses in parallel. Drives
|
|
112
|
+
both of ReportGenerator's own `numberOfReportsParsedInParallel` and
|
|
113
|
+
`numberOfReportsMergedInParallel` settings together.
|
|
114
|
+
|
|
115
|
+
**Default:** unset (ReportGenerator's own default applies)
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### `:custom_args`
|
|
120
|
+
|
|
121
|
+
Optional list of one or more command line arguments to pass to Report
|
|
122
|
+
Generator. Useful for configuring Risk Hotspots and other settings not
|
|
123
|
+
covered by the options above. See the
|
|
124
|
+
[ReportGenerator settings wiki](https://github.com/danielpalme/ReportGenerator/wiki/Settings).
|
|
125
|
+
|
|
126
|
+
Note: This can be accomplished with Ceedling's tool configuration options
|
|
127
|
+
outside of plugin configuration but is supported here to collect
|
|
128
|
+
configuration options in one place.
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
:gcov:
|
|
132
|
+
:report_generator:
|
|
53
133
|
:custom_args:
|
|
54
134
|
- <argument>
|
|
55
135
|
- ...
|
|
56
136
|
```
|
|
57
137
|
|
|
138
|
+
**Default:** `[]`
|
|
139
|
+
|
|
58
140
|
<br/><br/>
|
|
@@ -213,8 +213,24 @@ Exit with status 4 if total branch coverage is below this percentage.
|
|
|
213
213
|
Exit with status 8 if total decision coverage is below this percentage.
|
|
214
214
|
(`gcovr --fail-under-decision`)
|
|
215
215
|
|
|
216
|
+
`gcovr` treats `--fail-under-decision` as a no-op without `--decisions` also
|
|
217
|
+
present — setting this option implies `:decisions` (below) automatically.
|
|
218
|
+
|
|
216
219
|
**Values:** `1`–`100`
|
|
217
220
|
|
|
221
|
+
**Requires:** `gcovr` 7.0 or higher
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
### `:decisions`
|
|
226
|
+
|
|
227
|
+
Report the decision coverage. For HTML, JSON, and the summary report.
|
|
228
|
+
(`gcovr --decisions`)
|
|
229
|
+
|
|
230
|
+
Implied automatically whenever `:fail_under_decision` is set.
|
|
231
|
+
|
|
232
|
+
**Requires:** `gcovr` 6.0 or higher
|
|
233
|
+
|
|
218
234
|
---
|
|
219
235
|
|
|
220
236
|
### `:fail_under_function`
|
|
@@ -552,11 +568,13 @@ are excluded from report generation.
|
|
|
552
568
|
|
|
553
569
|
---
|
|
554
570
|
|
|
555
|
-
### `:
|
|
571
|
+
### `:num_parallel_threads`
|
|
556
572
|
|
|
557
|
-
Number of parallel threads to use during report generation.
|
|
573
|
+
Number of parallel threads to use during report generation. Drives both
|
|
574
|
+
ReportGenerator's own `numberOfReportsParsedInParallel` and
|
|
575
|
+
`numberOfReportsMergedInParallel` settings together.
|
|
558
576
|
|
|
559
|
-
**Default:**
|
|
577
|
+
**Default:** unset (ReportGenerator's own default applies)
|
|
560
578
|
|
|
561
579
|
---
|
|
562
580
|
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
|
|
28
28
|
:report_generator:
|
|
29
29
|
:verbosity: Warning # Default verbosity
|
|
30
|
-
:collection_paths_source: [] # Explicitly defined as default empty array to simplify option validation code
|
|
31
30
|
:custom_args: [] # Explicitly defined as default empty array to simplify option validation code
|
|
32
31
|
:gcov_exclude: [] # Explicitly defined as default empty array to simplify option validation code
|
|
33
32
|
...
|
|
@@ -16,4 +16,17 @@ bool SensorHal_IsChannelReady(SensorChannel_t channel);
|
|
|
16
16
|
void SensorHal_StartConversion(SensorChannel_t channel);
|
|
17
17
|
uint32 SensorHal_GetTimestampMs(void);
|
|
18
18
|
|
|
19
|
+
/* Vendor-header-style static inline register accessor -- the same pattern that
|
|
20
|
+
* makes a real hardware header need Partial mocking instead of ordinary mocking,
|
|
21
|
+
* since there is no separate .c file to exclude from a test build and swap for a
|
|
22
|
+
* mock's .o at link time. The real body here stands in for what would otherwise
|
|
23
|
+
* be a direct, unsafe-off-target memory-mapped register read: it always returns
|
|
24
|
+
* the same obviously-wrong sentinel, so a test can tell whether this real body
|
|
25
|
+
* ran (Partial mocking failed to intercept the call) instead of its mock. */
|
|
26
|
+
static inline uint16 SensorHal_RawStatusRegister(SensorChannel_t channel)
|
|
27
|
+
{
|
|
28
|
+
(void)channel;
|
|
29
|
+
return 0xDEADu;
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
#endif /* SENSOR_HAL_H */
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
#include "TemperatureSensor.h"
|
|
10
10
|
#include "SensorHal.h"
|
|
11
11
|
|
|
12
|
-
static float
|
|
13
|
-
static int32
|
|
14
|
-
static bool
|
|
12
|
+
static float s_calibration_offset;
|
|
13
|
+
static int32 s_last_milli_celsius;
|
|
14
|
+
static bool s_reading_valid;
|
|
15
|
+
static uint16 s_last_status_register;
|
|
15
16
|
|
|
16
17
|
/* Linearized approximation: full-scale 4095 counts maps 0 C to 85 C. */
|
|
17
18
|
static int32 TemperatureSensor__RawToMilliCelsius(uint16 raw_counts)
|
|
@@ -45,8 +46,9 @@ bool TemperatureSensor_Sample(void)
|
|
|
45
46
|
|
|
46
47
|
if (!SensorHal_IsChannelReady(SENSOR_CHANNEL_TEMP)) { return false; }
|
|
47
48
|
|
|
48
|
-
raw
|
|
49
|
-
|
|
49
|
+
raw = SensorHal_ReadChannel(SENSOR_CHANNEL_TEMP);
|
|
50
|
+
s_last_status_register = SensorHal_RawStatusRegister(SENSOR_CHANNEL_TEMP);
|
|
51
|
+
milli_c = TemperatureSensor__RawToMilliCelsius(raw);
|
|
50
52
|
milli_c += (int32)(s_calibration_offset * 1000.0f);
|
|
51
53
|
|
|
52
54
|
s_reading_valid = TemperatureSensor__IsInRange(milli_c);
|
|
@@ -65,3 +67,8 @@ bool TemperatureSensor_IsValid(void)
|
|
|
65
67
|
{
|
|
66
68
|
return s_reading_valid;
|
|
67
69
|
}
|
|
70
|
+
|
|
71
|
+
uint16 TemperatureSensor_GetStatusRegister(void)
|
|
72
|
+
{
|
|
73
|
+
return s_last_status_register;
|
|
74
|
+
}
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
#include "Types.h"
|
|
12
12
|
|
|
13
|
-
void
|
|
14
|
-
bool
|
|
15
|
-
int32
|
|
16
|
-
bool
|
|
13
|
+
void TemperatureSensor_Init(float calibration_offset_celsius);
|
|
14
|
+
bool TemperatureSensor_Sample(void);
|
|
15
|
+
int32 TemperatureSensor_GetMilliCelsius(void);
|
|
16
|
+
bool TemperatureSensor_IsValid(void);
|
|
17
|
+
uint16 TemperatureSensor_GetStatusRegister(void);
|
|
17
18
|
|
|
18
19
|
#endif /* TEMPERATURE_SENSOR_H */
|
|
@@ -5,17 +5,25 @@
|
|
|
5
5
|
SPDX-License-Identifier: MIT
|
|
6
6
|
========================================================================= */
|
|
7
7
|
|
|
8
|
-
/* Partials pattern: TEST_PARTIAL_ALL_MODULE
|
|
8
|
+
/* Partials pattern: TEST_PARTIAL_ALL_MODULE + MOCK_PARTIAL_ALL_MODULE
|
|
9
9
|
* Tests both public functions AND the private static helpers
|
|
10
10
|
* TemperatureSensor__RawToMilliCelsius() and TemperatureSensor__IsInRange().
|
|
11
11
|
* Also accesses the file-scoped static s_calibration_offset directly.
|
|
12
|
-
* SensorHal is mocked
|
|
12
|
+
* SensorHal is mocked via Partials (MOCK_PARTIAL_ALL_MODULE) rather than
|
|
13
|
+
* traditionally: SensorHal_RawStatusRegister() is a static inline function,
|
|
14
|
+
* which only Partial mocking (not ordinary CMock header mocking) can
|
|
15
|
+
* intercept -- there is no separate SensorHal.c definition for a static
|
|
16
|
+
* inline function to exclude from this test build and replace with a mock
|
|
17
|
+
* .o at link time, so the call must be redirected to the mock before that,
|
|
18
|
+
* at the #include level. Every existing SensorHal_*_Expect* call below
|
|
19
|
+
* keeps working unchanged either way, since Partial-mocked functions use
|
|
20
|
+
* the identical CMock expectation API as a traditionally mocked module. */
|
|
13
21
|
|
|
14
22
|
#include "unity.h"
|
|
15
23
|
#include "ceedling.h"
|
|
16
|
-
#include "MockSensorHal.h"
|
|
17
24
|
|
|
18
25
|
#include TEST_PARTIAL_ALL_MODULE(TemperatureSensor)
|
|
26
|
+
#include MOCK_PARTIAL_ALL_MODULE(SensorHal)
|
|
19
27
|
|
|
20
28
|
#include "Types.h"
|
|
21
29
|
|
|
@@ -78,6 +86,7 @@ void test_Sample_ReturnsTrueAndStoresReadingWhenReady(void)
|
|
|
78
86
|
/* 1638 counts: (1638 * 85000) / 4095 ~= 34000 milli-C (34 C), in range */
|
|
79
87
|
SensorHal_IsChannelReady_ExpectAndReturn(SENSOR_CHANNEL_TEMP, true);
|
|
80
88
|
SensorHal_ReadChannel_ExpectAndReturn(SENSOR_CHANNEL_TEMP, 1638u);
|
|
89
|
+
SensorHal_RawStatusRegister_ExpectAndReturn(SENSOR_CHANNEL_TEMP, 0x1234u);
|
|
81
90
|
SensorHal_StartConversion_Expect(SENSOR_CHANNEL_TEMP);
|
|
82
91
|
|
|
83
92
|
TEST_ASSERT_TRUE(TemperatureSensor_Sample());
|
|
@@ -93,8 +102,28 @@ void test_CalibrationOffsetShiftsReading(void)
|
|
|
93
102
|
/* 2048 counts ~= 42502 milli-C; with +1.0 C offset -> ~= 43502 */
|
|
94
103
|
SensorHal_IsChannelReady_ExpectAndReturn(SENSOR_CHANNEL_TEMP, true);
|
|
95
104
|
SensorHal_ReadChannel_ExpectAndReturn(SENSOR_CHANNEL_TEMP, 2048u);
|
|
105
|
+
SensorHal_RawStatusRegister_ExpectAndReturn(SENSOR_CHANNEL_TEMP, 0x1234u);
|
|
96
106
|
SensorHal_StartConversion_Expect(SENSOR_CHANNEL_TEMP);
|
|
97
107
|
|
|
98
108
|
TemperatureSensor_Sample();
|
|
99
109
|
TEST_ASSERT_INT32_WITHIN(200, 43502, TemperatureSensor_GetMilliCelsius());
|
|
100
110
|
}
|
|
111
|
+
|
|
112
|
+
/* Regression test for #1215: a module partial-mocked via MOCK_PARTIAL_ALL_MODULE
|
|
113
|
+
* (as SensorHal is above) must have its calling module's real #include swapped for
|
|
114
|
+
* the generated mock interface header. Without that swap, SensorHal_RawStatusRegister()'s
|
|
115
|
+
* real static inline body -- unreachable through ordinary link-time mock substitution,
|
|
116
|
+
* since a static inline function has no separate object file to exclude -- compiles
|
|
117
|
+
* straight into this test build and always returns its 0xDEAD sentinel regardless of
|
|
118
|
+
* what's expected here, no matter what the mock is told to return. */
|
|
119
|
+
void test_StatusRegisterReflectsMockedValueNotRealSentinel(void)
|
|
120
|
+
{
|
|
121
|
+
SensorHal_IsChannelReady_ExpectAndReturn(SENSOR_CHANNEL_TEMP, true);
|
|
122
|
+
SensorHal_ReadChannel_ExpectAndReturn(SENSOR_CHANNEL_TEMP, 1638u);
|
|
123
|
+
SensorHal_RawStatusRegister_ExpectAndReturn(SENSOR_CHANNEL_TEMP, 0x1234u);
|
|
124
|
+
SensorHal_StartConversion_Expect(SENSOR_CHANNEL_TEMP);
|
|
125
|
+
|
|
126
|
+
TemperatureSensor_Sample();
|
|
127
|
+
|
|
128
|
+
TEST_ASSERT_EQUAL_HEX16(0x1234u, TemperatureSensor_GetStatusRegister());
|
|
129
|
+
}
|
|
@@ -66,13 +66,17 @@ class GeneratorTestResultsBacktrace
|
|
|
66
66
|
# Attribute each group member its own real result line, if Unity printed one
|
|
67
67
|
group.each do |test_case|
|
|
68
68
|
case crash_result[:output]
|
|
69
|
-
# Success test case
|
|
70
|
-
|
|
69
|
+
# Success test case -- tolerates a trailing duration suffix (e.g. `PASS (12 ms)`,
|
|
70
|
+
# UNITY_INCLUDE_EXEC_TIME), matching the real format generator_test_results.rb's
|
|
71
|
+
# own parser already recognizes for it.
|
|
72
|
+
when /(^#{Regexp.escape(filename)}:\d+:#{Regexp.escape(test_case[:test])}:PASS(\s\(.*ms\))?\s*$)/
|
|
71
73
|
group_results[:passed] += 1
|
|
72
74
|
group_results[:output] << $1
|
|
73
75
|
|
|
74
|
-
# Ignored test case
|
|
75
|
-
|
|
76
|
+
# Ignored test case -- tolerates a trailing message (TEST_IGNORE_MESSAGE), same as
|
|
77
|
+
# FAIL below. Before this fix, a message-carrying ignore fell through to "unresolved"
|
|
78
|
+
# and was misreported as crash evidence -- IGNORE was only recognized bare.
|
|
79
|
+
when /(^#{Regexp.escape(filename)}:\d+:#{Regexp.escape(test_case[:test])}:IGNORE(:.+)?\s*$)/
|
|
76
80
|
group_results[:ignored] += 1
|
|
77
81
|
group_results[:output] << $1
|
|
78
82
|
|
|
@@ -260,13 +264,17 @@ class GeneratorTestResultsBacktrace
|
|
|
260
264
|
# Attribute each group member its own real result line, if Unity printed one
|
|
261
265
|
group.each do |test_case|
|
|
262
266
|
case crash_result[:output]
|
|
263
|
-
# Success test case
|
|
264
|
-
|
|
267
|
+
# Success test case -- tolerates a trailing duration suffix (e.g. `PASS (12 ms)`,
|
|
268
|
+
# UNITY_INCLUDE_EXEC_TIME), matching the real format generator_test_results.rb's
|
|
269
|
+
# own parser already recognizes for it.
|
|
270
|
+
when /(^#{Regexp.escape(filename)}:\d+:#{Regexp.escape(test_case[:test])}:PASS(\s\(.*ms\))?\s*$)/
|
|
265
271
|
group_results[:passed] += 1
|
|
266
272
|
group_results[:output] << $1
|
|
267
273
|
|
|
268
|
-
# Ignored test case
|
|
269
|
-
|
|
274
|
+
# Ignored test case -- tolerates a trailing message (TEST_IGNORE_MESSAGE), same as
|
|
275
|
+
# FAIL below. Before this fix, a message-carrying ignore fell through to "unresolved"
|
|
276
|
+
# and was misreported as crash evidence -- IGNORE was only recognized bare.
|
|
277
|
+
when /(^#{Regexp.escape(filename)}:\d+:#{Regexp.escape(test_case[:test])}:IGNORE(:.+)?\s*$)/
|
|
270
278
|
group_results[:ignored] += 1
|
|
271
279
|
group_results[:output] << $1
|
|
272
280
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
require 'generate_test_runner' # Unity's test runner generator
|
|
9
9
|
require 'ceedling/parsing_parcels'
|
|
10
|
+
require 'ceedling/includes/includes'
|
|
10
11
|
|
|
11
12
|
class GeneratorTestRunner
|
|
12
13
|
|
|
@@ -38,7 +39,30 @@ class GeneratorTestRunner
|
|
|
38
39
|
@test_cases_internal,
|
|
39
40
|
# Small hack for mock subdirectory support until include paths fully supported
|
|
40
41
|
mocks.map{ |include| include.filepath },
|
|
41
|
-
|
|
42
|
+
# Unity's own generator emits a string verbatim if it contains '<' and otherwise
|
|
43
|
+
# wraps it in double quotes -- each entry here must therefore already be in its
|
|
44
|
+
# final, exact form.
|
|
45
|
+
#
|
|
46
|
+
# System includes only: use the full, bracketed spelling (include_path, a
|
|
47
|
+
# reconciled SystemInclude's original as-written directive text -- e.g.
|
|
48
|
+
# "sys/stat.h" -- when set, else the directory-preserving filepath). A bare
|
|
49
|
+
# filename here drops both the directory component and the '<>' delimiters a
|
|
50
|
+
# system header's own search path depends on (issue #1236).
|
|
51
|
+
#
|
|
52
|
+
# User includes: bare filename, same as always. Unlike mocks (whose subdirectory
|
|
53
|
+
# is a real, dedicated build/test/mocks/<test>/ path -- hence their own
|
|
54
|
+
# directory-preserving filepath usage above) or a system header (whose directory
|
|
55
|
+
# is meaningful to the system include search path), a project's own directories
|
|
56
|
+
# are exposed to the compiler as a flat list of -I search paths, not nested to
|
|
57
|
+
# match whatever directory component a captured UserInclude's filepath happens to
|
|
58
|
+
# carry -- rendering the full path here breaks resolution instead of fixing it.
|
|
59
|
+
includes.map do |include|
|
|
60
|
+
if include.is_a?(SystemInclude)
|
|
61
|
+
"<#{include.include_path || include.filepath}>"
|
|
62
|
+
else
|
|
63
|
+
include.filename
|
|
64
|
+
end
|
|
65
|
+
end
|
|
42
66
|
)
|
|
43
67
|
end
|
|
44
68
|
|
|
@@ -125,8 +125,15 @@ class Partializer
|
|
|
125
125
|
|
|
126
126
|
partials.each do |_module, config|
|
|
127
127
|
# Remap mockable interface headers that will be injected into generated partial implementation
|
|
128
|
+
#
|
|
129
|
+
# Any real (non-nil) mock mode means this module has a generated mock interface header
|
|
130
|
+
# to redirect to -- PUBLIC/PRIVATE alone once covered every mode that existed, but DEDUCT
|
|
131
|
+
# (MOCK_PARTIAL_ALL_MODULE) and ACCUMULATE (MOCK_PARTIAL_MODULE) were added later without
|
|
132
|
+
# updating this check, so a module mocked via either of those was silently never
|
|
133
|
+
# redirected: its real header (and any static inline/static function bodies in it) stayed
|
|
134
|
+
# #include'd verbatim, compiling straight past the mock instead of being replaced by it.
|
|
128
135
|
if includes.any? { |include| include.filename.ext().downcase() == _module.downcase() }
|
|
129
|
-
if
|
|
136
|
+
if !config.mocks.type.nil?
|
|
130
137
|
# Insert mockable interface header from remapping of module name
|
|
131
138
|
_includes << UserInclude.new(
|
|
132
139
|
@file_path_utils.form_partial_interface_header_filename(_module)
|
|
@@ -95,6 +95,15 @@ class PluginReportinator
|
|
|
95
95
|
return aggregated_results
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
# A build's own test results -- pass or fail -- are core information a user
|
|
99
|
+
# silencing routine build chatter still wants to see; ERRORS is the floor
|
|
100
|
+
# for both, not just for a failing run. Centralized here so every plugin
|
|
101
|
+
# printing post-build test results (report_tests_stdout_plugin, gcov,
|
|
102
|
+
# valgrind) agrees on the same answer instead of each hardcoding its own.
|
|
103
|
+
def test_results_floor_verbosity
|
|
104
|
+
Verbosity::ERRORS
|
|
105
|
+
end
|
|
106
|
+
|
|
98
107
|
def run_test_results_report(hash, verbosity=Verbosity::NORMAL)
|
|
99
108
|
if @test_results_template.nil?
|
|
100
109
|
raise CeedlingException.new( "No test results report template has been set." )
|
|
@@ -50,7 +50,7 @@ class ReportTestsStdoutPlugin < Plugin
|
|
|
50
50
|
|
|
51
51
|
results = @plugin_reportinator.assemble_test_results( @result_list )
|
|
52
52
|
hash = { :context => TEST_SYM, :results => results }
|
|
53
|
-
verbosity =
|
|
53
|
+
verbosity = @plugin_reportinator.test_results_floor_verbosity
|
|
54
54
|
|
|
55
55
|
# Print unit test suite results
|
|
56
56
|
@plugin_reportinator.run_test_results_report( hash, verbosity )
|
|
@@ -567,6 +567,28 @@ class Preprocessinator
|
|
|
567
567
|
defines: defines
|
|
568
568
|
)
|
|
569
569
|
|
|
570
|
+
# Supplement with a literal text scan of the original file's own #include
|
|
571
|
+
# lines -- the gcc-based bare pass above runs against an isolated copy that
|
|
572
|
+
# can never open another header, so a conditional #include whose guard
|
|
573
|
+
# depends on a macro defined by an *earlier #include in this same file*
|
|
574
|
+
# evaluates false there and silently drops out. Unioning in this text-based
|
|
575
|
+
# pass's result only ever adds candidates for Includes.reconcile below to
|
|
576
|
+
# match against the accurate directives-only pass -- it can't introduce a
|
|
577
|
+
# spurious entry on its own, since reconcile still requires the accurate
|
|
578
|
+
# pass to also report it.
|
|
579
|
+
#
|
|
580
|
+
# This supplements the gcc-based pass rather than replacing it: gcc can
|
|
581
|
+
# resolve an #include whose target is itself a macro (e.g. the
|
|
582
|
+
# MOCK_PARTIAL_ALL_MODULE()-style directives this project's own generated
|
|
583
|
+
# test files use), since a command-line -D define is visible even to the
|
|
584
|
+
# isolated copy -- a literal text scan has no filename there to find at
|
|
585
|
+
# all, since none exists until a real preprocessor expands the macro. The
|
|
586
|
+
# two passes catch different, non-overlapping failure modes; keeping both
|
|
587
|
+
# covers both.
|
|
588
|
+
bare_includes = (
|
|
589
|
+
bare_includes + @includes_handler.extract_bare_includes_from_text( filepath: filepath )
|
|
590
|
+
).uniq( &:filename )
|
|
591
|
+
|
|
570
592
|
# Extract user includes
|
|
571
593
|
user_includes = preprocess_user_includes(
|
|
572
594
|
name: test,
|
|
@@ -115,6 +115,39 @@ class PreprocessinatorIncludesHandler
|
|
|
115
115
|
return includes
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
+
# Scan the original file's own text for every #include line, unconditionally --
|
|
119
|
+
# no #if/#ifdef tracking at all, just literal presence. Supplements the gcc-based
|
|
120
|
+
# bare pass (`extract_bare_includes`), which runs against an isolated, sibling-free
|
|
121
|
+
# copy of the file and so can never open another header to resolve a conditional
|
|
122
|
+
# that depends on a macro that header defines (e.g. `#if SOME_MACRO_FROM_ANOTHER_HEADER`)
|
|
123
|
+
# -- GCC treats the macro as undefined there and silently drops the #include line
|
|
124
|
+
# from that pass's output even though it's a perfectly ordinary, real, top-level
|
|
125
|
+
# #include once actually evaluated with the real file in place. This method's result
|
|
126
|
+
# is meant to be unioned with the gcc-based bare pass's own result (see
|
|
127
|
+
# Preprocessinator#preprocess_file_includes_common), not used on its own -- an
|
|
128
|
+
# `Includes.reconcile` call downstream still only keeps an entry here if the
|
|
129
|
+
# accurate directives-only pass also reports it, so unconditionally capturing every
|
|
130
|
+
# literal #include line (regardless of whether its own guard is really true) is
|
|
131
|
+
# safe: it can only ever let back in an entry the accurate pass already confirmed,
|
|
132
|
+
# never introduce a spurious one on its own. A supplement, not a replacement --
|
|
133
|
+
# the gcc pass can still do something this literal scan structurally can't: resolve
|
|
134
|
+
# an #include whose own target is a macro rather than a literal filename.
|
|
135
|
+
def extract_bare_includes_from_text(filepath:)
|
|
136
|
+
includes = []
|
|
137
|
+
|
|
138
|
+
# Open in binary mode: code_lines applies clean_encoding per-line, but each_line
|
|
139
|
+
# itself can raise on invalid byte sequences before clean_encoding is reached.
|
|
140
|
+
@file_wrapper.open(filepath, 'rb') do |input|
|
|
141
|
+
@parsing_parcels.code_lines( input ) do |line|
|
|
142
|
+
_include = @include_factory.user_include_from_directive( line ) ||
|
|
143
|
+
@include_factory.system_include_from_directive( line )
|
|
144
|
+
includes << Include.new( _include.filepath ) if !_include.nil?
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
return clean_self_reference( filepath, includes )
|
|
149
|
+
end
|
|
150
|
+
|
|
118
151
|
def extract_user_includes_preprocess(name:, filepath:, preprocessed_filepath:)
|
|
119
152
|
includes = []
|
|
120
153
|
|
data/lib/version.rb
CHANGED
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
|
|
28
28
|
:report_generator:
|
|
29
29
|
:verbosity: Warning # Default verbosity
|
|
30
|
-
:collection_paths_source: [] # Explicitly defined as default empty array to simplify option validation code
|
|
31
30
|
:custom_args: [] # Explicitly defined as default empty array to simplify option validation code
|
|
32
31
|
:gcov_exclude: [] # Explicitly defined as default empty array to simplify option validation code
|
|
33
32
|
...
|
data/plugins/gcov/lib/gcov.rb
CHANGED
|
@@ -40,11 +40,19 @@ class Gcov < Plugin
|
|
|
40
40
|
)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
# Validate
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
# #1252 -- Validate `:gcov ↳ :utilities` config (cheap, no external tool needed) and
|
|
44
|
+
# build the console summary Reportinator (needs no external tool of its own) here,
|
|
45
|
+
# eagerly, since `setup()` runs for every build this plugin is merely *enabled* for,
|
|
46
|
+
# not only real `gcov:` builds. Deliberately NOT building the gcovr/ReportGenerator
|
|
47
|
+
# Reportinators here -- doing so validates gcovr/ReportGenerator are installed
|
|
48
|
+
# (see their own constructors), which would make either a hard dependency of any
|
|
49
|
+
# build at all (e.g. plain `test:all`) rather than only a real `gcov:` build. See
|
|
50
|
+
# generate_coverage_reports, which builds (and so validates) them lazily, only once
|
|
51
|
+
# post_build already knows a gcov: task actually ran.
|
|
52
|
+
validate_utilities_config( @project_config[:gcov_utilities] )
|
|
53
|
+
@console_reportinator = summaries_enabled?( @project_config ) ?
|
|
54
|
+
ConsoleReportinator.new( @ceedling, @project_config ) : nil
|
|
55
|
+
@reportinators = nil
|
|
48
56
|
|
|
49
57
|
# Convenient instance variable references
|
|
50
58
|
@configurator = @ceedling[:configurator]
|
|
@@ -214,7 +222,7 @@ class Gcov < Plugin
|
|
|
214
222
|
results: results
|
|
215
223
|
}
|
|
216
224
|
|
|
217
|
-
verbosity =
|
|
225
|
+
verbosity = @plugin_reportinator.test_results_floor_verbosity
|
|
218
226
|
|
|
219
227
|
# Print unit test suite results
|
|
220
228
|
@plugin_reportinator.run_test_results_report( hash, verbosity )
|
|
@@ -257,6 +265,15 @@ class Gcov < Plugin
|
|
|
257
265
|
def generate_coverage_reports()
|
|
258
266
|
return if not @reports_enabled
|
|
259
267
|
|
|
268
|
+
# #1252 -- Lazily build (and so validate the external tools of) the gcovr/
|
|
269
|
+
# ReportGenerator Reportinators only now: this method only runs from post_build
|
|
270
|
+
# (automatic reporting) or the standalone `gcov:report` task (manual reporting,
|
|
271
|
+
# mutually exclusive with automatic per :gcov_report_task) -- either way, only
|
|
272
|
+
# once a real gcov: task is confirmed to have already run. See setup()'s own
|
|
273
|
+
# comment for why this can't happen any earlier. `||=` just guards against ever
|
|
274
|
+
# rebuilding (and so re-validating) on a hypothetical repeat call.
|
|
275
|
+
@reportinators ||= build_reportinators( @project_config[:gcov_utilities] )
|
|
276
|
+
|
|
260
277
|
@reportinators.each do |reportinator|
|
|
261
278
|
# Create the artifacts output directory.
|
|
262
279
|
@file_wrapper.mkdir( reportinator.artifacts_path ) if reportinator.artifacts_path
|
|
@@ -312,16 +329,10 @@ class Gcov < Plugin
|
|
|
312
329
|
return sources - tested_sources
|
|
313
330
|
end
|
|
314
331
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
@console_reportinator = summaries_enabled?(@project_config) ?
|
|
320
|
-
ConsoleReportinator.new(@ceedling, @project_config) : nil
|
|
321
|
-
|
|
322
|
-
# Do not instantiate file reportinators (and tool validation) unless reports enabled
|
|
323
|
-
return reportinators if (!enabled)
|
|
324
|
-
|
|
332
|
+
# Fail fast at plugin setup if :utilities holds an unrecognized name (e.g. a typo) --
|
|
333
|
+
# cheap, config-shape-only validation, so this stays eager even though the actual
|
|
334
|
+
# Reportinators it names are built lazily (see build_reportinators, generate_coverage_reports).
|
|
335
|
+
def validate_utilities_config(config)
|
|
325
336
|
config.each do |reportinator|
|
|
326
337
|
if not GCOV_UTILITY_NAMES.map(&:upcase).include?( reportinator.upcase )
|
|
327
338
|
options = GCOV_UTILITY_NAMES.map{ |utility| "'#{utility}'" }.join(', ')
|
|
@@ -329,6 +340,14 @@ class Gcov < Plugin
|
|
|
329
340
|
raise CeedlingException.new(msg)
|
|
330
341
|
end
|
|
331
342
|
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# #1252 -- Deliberately not called from setup(); see its own comment and
|
|
346
|
+
# generate_coverage_reports, the only caller. Constructing GcovrReportinator/
|
|
347
|
+
# ReportGeneratorReportinator validates gcovr/ReportGenerator are installed, so this
|
|
348
|
+
# can only run once a real gcov: task is confirmed to have run.
|
|
349
|
+
def build_reportinators(config)
|
|
350
|
+
reportinators = []
|
|
332
351
|
|
|
333
352
|
# Run reports using gcovr
|
|
334
353
|
if utility_enabled?( config, GCOV_UTILITY_NAME_GCOVR )
|