1 | // ============================================================= // |
---|
2 | // // |
---|
3 | // File : command_output.h // |
---|
4 | // Purpose : // |
---|
5 | // // |
---|
6 | // Coded by Ralf Westram (coder@reallysoft.de) in March 2012 // |
---|
7 | // Institute of Microbiology (Technical University Munich) // |
---|
8 | // http://www.arb-home.de/ // |
---|
9 | // // |
---|
10 | // ============================================================= // |
---|
11 | |
---|
12 | #ifndef COMMAND_OUTPUT_H |
---|
13 | #define COMMAND_OUTPUT_H |
---|
14 | |
---|
15 | #ifndef UNIT_TESTS |
---|
16 | #error currently only used inside unittest-code. need refactoring to be used generally |
---|
17 | #endif |
---|
18 | |
---|
19 | #ifndef ARB_FILE_H |
---|
20 | #include <arb_file.h> |
---|
21 | #endif |
---|
22 | #ifndef ARBDBT_H |
---|
23 | #include <arbdbt.h> |
---|
24 | #endif |
---|
25 | #ifndef UT_VALGRINDED_H |
---|
26 | #include <ut_valgrinded.h> |
---|
27 | #endif |
---|
28 | #ifndef _UNISTD_H |
---|
29 | #include <unistd.h> |
---|
30 | #endif |
---|
31 | |
---|
32 | // -------------------------------------------------------------------------------- |
---|
33 | |
---|
34 | class CommandOutput : virtual Noncopyable { |
---|
35 | // support class to test CLI of arb-tools |
---|
36 | |
---|
37 | char *stdoutput; // output from command |
---|
38 | char *stderrput; |
---|
39 | GB_ERROR error; |
---|
40 | bool expect_failure; |
---|
41 | |
---|
42 | void appendError(GB_ERROR err) { |
---|
43 | if (!error) error = err; |
---|
44 | else error = GBS_global_string("%s\n%s", error, err); |
---|
45 | } |
---|
46 | |
---|
47 | char *readAndUnlink(const char *file) { |
---|
48 | char *content = GB_read_file(file); |
---|
49 | if (!content) appendError(GB_await_error()); |
---|
50 | int res = GB_unlink(file); |
---|
51 | if (res == -1) appendError(GB_await_error()); |
---|
52 | return content; |
---|
53 | } |
---|
54 | void add_failure_expection(arb_test::expectation_group& expected) { |
---|
55 | using namespace arb_test; |
---|
56 | if (expect_failure) expected.add(that(error).does_differ_from_NULL()); |
---|
57 | else expected.add(that(error).is_equal_to_NULL()); |
---|
58 | } |
---|
59 | |
---|
60 | public: |
---|
61 | CommandOutput(const char *command, bool try_valgrind, bool expect_failure_ = false) : // @@@ remove parameter try_valgrind - see ./ut_valgrinded.h@make_valgrinded_call |
---|
62 | stdoutput(NULp), |
---|
63 | stderrput(NULp), |
---|
64 | error(NULp), |
---|
65 | expect_failure(expect_failure_) |
---|
66 | { |
---|
67 | char *escaped = GBS_string_eval(command, "'=\\\\'"); // @@@ use GBK_singlequote? |
---|
68 | if (!escaped) { |
---|
69 | appendError(GB_await_error()); |
---|
70 | } |
---|
71 | else { |
---|
72 | if (try_valgrind) make_valgrinded_call(escaped); // @@@ extract part of valgrinded_system to create command |
---|
73 | |
---|
74 | pid_t pid = getpid(); |
---|
75 | |
---|
76 | char *stdout_log = GBS_global_string_copy("stdout_%i.log", pid); |
---|
77 | char *stderr_log = GBS_global_string_copy("stderr_%i.log", pid); |
---|
78 | |
---|
79 | char *cmd = GBS_global_string_copy("bash -c '%s >%s 2>%s'", escaped, stdout_log, stderr_log); |
---|
80 | |
---|
81 | appendError(GBK_system(cmd)); |
---|
82 | free(cmd); |
---|
83 | |
---|
84 | stdoutput = readAndUnlink(stdout_log); |
---|
85 | stderrput = readAndUnlink(stderr_log); |
---|
86 | |
---|
87 | free(stderr_log); |
---|
88 | free(stdout_log); |
---|
89 | } |
---|
90 | if (error) { |
---|
91 | printf("command '%s'\n" |
---|
92 | "escaped command '%s'\n" |
---|
93 | "stdout='%s'\n" |
---|
94 | "stderr='%s'\n", |
---|
95 | command, escaped, stdoutput, stderrput); |
---|
96 | } |
---|
97 | free(escaped); |
---|
98 | } |
---|
99 | ~CommandOutput() { |
---|
100 | free(stderrput); |
---|
101 | free(stdoutput); |
---|
102 | } |
---|
103 | |
---|
104 | const char *get_stdoutput() const { return stdoutput; } |
---|
105 | const char *get_stderrput() const { return stderrput; } |
---|
106 | GB_ERROR get_error() const { return error; } |
---|
107 | |
---|
108 | arb_test::match_expectation Equals(const char *expected_std, const char *expected_err) { |
---|
109 | using namespace arb_test; |
---|
110 | expectation_group expected; add_failure_expection(expected); |
---|
111 | if (expected_std) expected.add(that(stdoutput).is_equal_to(expected_std)); |
---|
112 | if (expected_err) expected.add(that(stderrput).is_equal_to(expected_err)); |
---|
113 | return all().ofgroup(expected); |
---|
114 | } |
---|
115 | arb_test::match_expectation Contains(const char *expected_std, const char *expected_err) { |
---|
116 | using namespace arb_test; |
---|
117 | expectation_group expected; add_failure_expection(expected); |
---|
118 | if (expected_std) expected.add(that(stdoutput).does_contain(expected_std)); |
---|
119 | if (expected_err) expected.add(that(stderrput).does_contain(expected_err)); |
---|
120 | return all().ofgroup(expected); |
---|
121 | } |
---|
122 | arb_test::match_expectation has_checksum(uint32_t expected_checksum) { |
---|
123 | uint32_t css = GBS_checksum(stdoutput, false, ""); |
---|
124 | uint32_t cse = GBS_checksum(stderrput, false, ""); |
---|
125 | uint32_t checksum = css^cse; |
---|
126 | |
---|
127 | using namespace arb_test; |
---|
128 | expectation_group expected; add_failure_expection(expected); |
---|
129 | expected.add(that(checksum).is_equal_to(expected_checksum)); |
---|
130 | return all().ofgroup(expected); |
---|
131 | } |
---|
132 | }; |
---|
133 | |
---|
134 | // -------------------------------------------------------------------------------- |
---|
135 | |
---|
136 | #define TEST_OUTPUT_EQUALS(cmd, expected_std, expected_err) \ |
---|
137 | do { \ |
---|
138 | bool try_valgrind = false; \ |
---|
139 | TEST_EXPECTATION(CommandOutput(cmd, try_valgrind).Equals(expected_std, expected_err)); \ |
---|
140 | } while(0) |
---|
141 | |
---|
142 | #define TEST_OUTPUT_EQUALS__BROKEN(cmd, expected_std, expected_err) \ |
---|
143 | do { \ |
---|
144 | bool try_valgrind = false; \ |
---|
145 | TEST_EXPECTATION__BROKEN_SIMPLE(CommandOutput(cmd, try_valgrind).Equals(expected_std, expected_err)); \ |
---|
146 | } while(0) |
---|
147 | |
---|
148 | #define TEST_OUTPUT_CONTAINS(cmd, expected_std, expected_err) \ |
---|
149 | do { \ |
---|
150 | bool try_valgrind = false; \ |
---|
151 | TEST_EXPECTATION(CommandOutput(cmd, try_valgrind).Contains(expected_std, expected_err)); \ |
---|
152 | } while(0) |
---|
153 | |
---|
154 | #define TEST_OUTPUT_CONTAINS__BROKEN(cmd, expected_std, expected_err) \ |
---|
155 | do { \ |
---|
156 | bool try_valgrind = false; \ |
---|
157 | TEST_EXPECTATION__BROKEN_SIMPLE(CommandOutput(cmd, try_valgrind).Contains(expected_std, expected_err)); \ |
---|
158 | } while(0) |
---|
159 | |
---|
160 | #define TEST_FAILURE_OUTPUT_CONTAINS(cmd, expected_std, expected_err) \ |
---|
161 | do { \ |
---|
162 | TEST_EXPECTATION(CommandOutput(cmd, false, true).Contains(expected_std, expected_err)); \ |
---|
163 | } while(0) |
---|
164 | |
---|
165 | #define TEST_FAILURE_OUTPUT_CONTAINS__BROKEN(cmd, expected_std, expected_err) \ |
---|
166 | do { \ |
---|
167 | TEST_EXPECTATION__BROKEN_SIMPLE(CommandOutput(cmd, false, true).Contains(expected_std, expected_err)); \ |
---|
168 | } while(0) |
---|
169 | |
---|
170 | |
---|
171 | #define TEST_OUTPUT_HAS_CHECKSUM(cmd,checksum) TEST_EXPECTATION (CommandOutput(cmd, false).has_checksum(checksum)) |
---|
172 | #define TEST_OUTPUT_HAS_CHECKSUM__BROKEN(cmd,checksum) TEST_EXPECTATION__BROKEN_SIMPLE(CommandOutput(cmd, false).has_checksum(checksum)) |
---|
173 | |
---|
174 | #define TEST_STDOUT_EQUALS(cmd, expected_std) TEST_OUTPUT_EQUALS(cmd, expected_std, (const char *)NULp) |
---|
175 | #define TEST_STDERR_EQUALS(cmd, expected_err) TEST_OUTPUT_EQUALS(cmd, (const char *)NULp, expected_err) |
---|
176 | |
---|
177 | #define TEST_STDOUT_CONTAINS(cmd, part) TEST_OUTPUT_CONTAINS(cmd, part, (const char *)NULp) |
---|
178 | #define TEST_STDERR_CONTAINS(cmd, part) TEST_OUTPUT_CONTAINS(cmd, (const char *)NULp, part) |
---|
179 | |
---|
180 | #else |
---|
181 | #error command_output.h included twice |
---|
182 | #endif // COMMAND_OUTPUT_H |
---|