Branch data Line data Source code
1 : : #include "sute.h"
2 : :
3 : : static const TraversalSummary *statistics_summary = NULL;
4 : :
5 : : /**
6 : : * @brief Print the selected traversal summary through the output capture API
7 : : */
8 : 9 : static void capture_statistics(void)
9 : : {
10 : 9 : show_statistics(statistics_summary);
11 : 9 : }
12 : :
13 : : /**
14 : : * @brief Compare one statistics report with its complete expected output
15 : : *
16 : : * The supplied configuration and counters are used only for this capture.
17 : : * Shared configuration, logger mode, and callback state are restored before
18 : : * returning, including when capture or comparison fails
19 : : *
20 : : * @param statistics_config Per-case configuration with its runtime start set for capture
21 : : * @param summary Fully initialized counters for the report
22 : : * @param template_path File containing the expected complete output
23 : : * @return SUCCESS when stdout matches the template and stderr is empty
24 : : */
25 : 9 : static Return check_statistics_output(
26 : : Config *statistics_config,
27 : : const TraversalSummary *summary,
28 : : const char *template_path)
29 : : {
30 : : /* Status returned by this function through deliver()
31 : : Default value assumes successful completion */
32 : 9 : Return status = SUCCESS;
33 : :
34 : : /* Save the shared configuration, logger mode, and capture callback state */
35 : 9 : Config *initial_config = config;
36 : 9 : const LOGMODES initial_logger_mode = atomic_load_explicit(&rational_logger_mode,memory_order_relaxed);
37 : 9 : const TraversalSummary *initial_summary = statistics_summary;
38 : 9 : m_create(char,captured_stdout,MEMORY_STRING);
39 : 9 : m_create(char,captured_stderr,MEMORY_STRING);
40 : 9 : m_create(char,pattern,MEMORY_STRING);
41 : :
42 : : /* Enable the report without traversing or reading files */
43 : 9 : statistics_config->app_start_time_ns = cur_time_monotonic_ns();
44 : 9 : config = statistics_config;
45 : 9 : rational_logger_mode = REGULAR;
46 : 9 : statistics_summary = summary;
47 : :
48 : : /* Capture one report and check both output streams */
49 : 9 : ASSERT(SUCCESS == function_capture(capture_statistics,captured_stdout,captured_stderr));
50 : 9 : ASSERT(captured_stderr->length == 0U);
51 : 9 : ASSERT(SUCCESS == get_file_content(template_path,pattern));
52 : 9 : ASSERT(SUCCESS == match_pattern(captured_stdout,pattern,template_path));
53 : :
54 : : /* Restore shared state and release buffers even after an assertion fails */
55 : 9 : config = initial_config;
56 : 9 : rational_logger_mode = initial_logger_mode;
57 : 9 : statistics_summary = initial_summary;
58 : 9 : call(m_del(pattern));
59 : 9 : call(m_del(captured_stderr));
60 : 9 : call(m_del(captured_stdout));
61 : :
62 : 9 : deliver(status);
63 : : }
64 : :
65 : : /**
66 : : * @brief Verify that scan and hashing rates use their respective intervals
67 : : * @return Return status for the complete output check
68 : : */
69 : 1 : static Return test0043_1(void)
70 : : {
71 : 1 : INITTEST;
72 : :
73 : : /* One MiB over two seconds gives 512 KiB/s; hashing over half a second
74 : : gives 2 MiB/s, so the two rates must use their respective intervals */
75 : 1 : Config statistics_config = {0};
76 : 1 : const TraversalSummary summary = {
77 : : .total_hashed_bytes = 1048576U,
78 : : .at_least_one_file_was_shown = true,
79 : : .total_hashing_elapsed_ns = 500000000LL,
80 : : .scan_elapsed_ns = 2000000000LL
81 : : };
82 : :
83 : 1 : ASSERT(SUCCESS == check_statistics_output(&statistics_config,&summary,"templates/0043_001.txt"));
84 : :
85 : 1 : RETURN_STATUS;
86 : : }
87 : :
88 : : /**
89 : : * @brief Verify unavailable rates when no bytes were hashed
90 : : * @return Return status for the complete output check
91 : : */
92 : 1 : static Return test0043_2(void)
93 : : {
94 : 1 : INITTEST;
95 : :
96 : : /* No hashed bytes means both rates are unavailable despite positive times */
97 : 1 : Config statistics_config = {0};
98 : 1 : const TraversalSummary summary = {
99 : : .total_hashed_bytes = 0U,
100 : : .at_least_one_file_was_shown = true,
101 : : .total_hashing_elapsed_ns = 500000000LL,
102 : : .scan_elapsed_ns = 2000000000LL
103 : : };
104 : :
105 : 1 : ASSERT(SUCCESS == check_statistics_output(&statistics_config,&summary,"templates/0043_002.txt"));
106 : :
107 : 1 : RETURN_STATUS;
108 : : }
109 : :
110 : : /**
111 : : * @brief Verify unavailable rates for zero measurement intervals
112 : : * @return Return status for the complete output check
113 : : */
114 : 1 : static Return test0043_3(void)
115 : : {
116 : 1 : INITTEST;
117 : :
118 : : /* Positive bytes with zero intervals must not produce a division result */
119 : 1 : Config statistics_config = {0};
120 : 1 : const TraversalSummary summary = {
121 : : .total_hashed_bytes = 1048576U,
122 : : .at_least_one_file_was_shown = true,
123 : : .total_hashing_elapsed_ns = 0LL,
124 : : .scan_elapsed_ns = 0LL
125 : : };
126 : :
127 : 1 : ASSERT(SUCCESS == check_statistics_output(&statistics_config,&summary,"templates/0043_003.txt"));
128 : :
129 : 1 : RETURN_STATUS;
130 : : }
131 : :
132 : : /**
133 : : * @brief Verify that negative intervals display zero time and unavailable rates
134 : : * @return Return status for the complete output check
135 : : */
136 : 1 : static Return test0043_4(void)
137 : : {
138 : 1 : INITTEST;
139 : :
140 : : /* Negative intervals produce unavailable rates and a zero time display */
141 : 1 : Config statistics_config = {0};
142 : 1 : const TraversalSummary summary = {
143 : : .total_hashed_bytes = 1048576U,
144 : : .at_least_one_file_was_shown = true,
145 : : .total_hashing_elapsed_ns = -1LL,
146 : : .scan_elapsed_ns = -1LL
147 : : };
148 : :
149 : 1 : ASSERT(SUCCESS == check_statistics_output(&statistics_config,&summary,"templates/0043_003.txt"));
150 : :
151 : 1 : RETURN_STATUS;
152 : : }
153 : :
154 : : /**
155 : : * @brief Verify the wording for positive rates below one byte per second
156 : : * @return Return status for the complete output check
157 : : */
158 : 1 : static Return test0043_5(void)
159 : : {
160 : 1 : INITTEST;
161 : :
162 : : /* A positive rate below one byte per second has its own explicit wording */
163 : 1 : Config statistics_config = {0};
164 : 1 : const TraversalSummary summary = {
165 : : .total_hashed_bytes = 1U,
166 : : .at_least_one_file_was_shown = true,
167 : : .total_hashing_elapsed_ns = 3000000000LL,
168 : : .scan_elapsed_ns = 2000000000LL
169 : : };
170 : :
171 : 1 : ASSERT(SUCCESS == check_statistics_output(&statistics_config,&summary,"templates/0043_004.txt"));
172 : :
173 : 1 : RETURN_STATUS;
174 : : }
175 : :
176 : : /**
177 : : * @brief Verify that a rate of 1.5 bytes per second is displayed as 1B/s
178 : : * @return Return status for the complete output check
179 : : */
180 : 1 : static Return test0043_6(void)
181 : : {
182 : 1 : INITTEST;
183 : :
184 : : /* Fractional rates above one byte per second are truncated, not rounded */
185 : 1 : Config statistics_config = {0};
186 : 1 : const TraversalSummary summary = {
187 : : .total_hashed_bytes = 3U,
188 : : .at_least_one_file_was_shown = true,
189 : : .total_hashing_elapsed_ns = 2000000000LL,
190 : : .scan_elapsed_ns = 2000000000LL
191 : : };
192 : :
193 : 1 : ASSERT(SUCCESS == check_statistics_output(&statistics_config,&summary,"templates/0043_005.txt"));
194 : :
195 : 1 : RETURN_STATUS;
196 : : }
197 : :
198 : : /**
199 : : * @brief Verify saturation before converting an oversized rate to size_t
200 : : * @return Return status for the complete output check
201 : : */
202 : 1 : static Return test0043_7(void)
203 : : {
204 : 1 : INITTEST;
205 : :
206 : : /* A one-nanosecond interval makes the rate exceed SIZE_MAX. Both rates
207 : : must saturate at the largest representable byte count before conversion */
208 : 1 : Config statistics_config = {0};
209 : 1 : const TraversalSummary summary = {
210 : : .total_hashed_bytes = SIZE_MAX,
211 : : .at_least_one_file_was_shown = true,
212 : : .total_hashing_elapsed_ns = 1LL,
213 : : .scan_elapsed_ns = 1LL
214 : : };
215 : :
216 : 1 : ASSERT(SUCCESS == check_statistics_output(&statistics_config,&summary,"templates/0043_006.txt"));
217 : :
218 : 1 : RETURN_STATUS;
219 : : }
220 : :
221 : : /**
222 : : * @brief Verify that ordinary dry-run reports no hashed data or rates
223 : : * @return Return status for the complete output check
224 : : */
225 : 1 : static Return test0043_8(void)
226 : : {
227 : 1 : INITTEST;
228 : :
229 : : /* Ordinary dry-run suppresses hashed data and rates even if counters exist */
230 : 1 : Config statistics_config = {
231 : : .dry_run = true,
232 : : .dry_run_with_checksums = false
233 : : };
234 : 1 : const TraversalSummary summary = {
235 : : .total_hashed_bytes = 1048576U,
236 : : .at_least_one_file_was_shown = true,
237 : : .total_hashing_elapsed_ns = 500000000LL,
238 : : .scan_elapsed_ns = 2000000000LL
239 : : };
240 : :
241 : 1 : ASSERT(SUCCESS == check_statistics_output(&statistics_config,&summary,"templates/0043_007.txt"));
242 : :
243 : 1 : RETURN_STATUS;
244 : : }
245 : :
246 : : /**
247 : : * @brief Verify measured rates when dry-run includes checksum calculation
248 : : * @return Return status for the complete output check
249 : : */
250 : 1 : static Return test0043_9(void)
251 : : {
252 : 1 : INITTEST;
253 : :
254 : : /* Dry-run with checksums reports the same measured rates as ordinary hashing */
255 : 1 : Config statistics_config = {
256 : : .dry_run = true,
257 : : .dry_run_with_checksums = true
258 : : };
259 : 1 : const TraversalSummary summary = {
260 : : .total_hashed_bytes = 1048576U,
261 : : .at_least_one_file_was_shown = true,
262 : : .total_hashing_elapsed_ns = 500000000LL,
263 : : .scan_elapsed_ns = 2000000000LL
264 : : };
265 : :
266 : 1 : ASSERT(SUCCESS == check_statistics_output(&statistics_config,&summary,"templates/0043_001.txt"));
267 : :
268 : 1 : RETURN_STATUS;
269 : : }
270 : :
271 : : /**
272 : : * @brief Verify complete statistics reports and independently calculated rates
273 : : *
274 : : * Fixed byte counts and intervals distinguish scan throughput from hashing
275 : : * throughput. The cases also exercise unavailable measurements, fractional
276 : : * rates, conversion bounds, and dry-run behavior. Every report is compared
277 : : * with a complete template; only the actual application runtime is variable.
278 : : * Each subtest supplies its own configuration, counters, and expected output.
279 : : * The tests check reporting from supplied counters, not traversal timing
280 : : *
281 : : * @return Return status for the output and rate checks
282 : : */
283 : 1 : Return test0043(void)
284 : : {
285 : 1 : INITTEST;
286 : :
287 : 1 : TEST(test0043_1,"Scan and hashing rates use their respective intervals");
288 : 1 : TEST(test0043_2,"No hashed bytes makes both rates unavailable");
289 : 1 : TEST(test0043_3,"Zero intervals make both rates unavailable");
290 : 1 : TEST(test0043_4,"Negative intervals display zero time and unavailable rates");
291 : 1 : TEST(test0043_5,"Positive rates below one byte per second are identified");
292 : 1 : TEST(test0043_6,"Fractional rates are truncated to whole bytes per second");
293 : 1 : TEST(test0043_7,"Oversized rates saturate before integer conversion");
294 : 1 : TEST(test0043_8,"Ordinary dry-run reports no hashed data or rates");
295 : 1 : TEST(test0043_9,"Dry-run with checksums reports measured rates");
296 : :
297 : 1 : RETURN_STATUS;
298 : : }
|