1 // Copyright 2012 Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 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. 16 // 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. 28 29 #include "atf_list.h" 30 31 #include <fcntl.h> 32 33 #include <atf-c.h> 34 35 #include "error.h" 36 37 38 /// Opens a file for reading and fails the test case if the open fails. 39 /// 40 /// \param name The file to open. 41 /// 42 /// \return A valid file descriptor. 43 static int 44 safe_open(const char* name) 45 { 46 const int fd = open(name, O_RDONLY); 47 ATF_REQUIRE(fd != -1); 48 return fd; 49 } 50 51 52 /// Test atf_list_parse for a valid case. 53 /// 54 /// \param input_name Result file to parse. 55 /// \param exp_output Expected output of the parsing. 56 static void 57 do_ok_test(const char* input_name, const char* exp_output) 58 { 59 FILE* output = fopen("output.txt", "w"); 60 kyua_error_t error = atf_list_parse(safe_open(input_name), output); 61 fclose(output); 62 63 if (!atf_utils_compare_file("output.txt", exp_output)) { 64 atf_utils_create_file("expout.txt", "%s", exp_output); 65 atf_utils_cat_file("expout.txt", "EXPECTED: "); 66 atf_utils_cat_file("output.txt", "ACTUAL: "); 67 atf_tc_fail_nonfatal("Output of atf_list_parse does not match expected " 68 "results"); 69 } 70 71 if (kyua_error_is_set(error)) { 72 char message[1024]; 73 kyua_error_format(error, message, sizeof(message)); 74 kyua_error_free(error); 75 atf_tc_fail("%s", message); 76 } 77 } 78 79 80 /// Test atf_list_parse for an error case. 81 /// 82 /// \param input_name Invalid result file to parse. 83 /// \param exp_type Expected error type. 84 /// \param exp_message Expected error message. 85 static void 86 do_fail_test(const char* input_name, const char* exp_type, 87 const char* exp_message) 88 { 89 FILE* output = fopen("output.txt", "w"); 90 kyua_error_t error = atf_list_parse(safe_open(input_name), output); 91 fclose(output); 92 93 ATF_REQUIRE(kyua_error_is_set(error)); 94 ATF_REQUIRE(kyua_error_is_type(error, exp_type)); 95 96 char message[1024]; 97 kyua_error_format(error, message, sizeof(message)); 98 kyua_error_free(error); 99 ATF_REQUIRE_MATCH(exp_message, message); 100 } 101 102 103 ATF_TC_WITHOUT_HEAD(parse__ok__one); 104 ATF_TC_BODY(parse__ok__one, tc) 105 { 106 atf_utils_create_file( 107 "input.txt", 108 "Content-Type: application/X-atf-tp; version=\"1\"\n" 109 "\n" 110 "ident: first\n"); 111 do_ok_test( 112 "input.txt", 113 "test_case{name='first'}\n"); 114 } 115 116 117 ATF_TC_WITHOUT_HEAD(parse__ok__several); 118 ATF_TC_BODY(parse__ok__several, tc) 119 { 120 atf_utils_create_file( 121 "input.txt", 122 "Content-Type: application/X-atf-tp; version=\"1\"\n" 123 "\n" 124 "ident: first\n" 125 "require.user: root\n" 126 "\n" 127 "ident: second\n" 128 "\n" 129 "ident: third\n" 130 "descr: A string with an embedded ' and \\' in it\n" 131 "has.cleanup: true\n" 132 "X-custom: foo\n" 133 "X-a'b: bar\n"); 134 do_ok_test( 135 "input.txt", 136 "test_case{name='first', required_user='root'}\n" 137 "test_case{name='second'}\n" 138 "test_case{name='third', description='A string with an embedded \\' " 139 "and \\\\\\' in it', has_cleanup='true', ['custom.X-custom']='foo', " 140 "['custom.X-a\\'b']='bar'}\n"); 141 } 142 143 144 ATF_TC_WITHOUT_HEAD(parse__error__bad_fd); 145 ATF_TC_BODY(parse__error__bad_fd, tc) 146 { 147 (void)close(10); 148 kyua_error_t error = atf_list_parse(10, stdout); 149 150 ATF_REQUIRE(kyua_error_is_set(error)); 151 ATF_REQUIRE(kyua_error_is_type(error, "libc")); 152 153 char message[1024]; 154 kyua_error_format(error, message, sizeof(message)); 155 kyua_error_free(error); 156 ATF_REQUIRE_MATCH("fdopen\\(10\\) failed", message); 157 } 158 159 160 ATF_TC_WITHOUT_HEAD(parse__error__bad_header); 161 ATF_TC_BODY(parse__error__bad_header, tc) 162 { 163 atf_utils_create_file("input.txt", "%s", ""); 164 do_fail_test("input.txt", "generic", 165 "fgets failed to read test cases list header"); 166 167 atf_utils_create_file( 168 "input.txt", 169 "Content-Type: application/X-atf-tp; version=\"1234\""); 170 do_fail_test("input.txt", "generic", 171 "Invalid test cases list header '.*X-atf-tp.*1234.*'"); 172 173 atf_utils_create_file( 174 "input.txt", 175 "Content-Type: application/X-atf-tp; version=\"1\"\n"); 176 do_fail_test("input.txt", "generic", 177 "fgets failed to read test cases list header"); 178 179 atf_utils_create_file( 180 "input.txt", 181 "Content-Type: application/X-atf-tp; version=\"1\"\n" 182 "some garbage\n" 183 "\n"); 184 do_fail_test("input.txt", "generic", 185 "Incomplete test cases list header"); 186 } 187 188 189 ATF_TC_WITHOUT_HEAD(parse__error__empty); 190 ATF_TC_BODY(parse__error__empty, tc) 191 { 192 atf_utils_create_file( 193 "input.txt", 194 "Content-Type: application/X-atf-tp; version=\"1\"\n" 195 "\n"); 196 do_fail_test("input.txt", "generic", 197 "Empty test cases list: unexpected EOF"); 198 } 199 200 201 ATF_TC_WITHOUT_HEAD(parse__error__bad_property); 202 ATF_TC_BODY(parse__error__bad_property, tc) 203 { 204 atf_utils_create_file( 205 "input.txt", 206 "Content-Type: application/X-atf-tp; version=\"1\"\n" 207 "\n" 208 "oh noes; 2\n"); 209 do_fail_test("input.txt", "generic", "Invalid property 'oh noes; 2'"); 210 } 211 212 213 ATF_TC_WITHOUT_HEAD(parse__error__bad_order); 214 ATF_TC_BODY(parse__error__bad_order, tc) 215 { 216 atf_utils_create_file( 217 "input.txt", 218 "Content-Type: application/X-atf-tp; version=\"1\"\n" 219 "\n" 220 "descr: Some text\n" 221 "ident: first\n"); 222 do_fail_test("input.txt", "generic", "Expected ident property, got descr"); 223 } 224 225 226 ATF_TP_ADD_TCS(tp) 227 { 228 ATF_TP_ADD_TC(tp, parse__ok__one); 229 ATF_TP_ADD_TC(tp, parse__ok__several); 230 ATF_TP_ADD_TC(tp, parse__error__bad_fd); 231 ATF_TP_ADD_TC(tp, parse__error__bad_header); 232 ATF_TP_ADD_TC(tp, parse__error__empty); 233 ATF_TP_ADD_TC(tp, parse__error__bad_property); 234 ATF_TP_ADD_TC(tp, parse__error__bad_order); 235 236 return atf_no_error(); 237 } 238