Branch data Line data Source code
1 : : #include "sute.h"
2 : :
3 : : #define DRY_RUN_ARGUMENTS "--dry-run --database=0040.db tests/fixtures/diffs/diff1/2"
4 : :
5 : : struct color_environment_backup {
6 : : char *no_color;
7 : : char *term;
8 : : bool snapshot_is_valid;
9 : : };
10 : :
11 : : static const char *remembered_value = "remembered";
12 : : static LOGMODES remembered_log_level = REGULAR | UNDECOR | REMEMBER;
13 : :
14 : : /**
15 : : * @brief Write one decorated message through the REMEMBER logger path
16 : : */
17 : 4 : static void capture_remembered_message(void)
18 : : {
19 : 4 : slog(remembered_log_level,
20 : : "@{bold}@{red}%s %zu@{reset}\n",
21 : : remembered_value,
22 : : (size_t)7U);
23 : 4 : }
24 : :
25 : : /**
26 : : * @brief Save environment values that affect automatic color output
27 : : *
28 : : * @param backup Zero-initialized storage for duplicated environment values
29 : : * @return SUCCESS when the values were saved, otherwise FAILURE
30 : : */
31 : 6 : static Return save_color_environment(struct color_environment_backup *backup)
32 : : {
33 : : /* Status returned by this function through deliver()
34 : : Default value assumes successful completion */
35 : 6 : Return status = SUCCESS;
36 : 6 : const char *no_color = getenv("NO_COLOR");
37 : 6 : const char *term = getenv("TERM");
38 : :
39 : : /* Copy existing values so an unset variable remains distinct from an empty one */
40 [ - + ]: 6 : if(no_color != NULL)
41 : : {
42 : 0 : backup->no_color = strdup(no_color);
43 : 0 : ASSERT(backup->no_color != NULL);
44 : : }
45 : :
46 [ + - - + ]: 6 : if(SUCCESS == status && term != NULL)
47 : : {
48 : 0 : backup->term = strdup(term);
49 : 0 : ASSERT(backup->term != NULL);
50 : : }
51 : :
52 : : /* An incomplete snapshot must never replace the original environment */
53 : 6 : backup->snapshot_is_valid = SUCCESS == status;
54 : :
55 : 6 : deliver(status);
56 : : }
57 : :
58 : : /**
59 : : * @brief Restore environment values saved before a color output test
60 : : *
61 : : * @param backup Saved environment values to restore and release
62 : : * @return SUCCESS when the environment was restored, otherwise FAILURE
63 : : */
64 : 6 : static Return restore_color_environment(struct color_environment_backup *backup)
65 : : {
66 : : /* Status returned by this function through deliver()
67 : : Default value assumes successful completion */
68 : 6 : Return status = SUCCESS;
69 : :
70 : : /* Attempt both restorations before checking their results */
71 [ + - ]: 6 : if(backup->snapshot_is_valid == true)
72 : : {
73 : 6 : int no_color_result = 0;
74 : 6 : int term_result = 0;
75 : :
76 [ - + ]: 6 : if(backup->no_color != NULL)
77 : : {
78 : 0 : no_color_result = setenv("NO_COLOR",backup->no_color,1);
79 : : } else {
80 : 6 : no_color_result = unsetenv("NO_COLOR");
81 : : }
82 : :
83 [ - + ]: 6 : if(backup->term != NULL)
84 : : {
85 : 0 : term_result = setenv("TERM",backup->term,1);
86 : : } else {
87 : 6 : term_result = unsetenv("TERM");
88 : : }
89 : :
90 : 6 : ASSERT(no_color_result == 0);
91 : 6 : ASSERT(term_result == 0);
92 : : }
93 : :
94 : : /* Release complete or partial snapshots after any restoration result */
95 : 6 : free(backup->term);
96 : 6 : free(backup->no_color);
97 : 6 : memset(backup,0,sizeof(*backup));
98 : :
99 : 6 : deliver(status);
100 : : }
101 : :
102 : : /**
103 : : * @brief Check the most recent message stored in the real REMEMBER table
104 : : *
105 : : * @param[in] database Database containing the temporary remember_history table
106 : : * @param[in] expected_message Exact plain message expected in the last row
107 : : * @param expected_length Number of bytes in @p expected_message
108 : : * @return SUCCESS when the latest row contains the expected bytes, otherwise FAILURE
109 : : */
110 : 4 : static Return check_last_remembered_message(
111 : : sqlite3 *database,
112 : : const char *expected_message,
113 : : size_t expected_length)
114 : : {
115 : : /* Status returned by this function through deliver()
116 : : Default value assumes successful completion */
117 : 4 : Return status = SUCCESS;
118 : 4 : sqlite3_stmt *statement = NULL;
119 : :
120 : : /* Read the most recently stored message from the real SQLite table */
121 : 4 : ASSERT(SQLITE_OK == sqlite3_prepare_v2(database,
122 : : "SELECT message FROM temp.remember_history ORDER BY id DESC LIMIT 1;",
123 : : -1,&statement,NULL));
124 : 4 : ASSERT(SQLITE_ROW == sqlite3_step(statement));
125 : :
126 : : /* Require the exact byte count and text, including prefixes and the newline */
127 [ + - ]: 4 : if(SUCCESS == status)
128 : : {
129 : 4 : const unsigned char *stored_message = sqlite3_column_text(statement,0);
130 : 4 : ASSERT(stored_message != NULL);
131 : 4 : ASSERT(sqlite3_column_bytes(statement,0) == (int)expected_length);
132 : 4 : ASSERT(memcmp(stored_message,expected_message,expected_length) == 0);
133 : : }
134 : :
135 : : /* Release the statement even when a query or content check failed */
136 : 4 : const int finalize_result = sqlite3_finalize(statement);
137 : 4 : ASSERT(finalize_result == SQLITE_OK);
138 : :
139 : 4 : deliver(status);
140 : : }
141 : :
142 : : /**
143 : : * @brief Run a deterministic dry run and compare its complete captured output
144 : : *
145 : : * @param arguments Complete dry-run command-line arguments
146 : : * @param stdout_pattern_file Full stdout template for the selected color mode
147 : : * @param expected_color_mode Exact mode name to substitute into the diagnostic template
148 : : * @param colors_expected True when captured stdout must contain terminal color sequences
149 : : * @return SUCCESS when stdout matches and stderr is empty, otherwise FAILURE
150 : : */
151 : 40 : static Return assert_output(
152 : : const char *arguments,
153 : : const char *stdout_pattern_file,
154 : : const char *expected_color_mode,
155 : : const bool colors_expected)
156 : : {
157 : : /* Status returned by this function through deliver()
158 : : Default value assumes successful completion */
159 : 40 : Return status = SUCCESS;
160 : :
161 : 40 : m_create(char,stdout_result,MEMORY_STRING);
162 : 40 : m_create(char,stderr_result,MEMORY_STRING);
163 : 40 : m_create(char,stdout_pattern,MEMORY_STRING);
164 : :
165 : : /* Run with test diagnostics enabled and collect both output streams */
166 : 40 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
167 : 40 : ASSERT(SUCCESS == runit(arguments,stdout_result,stderr_result,COMPLETED,STDERR_ALLOW));
168 : :
169 : : /* Check the selected mode, complete output, styling, and absence of errors */
170 : 40 : ASSERT(SUCCESS == get_file_content(stdout_pattern_file,stdout_pattern));
171 : 40 : ASSERT(SUCCESS == replace_placeholder(stdout_pattern,"%COLOR_MODE%",expected_color_mode));
172 : 40 : ASSERT(SUCCESS == match_pattern(stdout_result,stdout_pattern,stdout_pattern_file));
173 : 40 : ASSERT((strchr(m_text(stdout_result),'\033') != NULL) == colors_expected);
174 : 40 : ASSERT(stderr_result->length == 0U);
175 : :
176 : : /* Release capture buffers and the template after any assertion result */
177 : 40 : call(m_del(stdout_pattern));
178 : 40 : call(m_del(stderr_result));
179 : 40 : call(m_del(stdout_result));
180 : :
181 : 40 : deliver(status);
182 : : }
183 : :
184 : : /**
185 : : * @brief Check the test runner's forced color default without a color argument
186 : : *
187 : : * The runner sets TESTITALL_TEST_ENV_COLOR_MODE=always so captured golden
188 : : * output retains styling. This case checks that test setting; the application's
189 : : * ordinary automatic default is checked separately in test0040_7()
190 : : *
191 : : * @return Return describing success or failure
192 : : */
193 : 2 : static Return test0040_1(void)
194 : : {
195 : 2 : INITTEST;
196 : :
197 : : /* Leave --color unspecified so the test-only override determines the mode */
198 : 2 : ASSERT(SUCCESS == assert_output(
199 : : DRY_RUN_ARGUMENTS,
200 : : "templates/0040_001.txt",
201 : : "always",
202 : : true));
203 : :
204 : 2 : RETURN_STATUS;
205 : : }
206 : :
207 : : /**
208 : : * @brief Check all long color mode arguments and their configuration equivalents
209 : : *
210 : : * Each --color value must appear in the parsed configuration and produce the
211 : : * expected output. Always retains styling; never and auto omit it from the
212 : : * redirected stream. Repeating the option must apply its last value
213 : : *
214 : : * @return Return describing success or failure
215 : : */
216 : 2 : static Return test0040_2(void)
217 : : {
218 : 2 : INITTEST;
219 : :
220 : : /* Forced styling must survive output redirection */
221 : 2 : ASSERT(SUCCESS == assert_output(
222 : : "--color=always " DRY_RUN_ARGUMENTS,
223 : : "templates/0040_001.txt",
224 : : "always",
225 : : true));
226 : :
227 : 2 : ASSERT(SUCCESS == copy_path("tests/templates/0040_001.conf","0040_001.conf"));
228 : 2 : ASSERT(SUCCESS == assert_output(
229 : : "--config=0040_001.conf",
230 : : "templates/0040_001.txt",
231 : : "always",
232 : : true));
233 : 2 : call(delete_path_if_present("0040_001.conf"));
234 : :
235 : : /* Explicitly disabling styling must produce plain text */
236 : 2 : ASSERT(SUCCESS == assert_output(
237 : : "--color=never " DRY_RUN_ARGUMENTS,
238 : : "templates/0040_002.txt",
239 : : "never",
240 : : false));
241 : :
242 : 2 : ASSERT(SUCCESS == copy_path("tests/templates/0040_002.conf","0040_002.conf"));
243 : 2 : ASSERT(SUCCESS == assert_output(
244 : : "--config=0040_002.conf",
245 : : "templates/0040_002.txt",
246 : : "never",
247 : : false));
248 : 2 : call(delete_path_if_present("0040_002.conf"));
249 : :
250 : : /* Auto must select its own mode while keeping redirected output plain */
251 : 2 : ASSERT(SUCCESS == assert_output(
252 : : "--color=auto " DRY_RUN_ARGUMENTS,
253 : : "templates/0040_002.txt",
254 : : "auto",
255 : : false));
256 : :
257 : 2 : ASSERT(SUCCESS == copy_path("tests/templates/0040_010.conf","0040_010.conf"));
258 : 2 : ASSERT(SUCCESS == assert_output(
259 : : "--config=0040_010.conf",
260 : : "templates/0040_002.txt",
261 : : "auto",
262 : : false));
263 : 2 : call(delete_path_if_present("0040_010.conf"));
264 : :
265 : : /* The last value replaces the earlier choice in either source */
266 : 2 : ASSERT(SUCCESS == assert_output(
267 : : "--color=always --color=never " DRY_RUN_ARGUMENTS,
268 : : "templates/0040_002.txt",
269 : : "never",
270 : : false));
271 : 2 : ASSERT(SUCCESS == copy_path("tests/templates/0040_002_1.conf","0040_002_1.conf"));
272 : 2 : ASSERT(SUCCESS == assert_output(
273 : : "--config=0040_002_1.conf",
274 : : "templates/0040_002.txt",
275 : : "never",
276 : : false));
277 : 2 : call(delete_path_if_present("0040_002_1.conf"));
278 : :
279 : 2 : RETURN_STATUS;
280 : : }
281 : :
282 : : /**
283 : : * @brief Check all short color mode arguments with captured output
284 : : *
285 : : * Each -S value must select the same mode and output as its --color equivalent
286 : : *
287 : : * @return Return describing success or failure
288 : : */
289 : 2 : static Return test0040_3(void)
290 : : {
291 : 2 : INITTEST;
292 : :
293 : : /* Forced styling must survive output redirection */
294 : 2 : ASSERT(SUCCESS == assert_output(
295 : : "-S always " DRY_RUN_ARGUMENTS,
296 : : "templates/0040_001.txt",
297 : : "always",
298 : : true));
299 : :
300 : : /* Explicitly disabling styling must produce plain text */
301 : 2 : ASSERT(SUCCESS == assert_output(
302 : : "-S never " DRY_RUN_ARGUMENTS,
303 : : "templates/0040_002.txt",
304 : : "never",
305 : : false));
306 : :
307 : : /* Auto must select its own mode while keeping redirected output plain */
308 : 2 : ASSERT(SUCCESS == assert_output(
309 : : "-S auto " DRY_RUN_ARGUMENTS,
310 : : "templates/0040_002.txt",
311 : : "auto",
312 : : false));
313 : :
314 : 2 : RETURN_STATUS;
315 : : }
316 : :
317 : : /**
318 : : * @brief Check that forced color output is preserved with NO_COLOR set
319 : : *
320 : : * Captured auto output would be plain even without NO_COLOR because stdout
321 : : * is redirected. The always run must retain styling even when NO_COLOR is
322 : : * present with an empty value
323 : : *
324 : : * @return Return describing success or failure
325 : : */
326 : 2 : static Return test0040_4(void)
327 : : {
328 : 2 : INITTEST;
329 : 2 : struct color_environment_backup environment_backup = {0};
330 : :
331 : : /* Save the environment and set NO_COLOR to an explicitly empty value */
332 : 2 : ASSERT(SUCCESS == save_color_environment(&environment_backup));
333 : 2 : ASSERT(0 == setenv("NO_COLOR","",1));
334 : 2 : ASSERT(0 == setenv("TERM","xterm",1));
335 : :
336 : : /* Redirected auto output remains plain under this environment setting */
337 : 2 : ASSERT(SUCCESS == assert_output(
338 : : "--color=auto " DRY_RUN_ARGUMENTS,
339 : : "templates/0040_002.txt",
340 : : "auto",
341 : : false));
342 : :
343 : : /* Always must preserve styling despite the presence of NO_COLOR */
344 : 2 : ASSERT(SUCCESS == assert_output(
345 : : "--color=always " DRY_RUN_ARGUMENTS,
346 : : "templates/0040_001.txt",
347 : : "always",
348 : : true));
349 : :
350 : : /* Restore the original environment even when an assertion failed */
351 : 2 : call(restore_color_environment(&environment_backup));
352 : :
353 : 2 : RETURN_STATUS;
354 : : }
355 : :
356 : : /**
357 : : * @brief Check that forced color output is preserved with TERM=dumb
358 : : *
359 : : * Captured auto output would be plain even without TERM=dumb because stdout
360 : : * is redirected. The always run must retain styling even when TERM identifies
361 : : * a dumb terminal
362 : : *
363 : : * @return Return describing success or failure
364 : : */
365 : 2 : static Return test0040_5(void)
366 : : {
367 : 2 : INITTEST;
368 : 2 : struct color_environment_backup environment_backup = {0};
369 : :
370 : : /* Save the environment and isolate TERM=dumb from NO_COLOR */
371 : 2 : ASSERT(SUCCESS == save_color_environment(&environment_backup));
372 : 2 : ASSERT(0 == unsetenv("NO_COLOR"));
373 : 2 : ASSERT(0 == setenv("TERM","dumb",1));
374 : :
375 : : /* Redirected auto output remains plain under this environment setting */
376 : 2 : ASSERT(SUCCESS == assert_output(
377 : : "--color=auto " DRY_RUN_ARGUMENTS,
378 : : "templates/0040_002.txt",
379 : : "auto",
380 : : false));
381 : :
382 : : /* Always must preserve styling despite TERM=dumb */
383 : 2 : ASSERT(SUCCESS == assert_output(
384 : : "--color=always " DRY_RUN_ARGUMENTS,
385 : : "templates/0040_001.txt",
386 : : "always",
387 : : true));
388 : :
389 : : /* Restore the original environment even when an assertion failed */
390 : 2 : call(restore_color_environment(&environment_backup));
391 : :
392 : 2 : RETURN_STATUS;
393 : : }
394 : :
395 : : /**
396 : : * @brief Check immediate message styling and plain-text storage in SQLite
397 : : *
398 : : * Messages logged with REMEMBER are displayed immediately and stored for later
399 : : * reporting. In always mode, markup adds terminal styling only to the displayed
400 : : * copy; the stored row contains plain text. Markup supplied through a formatted
401 : : * argument is also expanded, while raw terminal control bytes become visible
402 : : * hexadecimal escapes. In never mode, the displayed message and stored row
403 : : * must both contain the same plain text
404 : : *
405 : : * @return Return describing success or failure
406 : : */
407 : 2 : static Return test0040_6(void)
408 : : {
409 : 2 : INITTEST;
410 : :
411 : : /* Preserve the logger settings used by the surrounding test suite */
412 : 2 : const RATIONAL_COLOR_MODE initial_color_mode = atomic_load_explicit(&rational_color_mode,memory_order_relaxed);
413 : 2 : const LOGMODES initial_logger_mode = atomic_load_explicit(&rational_logger_mode,memory_order_relaxed);
414 : :
415 : : /* Markup in the formatted argument must expand, while raw ANSI bytes must
416 : : remain visible as escaped text in both the output and the stored message */
417 : : static const char styled_value[] =
418 : : "always @{green}dynamic@{reset} " BOLD "inside" RESET "\033[2Jblocked";
419 : : static const char expected_styled_output[] = "TESTING:" BOLD RED "always "
420 : : GREEN "dynamic" RESET " \\x1B[1minside\\x1B[0m\\x1B[2Jblocked 7"
421 : : RESET "\n";
422 : : static const char expected_stored_styled_message[] =
423 : : "TESTING:always dynamic \\x1B[1minside\\x1B[0m\\x1B[2Jblocked 7\n";
424 : : static const char expected_plain_output[] = "never 7\n";
425 : : static const char create_table_sql[] =
426 : : "CREATE TEMP TABLE remember_history ("
427 : : "id INTEGER PRIMARY KEY AUTOINCREMENT,"
428 : : "message TEXT NOT NULL"
429 : : ");";
430 : 2 : Config *initial_config = config;
431 : 2 : Config remember_config = {0};
432 : :
433 : 2 : m_create(char,captured_stdout,MEMORY_STRING);
434 : 2 : m_create(char,captured_stderr,MEMORY_STRING);
435 : :
436 : : /* Give the real REMEMBER callback an isolated in-memory SQLite table */
437 : 2 : ASSERT(SQLITE_OK == sqlite3_open(":memory:",&remember_config.db));
438 : 2 : config = &remember_config;
439 : 2 : ASSERT(SQLITE_OK == sqlite3_exec(remember_config.db,create_table_sql,NULL,NULL,NULL));
440 : :
441 : : /* Capture a styled message with a TESTING prefix */
442 : 2 : rational_logger_mode = TESTING;
443 : 2 : rational_color_mode = COLOR_MODE_ALWAYS;
444 : 2 : remembered_log_level = TESTING | REMEMBER;
445 : 2 : remembered_value = styled_value;
446 : 2 : ASSERT(SUCCESS == function_capture(
447 : : capture_remembered_message,
448 : : captured_stdout,
449 : : captured_stderr));
450 : :
451 : : /* Check expanded markup and escaped raw controls in the displayed line */
452 : 2 : ASSERT(0 == strcmp(m_text(captured_stdout),expected_styled_output));
453 : 2 : ASSERT(captured_stderr->length == 0U);
454 : :
455 : : /* SQLite must receive the same text and prefix without terminal styling */
456 : 2 : ASSERT(SUCCESS == check_last_remembered_message(
457 : : remember_config.db,
458 : : expected_stored_styled_message,
459 : : sizeof(expected_stored_styled_message) - 1U));
460 : :
461 : : /* Disable styling and capture an ordinary message without a log prefix */
462 : 2 : rational_logger_mode = REGULAR;
463 : 2 : rational_color_mode = COLOR_MODE_NEVER;
464 : 2 : remembered_log_level = REGULAR | UNDECOR | REMEMBER;
465 : 2 : remembered_value = "never";
466 : 2 : ASSERT(SUCCESS == function_capture(
467 : : capture_remembered_message,
468 : : captured_stdout,
469 : : captured_stderr));
470 : :
471 : : /* Both the immediate output and stored row must contain plain text */
472 : 2 : ASSERT(0 == strcmp(m_text(captured_stdout),expected_plain_output));
473 : 2 : ASSERT(NULL == strchr(m_text(captured_stdout),'\033'));
474 : 2 : ASSERT(captured_stderr->length == 0U);
475 : 2 : ASSERT(SUCCESS == check_last_remembered_message(
476 : : remember_config.db,
477 : : expected_plain_output,
478 : : sizeof(expected_plain_output) - 1U));
479 : :
480 : : /* Restore shared state and close the isolated database after any result */
481 : 2 : rational_logger_mode = initial_logger_mode;
482 : 2 : rational_color_mode = initial_color_mode;
483 : 2 : remembered_log_level = REGULAR | UNDECOR | REMEMBER;
484 : 2 : remembered_value = "remembered";
485 : :
486 : 2 : config = initial_config;
487 : 2 : const int close_result = sqlite3_close(remember_config.db);
488 : 2 : ASSERT(close_result == SQLITE_OK);
489 : :
490 : : /* Release both captured output streams */
491 : 2 : call(m_del(captured_stdout));
492 : 2 : call(m_del(captured_stderr));
493 : :
494 : 2 : RETURN_STATUS;
495 : : }
496 : :
497 : : /**
498 : : * @brief Check default automatic color output without the test-only override
499 : : *
500 : : * Removing TESTITALL_TEST_ENV_COLOR_MODE exposes the application's normal
501 : : * auto default. NO_COLOR is absent and TERM is xterm, so the captured output
502 : : * must be plain because it is redirected to a file. The runner mode and all
503 : : * changed environment values are restored after the check
504 : : *
505 : : * @return Return describing success or failure
506 : : */
507 : 2 : static Return test0040_7(void)
508 : : {
509 : 2 : INITTEST;
510 : 2 : const enum run_mode initial_run_mode = testitall_runit_mode;
511 : 2 : struct color_environment_backup environment_backup = {0};
512 : 2 : const char *test_color_override = getenv("TESTITALL_TEST_ENV_COLOR_MODE");
513 : 2 : const bool test_color_override_was_set = test_color_override != NULL;
514 : 2 : char *saved_test_color_override = NULL;
515 : :
516 : : /* Copy the override before unsetenv invalidates its environment storage */
517 [ + - ]: 2 : if(test_color_override_was_set == true)
518 : : {
519 : 2 : saved_test_color_override = strdup(test_color_override);
520 : 2 : ASSERT(saved_test_color_override != NULL);
521 : : }
522 : :
523 : : /* Remove forced styling and environment settings that could disable auto */
524 : 2 : ASSERT(SUCCESS == save_color_environment(&environment_backup));
525 : 2 : ASSERT(0 == unsetenv("NO_COLOR"));
526 : 2 : ASSERT(0 == setenv("TERM","xterm",1));
527 : 2 : ASSERT(0 == unsetenv("TESTITALL_TEST_ENV_COLOR_MODE"));
528 : :
529 : : /* Use the standalone executable to check its default color behavior.
530 : : With stdout redirected to a file, auto must produce plain text */
531 : 2 : testitall_runit_mode = EXTERNAL_CALL;
532 : 2 : ASSERT(SUCCESS == assert_output(
533 : : DRY_RUN_ARGUMENTS,
534 : : "templates/0040_002.txt",
535 : : "auto",
536 : : false));
537 : :
538 : : /* Restore shared test state even when an assertion failed */
539 : 2 : testitall_runit_mode = initial_run_mode;
540 : :
541 [ + - ]: 2 : if(saved_test_color_override != NULL)
542 : : {
543 : 2 : const int restore_result = setenv("TESTITALL_TEST_ENV_COLOR_MODE",saved_test_color_override,1);
544 : 2 : ASSERT(restore_result == 0);
545 [ # # ]: 0 : } else if(test_color_override_was_set == false){
546 : 0 : const int restore_result = unsetenv("TESTITALL_TEST_ENV_COLOR_MODE");
547 : 0 : ASSERT(restore_result == 0);
548 : : }
549 : :
550 : : /* Release the override copy and restore the remaining environment values */
551 : 2 : free(saved_test_color_override);
552 : 2 : call(restore_color_environment(&environment_backup));
553 : :
554 : 2 : RETURN_STATUS;
555 : : }
556 : :
557 : : /**
558 : : * @brief Check that CLI and configuration color options reject unsupported and empty values
559 : : *
560 : : * @return Return describing success or failure
561 : : */
562 : 2 : static Return test0040_8(void)
563 : : {
564 : 2 : INITTEST;
565 : :
566 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
567 : :
568 : 2 : const struct argument_test_case cases[] = {
569 : : /* Both option spellings must reject an unsupported mode name */
570 : : {"--color=invalid-value",FAILURE,"templates/0040_003.txt","templates/0040_004.txt"},
571 : : {"-S invalid-value",FAILURE,"templates/0040_003.txt","templates/0040_004.txt"},
572 : :
573 : : /* An explicitly empty value must also be rejected by both spellings */
574 : : {"--color=",FAILURE,"templates/0040_003.txt","templates/0040_005.txt"},
575 : : {"-S ''",FAILURE,"templates/0040_003.txt","templates/0040_005.txt"},
576 : : {0}
577 : : };
578 : :
579 : 2 : ASSERT(SUCCESS == run_and_match_templates(cases,NULL,NULL));
580 : :
581 : 2 : ASSERT(SUCCESS == copy_path("tests/templates/0040_004.conf","0040_004.conf"));
582 : 2 : ASSERT(SUCCESS == copy_path("tests/templates/0040_005.conf","0040_005.conf"));
583 : 2 : const struct argument_test_case file_cases[] = {
584 : : {"--config=0040_004.conf",FAILURE,"templates/0003_013.txt","templates/0040_004_1.txt"},
585 : : {"--config=0040_005.conf",FAILURE,"templates/0003_013.txt","templates/0040_005_1.txt"},
586 : : {0}
587 : : };
588 : 2 : ASSERT(SUCCESS == run_and_match_templates(file_cases,NULL,NULL));
589 : 2 : call(delete_path_if_present("0040_004.conf"));
590 : 2 : call(delete_path_if_present("0040_005.conf"));
591 : :
592 : 2 : RETURN_STATUS;
593 : : }
594 : :
595 : : /**
596 : : * @brief Check that long and short color options require a value
597 : : *
598 : : * @return Return describing success or failure
599 : : */
600 : 2 : static Return test0040_9(void)
601 : : {
602 : 2 : INITTEST;
603 : :
604 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
605 : :
606 : 2 : const struct argument_test_case cases[] = {
607 : : /* Check the parser diagnostic for a long option with no following value */
608 : : {"--color",FAILURE,"templates/0040_003.txt","templates/0040_006.txt"},
609 : : /* Check the corresponding diagnostic for the short option */
610 : : {"-S",FAILURE,"templates/0040_003.txt","templates/0040_007.txt"},
611 : : {0}
612 : : };
613 : :
614 : 2 : ASSERT(SUCCESS == run_and_match_templates(cases,NULL,NULL));
615 : :
616 : 2 : RETURN_STATUS;
617 : : }
618 : :
619 : : /**
620 : : * @brief Check that verbose diagnostics report each selected color mode
621 : : *
622 : : * @return Return describing success or failure
623 : : */
624 : 2 : static Return test0040_10(void)
625 : : {
626 : 2 : INITTEST;
627 : :
628 : : /* Verbose diagnostics must name always and retain styled messages */
629 : 2 : ASSERT(SUCCESS == assert_output(
630 : : "--verbose --color=always " DRY_RUN_ARGUMENTS,
631 : : "templates/0040_008.txt",
632 : : "always",
633 : : true));
634 : :
635 : : /* Verbose diagnostics must name never and contain no terminal styling */
636 : 2 : ASSERT(SUCCESS == assert_output(
637 : : "--verbose --color=never " DRY_RUN_ARGUMENTS,
638 : : "templates/0040_009.txt",
639 : : "never",
640 : : false));
641 : :
642 : : /* Auto must be reported distinctly while redirected output stays plain */
643 : 2 : ASSERT(SUCCESS == assert_output(
644 : : "--verbose --color=auto " DRY_RUN_ARGUMENTS,
645 : : "templates/0040_009.txt",
646 : : "auto",
647 : : false));
648 : :
649 : 2 : RETURN_STATUS;
650 : : }
651 : :
652 : : #undef DRY_RUN_ARGUMENTS
653 : :
654 : : /**
655 : : * @brief Check color output modes and plain-text storage of remembered messages
656 : : *
657 : : * Successful command-line cases scan a small directory fixture in dry-run mode
658 : : * and compare the captured output with full templates. They check --color and
659 : : * -S, the test runner's forced color setting, the application's automatic
660 : : * default, forced styling with NO_COLOR or TERM=dumb, and verbose diagnostics.
661 : : * Invalid, empty, and missing option values must produce the expected errors.
662 : : *
663 : : * A separate logger case stores messages in a real temporary SQLite table.
664 : : * Displayed messages may contain styling, while stored messages must remain
665 : : * plain text with raw terminal control bytes escaped
666 : : *
667 : : * @return SUCCESS when all color output and message-storage scenarios pass
668 : : */
669 : 2 : Return test0040(void)
670 : : {
671 : 2 : INITTEST;
672 : :
673 : : /* Check the runner default, both option spellings, and forced styling */
674 : 2 : TEST(test0040_1,"Test runs preserve colored dry-run output by default");
675 : 2 : TEST(test0040_2,"Long color options control captured dry-run output");
676 : 2 : TEST(test0040_3,"Short color options control captured dry-run output");
677 : 2 : TEST(test0040_4,"Forced color output is preserved with NO_COLOR set");
678 : 2 : TEST(test0040_5,"Forced color output is preserved with TERM=dumb");
679 : :
680 : : /* Compare immediate message formatting with the bytes stored in SQLite */
681 : 2 : TEST(test0040_6,"REMEMBER stores plain text while immediate output uses color markup");
682 : :
683 : : /* Check the application default without the runner override */
684 : 2 : TEST(test0040_7,"Default auto mode omits color from captured output without the test override");
685 : :
686 : : /* Verify rejected values and the mode reported in verbose diagnostics */
687 : 2 : TEST(test0040_8,"Color options reject unsupported and empty values");
688 : 2 : TEST(test0040_9,"Color options reject missing values");
689 : 2 : TEST(test0040_10,"Verbose diagnostics report the selected color mode");
690 : :
691 : 2 : RETURN_STATUS;
692 : : }
|