1 // Copyright 2012 Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 /// Dumps the contents of a run_params object to stdout.
45 /// We only print the settings that are relevant for testing purposes.
47 /// \param run_params The run parameters to be printed.
49 dump_run_params(const kyua_run_params_t
* run_params
)
51 printf("timeout_seconds: %lu\n", run_params
->timeout_seconds
);
53 if (run_params
->unprivileged_user
== getuid())
54 printf("unprivileged_user: self\n");
56 printf("unprivileged_user: %ld\n", (long)run_params
->unprivileged_user
);
58 if (run_params
->unprivileged_group
== getgid())
59 printf("unprivileged_group: self\n");
61 printf("unprivileged_group: %ld\n",
62 (long)run_params
->unprivileged_group
);
66 /// Helper to validate argument passing to the list_test_cases method.
68 /// This prints the value of all arguments to stdout so that the caller can
69 /// compare the printed output to the expected values.
71 /// \param test_program Test program path.
72 /// \param run_params Execution parameters to configure the test process.
74 /// \return An error if the test_program is set to the magic keyword 'error'; OK
77 list_test_cases(const char* test_program
, const kyua_run_params_t
* run_params
)
79 if (strcmp(test_program
, "error") == 0)
80 return kyua_oom_error_new();
82 printf("test_program: %s\n", test_program
);
83 dump_run_params(run_params
);
84 return kyua_error_ok();
89 /// Helper to validate argument passing to the run_test_cases method.
91 /// This prints the value of all arguments to stdout so that the caller can
92 /// compare the printed output to the expected values.
94 /// \param test_program Test program path.
95 /// \param test_case Test case name.
96 /// \param result_file Path to the result file.
97 /// \param user_variables User configuration variables.
98 /// \param run_params Execution parameters to configure the test process.
99 /// \param [out] success Whether the test case returned with a successful result
100 /// or not. Set to true if result_file is the magic word 'pass'.
102 /// \return An error if the test_program is set to the magic keyword 'error'; OK
105 run_test_case(const char* test_program
, const char* test_case
,
106 const char* result_file
, const char* const user_variables
[],
107 const kyua_run_params_t
* run_params
, bool* success
)
109 if (strcmp(test_program
, "error") == 0)
110 return kyua_oom_error_new();
112 printf("test_program: %s\n", test_program
);
113 printf("test_case: %s\n", test_case
);
114 printf("result_file: %s\n", result_file
);
115 const char* const* iter
;
116 for (iter
= user_variables
; *iter
!= NULL
; ++iter
)
117 printf("variable: %s\n", *iter
);
118 dump_run_params(run_params
);
119 *success
= strcmp(result_file
, "pass") == 0;
120 return kyua_error_ok();
125 /// Definition of a mock tester.
126 static kyua_cli_tester_t mock_tester
= {
127 .list_test_cases
= list_test_cases
,
128 .run_test_case
= run_test_case
,
132 /// Definition of a tester with invalid values.
134 /// This is to be used when the called code is not supposed to invoke any of the
136 static kyua_cli_tester_t unused_tester
= {
137 .list_test_cases
= NULL
,
138 .run_test_case
= NULL
,
142 /// Counts the number of arguments in an argv vector.
144 /// \param argv The NULL-terminated arguments vector to be passed to the
145 /// kyua_cli_main function.
147 /// \return The number of arguments in argv.
149 count_argv(char* const* const argv
)
153 for (arg
= argv
; *arg
!= NULL
; arg
++)
159 ATF_TC_WITHOUT_HEAD(main__unknown_option
);
160 ATF_TC_BODY(main__unknown_option
, tc
)
162 const pid_t pid
= atf_utils_fork();
164 char arg0
[] = "unused-progname";
166 char* const argv
[] = {arg0
, arg1
, NULL
};
167 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
169 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", "cli_test: Unknown option -Z\n");
173 ATF_TC_WITHOUT_HEAD(main__missing_option_argument
);
174 ATF_TC_BODY(main__missing_option_argument
, tc
)
176 const pid_t pid
= atf_utils_fork();
178 char arg0
[] = "unused-progname";
180 char* const argv
[] = {arg0
, arg1
, NULL
};
181 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
183 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", "cli_test: -t requires an "
188 ATF_TC_WITHOUT_HEAD(main__unknown_command
);
189 ATF_TC_BODY(main__unknown_command
, tc
)
191 const pid_t pid
= atf_utils_fork();
193 char arg0
[] = "unused-progname";
194 char arg1
[] = "foobar";
195 char* const argv
[] = {arg0
, arg1
, NULL
};
196 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
198 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", "cli_test: Unknown command "
203 ATF_TC_WITHOUT_HEAD(main__missing_command
);
204 ATF_TC_BODY(main__missing_command
, tc
)
206 const pid_t pid
= atf_utils_fork();
208 char arg0
[] = "unused-progname";
209 char* const argv
[] = {arg0
, NULL
};
210 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
212 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", "cli_test: Must provide a "
217 /// Checks that a textual argument to a numerical flag raises an error.
219 /// \param flag The generic flag to test.
220 /// \param error_message The expected error message when the flag is invalid.
222 check_flag_not_a_number(const char flag
, const char *error_message
)
224 const pid_t pid
= atf_utils_fork();
226 char arg0
[] = "unused-progname";
227 char arg1
[] = "-?foo";
229 char* const argv
[] = {arg0
, arg1
, NULL
};
230 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
233 snprintf(experr
, sizeof(experr
), "cli_test: %s 'foo' (not a number)\n",
235 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", experr
);
239 /// Checks that an out of range value to a numerical flag raises an error.
241 /// \param flag The generic flag to test.
242 /// \param error_message The expected error message when the flag is invalid.
244 check_flag_out_of_range(const char flag
, const char *error_message
)
246 const pid_t pid
= atf_utils_fork();
248 char arg0
[] = "unused-progname";
249 char arg1
[] = "-?99999999999999999999";
251 char* const argv
[] = {arg0
, arg1
, NULL
};
252 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
255 snprintf(experr
, sizeof(experr
), "cli_test: %s '99999999999999999999' "
256 "(out of range)\n", error_message
);
257 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", experr
);
261 ATF_TC_WITHOUT_HEAD(main__gflag__not_a_number
);
262 ATF_TC_BODY(main__gflag__not_a_number
, tc
)
264 check_flag_not_a_number('g', "Invalid GID");
268 ATF_TC_WITHOUT_HEAD(main__gflag__out_of_range
);
269 ATF_TC_BODY(main__gflag__out_of_range
, tc
)
271 check_flag_out_of_range('g', "Invalid GID");
275 ATF_TC_WITHOUT_HEAD(main__tflag__not_a_number
);
276 ATF_TC_BODY(main__tflag__not_a_number
, tc
)
278 check_flag_not_a_number('t', "Invalid timeout value");
282 ATF_TC_WITHOUT_HEAD(main__tflag__out_of_range
);
283 ATF_TC_BODY(main__tflag__out_of_range
, tc
)
285 check_flag_out_of_range('t', "Invalid timeout value");
289 ATF_TC_WITHOUT_HEAD(main__uflag__not_a_number
);
290 ATF_TC_BODY(main__uflag__not_a_number
, tc
)
292 check_flag_not_a_number('u', "Invalid UID");
296 ATF_TC_WITHOUT_HEAD(main__uflag__out_of_range
);
297 ATF_TC_BODY(main__uflag__out_of_range
, tc
)
299 check_flag_out_of_range('u', "Invalid UID");
303 ATF_TC_WITHOUT_HEAD(list__ok
);
304 ATF_TC_BODY(list__ok
, tc
)
306 const pid_t pid
= atf_utils_fork();
308 char arg0
[] = "unused-progname";
309 char arg1
[] = "list";
310 char arg2
[] = "the-program";
311 char* const argv
[] = {arg0
, arg1
, arg2
, NULL
};
312 exit(kyua_cli_main(count_argv(argv
), argv
, &mock_tester
));
314 atf_utils_wait(pid
, EXIT_SUCCESS
,
315 "test_program: the-program\n"
316 "timeout_seconds: 60\n"
317 "unprivileged_user: self\n"
318 "unprivileged_group: self\n",
323 ATF_TC_WITHOUT_HEAD(list__custom_run_params
);
324 ATF_TC_BODY(list__custom_run_params
, tc
)
326 const pid_t pid
= atf_utils_fork();
328 char arg0
[] = "unused-progname";
329 char arg1
[] = "-g987";
330 char arg2
[] = "-t123";
331 char arg3
[] = "-u45";
332 char arg4
[] = "list";
333 char arg5
[] = "the-program";
334 char* const argv
[] = {arg0
, arg1
, arg2
, arg3
, arg4
, arg5
, NULL
};
335 exit(kyua_cli_main(count_argv(argv
), argv
, &mock_tester
));
337 atf_utils_wait(pid
, EXIT_SUCCESS
,
338 "test_program: the-program\n"
339 "timeout_seconds: 123\n"
340 "unprivileged_user: 45\n"
341 "unprivileged_group: 987\n",
346 ATF_TC_WITHOUT_HEAD(list__error
);
347 ATF_TC_BODY(list__error
, tc
)
349 const pid_t pid
= atf_utils_fork();
351 char arg0
[] = "unused-progname";
352 char arg1
[] = "list";
353 char arg2
[] = "error";
354 char* const argv
[] = {arg0
, arg1
, arg2
, NULL
};
355 exit(kyua_cli_main(count_argv(argv
), argv
, &mock_tester
));
357 atf_utils_wait(pid
, EXIT_INTERNAL_ERROR
, "", "cli_test: Not enough "
362 ATF_TC_WITHOUT_HEAD(list__missing_arguments
);
363 ATF_TC_BODY(list__missing_arguments
, tc
)
365 const pid_t pid
= atf_utils_fork();
367 char arg0
[] = "unused-progname";
368 char arg1
[] = "list";
369 char* const argv
[] = {arg0
, arg1
, NULL
};
370 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
372 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", "cli_test: No test program "
377 ATF_TC_WITHOUT_HEAD(list__too_many_arguments
);
378 ATF_TC_BODY(list__too_many_arguments
, tc
)
380 const pid_t pid
= atf_utils_fork();
382 char arg0
[] = "unused-progname";
383 char arg1
[] = "list";
384 char arg2
[] = "first";
385 char arg3
[] = "second";
386 char* const argv
[] = {arg0
, arg1
, arg2
, arg3
, NULL
};
387 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
389 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", "cli_test: Only one test program "
394 ATF_TC_WITHOUT_HEAD(test__ok__pass
);
395 ATF_TC_BODY(test__ok__pass
, tc
)
397 const pid_t pid
= atf_utils_fork();
399 char arg0
[] = "unused-progname";
400 char arg1
[] = "test";
401 char arg2
[] = "the-program";
402 char arg3
[] = "the-test-case";
403 char arg4
[] = "pass";
404 char* const argv
[] = {arg0
, arg1
, arg2
, arg3
, arg4
, NULL
};
405 exit(kyua_cli_main(count_argv(argv
), argv
, &mock_tester
));
407 atf_utils_wait(pid
, EXIT_SUCCESS
,
408 "test_program: the-program\n"
409 "test_case: the-test-case\n"
410 "result_file: pass\n"
411 "timeout_seconds: 60\n"
412 "unprivileged_user: self\n"
413 "unprivileged_group: self\n",
418 ATF_TC_WITHOUT_HEAD(test__ok__fail
);
419 ATF_TC_BODY(test__ok__fail
, tc
)
421 const pid_t pid
= atf_utils_fork();
423 char arg0
[] = "unused-progname";
424 char arg1
[] = "test";
425 char arg2
[] = "the-program";
426 char arg3
[] = "the-test-case";
427 char arg4
[] = "fail";
428 char* const argv
[] = {arg0
, arg1
, arg2
, arg3
, arg4
, NULL
};
429 exit(kyua_cli_main(count_argv(argv
), argv
, &mock_tester
));
431 atf_utils_wait(pid
, EXIT_FAILURE
,
432 "test_program: the-program\n"
433 "test_case: the-test-case\n"
434 "result_file: fail\n"
435 "timeout_seconds: 60\n"
436 "unprivileged_user: self\n"
437 "unprivileged_group: self\n",
442 ATF_TC_WITHOUT_HEAD(test__custom_run_params
);
443 ATF_TC_BODY(test__custom_run_params
, tc
)
445 const pid_t pid
= atf_utils_fork();
447 char arg0
[] = "unused-progname";
448 char arg1
[] = "-g987";
449 char arg2
[] = "-t123";
450 char arg3
[] = "-u45";
451 char arg4
[] = "test";
452 char arg5
[] = "the-program";
453 char arg6
[] = "the-test-case";
454 char arg7
[] = "pass";
455 char* const argv
[] = {arg0
, arg1
, arg2
, arg3
, arg4
, arg5
, arg6
, arg7
,
457 exit(kyua_cli_main(count_argv(argv
), argv
, &mock_tester
));
459 atf_utils_wait(pid
, EXIT_SUCCESS
,
460 "test_program: the-program\n"
461 "test_case: the-test-case\n"
462 "result_file: pass\n"
463 "timeout_seconds: 123\n"
464 "unprivileged_user: 45\n"
465 "unprivileged_group: 987\n",
470 ATF_TC_WITHOUT_HEAD(test__config_variables
);
471 ATF_TC_BODY(test__config_variables
, tc
)
473 const pid_t pid
= atf_utils_fork();
475 char arg0
[] = "unused-progname";
476 char arg1
[] = "test";
477 char arg2
[] = "-vfoo=bar";
478 char arg3
[] = "-va=c";
479 char arg4
[] = "the-program";
480 char arg5
[] = "the-test-case";
481 char arg6
[] = "pass";
482 char* const argv
[] = {arg0
, arg1
, arg2
, arg3
, arg4
, arg5
, arg6
, NULL
};
483 exit(kyua_cli_main(count_argv(argv
), argv
, &mock_tester
));
485 atf_utils_wait(pid
, EXIT_SUCCESS
,
486 "test_program: the-program\n"
487 "test_case: the-test-case\n"
488 "result_file: pass\n"
489 "variable: foo=bar\n"
491 "timeout_seconds: 60\n"
492 "unprivileged_user: self\n"
493 "unprivileged_group: self\n",
498 ATF_TC_WITHOUT_HEAD(test__error
);
499 ATF_TC_BODY(test__error
, tc
)
501 const pid_t pid
= atf_utils_fork();
503 char arg0
[] = "unused-progname";
504 char arg1
[] = "test";
505 char arg2
[] = "error";
506 char* const argv
[] = {arg0
, arg1
, arg2
, arg2
, arg2
, NULL
};
507 exit(kyua_cli_main(count_argv(argv
), argv
, &mock_tester
));
509 atf_utils_wait(pid
, EXIT_INTERNAL_ERROR
, "", "cli_test: Not enough "
514 /// Checks that the test command validates the right number of arguments.
516 /// \param count Number of arguments to pass to the test command.
518 check_test_invalid_arguments(const unsigned int count
)
520 printf("Checking with %d arguments\n", count
);
521 const pid_t pid
= atf_utils_fork();
523 char arg0
[] = "unused-progname";
524 char arg1
[] = "test";
527 char* argv
[] = {arg0
, arg1
, argX
, argX
, argX
, argX
, NULL
};
528 argv
[2 + count
] = NULL
;
529 exit(kyua_cli_main(2 + count
, argv
, &unused_tester
));
531 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", "cli_test: Must provide a test "
532 "program, a test case name and a result file\n");
536 ATF_TC_WITHOUT_HEAD(test__invalid_arguments
);
537 ATF_TC_BODY(test__invalid_arguments
, tc
)
539 check_test_invalid_arguments(0);
540 check_test_invalid_arguments(1);
541 check_test_invalid_arguments(2);
542 check_test_invalid_arguments(4);
546 ATF_TC_WITHOUT_HEAD(test__unknown_option
);
547 ATF_TC_BODY(test__unknown_option
, tc
)
549 const pid_t pid
= atf_utils_fork();
551 char arg0
[] = "unused-progname";
552 char arg1
[] = "test";
554 char* const argv
[] = {arg0
, arg1
, arg2
, NULL
};
555 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
557 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", "cli_test: Unknown test option "
562 ATF_TC_WITHOUT_HEAD(test__missing_option_argument
);
563 ATF_TC_BODY(test__missing_option_argument
, tc
)
565 const pid_t pid
= atf_utils_fork();
567 char arg0
[] = "unused-progname";
568 char arg1
[] = "test";
570 char* const argv
[] = {arg0
, arg1
, arg2
, NULL
};
571 exit(kyua_cli_main(count_argv(argv
), argv
, &unused_tester
));
573 atf_utils_wait(pid
, EXIT_USAGE_ERROR
, "", "cli_test: test's -v requires an "
580 ATF_TP_ADD_TC(tp
, main__unknown_option
);
581 ATF_TP_ADD_TC(tp
, main__missing_option_argument
);
582 ATF_TP_ADD_TC(tp
, main__unknown_command
);
583 ATF_TP_ADD_TC(tp
, main__missing_command
);
584 ATF_TP_ADD_TC(tp
, main__gflag__not_a_number
);
585 ATF_TP_ADD_TC(tp
, main__gflag__out_of_range
);
586 ATF_TP_ADD_TC(tp
, main__tflag__not_a_number
);
587 ATF_TP_ADD_TC(tp
, main__tflag__out_of_range
);
588 ATF_TP_ADD_TC(tp
, main__uflag__not_a_number
);
589 ATF_TP_ADD_TC(tp
, main__uflag__out_of_range
);
591 ATF_TP_ADD_TC(tp
, list__ok
);
592 ATF_TP_ADD_TC(tp
, list__custom_run_params
);
593 ATF_TP_ADD_TC(tp
, list__error
);
594 ATF_TP_ADD_TC(tp
, list__missing_arguments
);
595 ATF_TP_ADD_TC(tp
, list__too_many_arguments
);
597 ATF_TP_ADD_TC(tp
, test__ok__pass
);
598 ATF_TP_ADD_TC(tp
, test__ok__fail
);
599 ATF_TP_ADD_TC(tp
, test__custom_run_params
);
600 ATF_TP_ADD_TC(tp
, test__config_variables
);
601 ATF_TP_ADD_TC(tp
, test__error
);
602 ATF_TP_ADD_TC(tp
, test__invalid_arguments
);
603 ATF_TP_ADD_TC(tp
, test__unknown_option
);
604 ATF_TP_ADD_TC(tp
, test__missing_option_argument
);
606 return atf_no_error();