github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/cmd/libsnap-confine-private/error-test.c (about) 1 /* 2 * Copyright (C) 2016 Canonical Ltd 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 3 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 */ 17 18 #include "error.h" 19 #include "error.c" 20 21 #include <errno.h> 22 #include <glib.h> 23 24 static void test_sc_error_init(void) 25 { 26 struct sc_error *err; 27 // Create an error 28 err = sc_error_init("domain", 42, "printer is on %s", "fire"); 29 g_assert_nonnull(err); 30 g_test_queue_destroy((GDestroyNotify) sc_error_free, err); 31 32 // Inspect the exposed attributes 33 g_assert_cmpstr(sc_error_domain(err), ==, "domain"); 34 g_assert_cmpint(sc_error_code(err), ==, 42); 35 g_assert_cmpstr(sc_error_msg(err), ==, "printer is on fire"); 36 } 37 38 static void test_sc_error_init_from_errno(void) 39 { 40 struct sc_error *err; 41 // Create an error 42 err = sc_error_init_from_errno(ENOENT, "printer is on %s", "fire"); 43 g_assert_nonnull(err); 44 g_test_queue_destroy((GDestroyNotify) sc_error_free, err); 45 46 // Inspect the exposed attributes 47 g_assert_cmpstr(sc_error_domain(err), ==, SC_ERRNO_DOMAIN); 48 g_assert_cmpint(sc_error_code(err), ==, ENOENT); 49 g_assert_cmpstr(sc_error_msg(err), ==, "printer is on fire"); 50 } 51 52 static void test_sc_error_init_simple(void) 53 { 54 struct sc_error *err; 55 // Create an error 56 err = sc_error_init_simple("hello %s", "errors"); 57 g_assert_nonnull(err); 58 g_test_queue_destroy((GDestroyNotify) sc_error_free, err); 59 60 // Inspect the exposed attributes 61 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 62 g_assert_cmpint(sc_error_code(err), ==, 0); 63 g_assert_cmpstr(sc_error_msg(err), ==, "hello errors"); 64 } 65 66 static void test_sc_error_init_api_misuse(void) 67 { 68 struct sc_error *err; 69 // Create an error 70 err = sc_error_init_api_misuse("foo cannot be %d", 42); 71 g_assert_nonnull(err); 72 g_test_queue_destroy((GDestroyNotify) sc_error_free, err); 73 74 // Inspect the exposed attributes 75 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 76 g_assert_cmpint(sc_error_code(err), ==, SC_API_MISUSE); 77 g_assert_cmpstr(sc_error_msg(err), ==, "foo cannot be 42"); 78 } 79 80 static void test_sc_error_cleanup(void) 81 { 82 // Check that sc_error_cleanup() is safe to use. 83 84 // Cleanup is safe on NULL errors. 85 struct sc_error *err = NULL; 86 sc_cleanup_error(&err); 87 88 // Cleanup is safe on non-NULL errors. 89 err = sc_error_init("domain", 123, "msg"); 90 g_assert_nonnull(err); 91 sc_cleanup_error(&err); 92 g_assert_null(err); 93 } 94 95 static void test_sc_error_domain__NULL(void) 96 { 97 // Check that sc_error_domain() dies if called with NULL error. 98 if (g_test_subprocess()) { 99 // NOTE: the code below fools gcc 5.4 but your mileage may vary. 100 struct sc_error *err = NULL; 101 const char *domain = sc_error_domain(err); 102 (void)(domain); 103 g_test_message("expected not to reach this place"); 104 g_test_fail(); 105 return; 106 } 107 g_test_trap_subprocess(NULL, 0, 0); 108 g_test_trap_assert_failed(); 109 g_test_trap_assert_stderr 110 ("cannot obtain error domain from NULL error\n"); 111 } 112 113 static void test_sc_error_code__NULL(void) 114 { 115 // Check that sc_error_code() dies if called with NULL error. 116 if (g_test_subprocess()) { 117 // NOTE: the code below fools gcc 5.4 but your mileage may vary. 118 struct sc_error *err = NULL; 119 int code = sc_error_code(err); 120 (void)(code); 121 g_test_message("expected not to reach this place"); 122 g_test_fail(); 123 return; 124 } 125 g_test_trap_subprocess(NULL, 0, 0); 126 g_test_trap_assert_failed(); 127 g_test_trap_assert_stderr("cannot obtain error code from NULL error\n"); 128 } 129 130 static void test_sc_error_msg__NULL(void) 131 { 132 // Check that sc_error_msg() dies if called with NULL error. 133 if (g_test_subprocess()) { 134 // NOTE: the code below fools gcc 5.4 but your mileage may vary. 135 struct sc_error *err = NULL; 136 const char *msg = sc_error_msg(err); 137 (void)(msg); 138 g_test_message("expected not to reach this place"); 139 g_test_fail(); 140 return; 141 } 142 g_test_trap_subprocess(NULL, 0, 0); 143 g_test_trap_assert_failed(); 144 g_test_trap_assert_stderr 145 ("cannot obtain error message from NULL error\n"); 146 } 147 148 static void test_sc_die_on_error__NULL(void) 149 { 150 // Check that sc_die_on_error() does nothing if called with NULL error. 151 if (g_test_subprocess()) { 152 sc_die_on_error(NULL); 153 return; 154 } 155 g_test_trap_subprocess(NULL, 0, 0); 156 g_test_trap_assert_passed(); 157 } 158 159 static void test_sc_die_on_error__regular(void) 160 { 161 // Check that sc_die_on_error() dies if called with an error. 162 if (g_test_subprocess()) { 163 struct sc_error *err = 164 sc_error_init("domain", 42, "just testing"); 165 sc_die_on_error(err); 166 return; 167 } 168 g_test_trap_subprocess(NULL, 0, 0); 169 g_test_trap_assert_failed(); 170 g_test_trap_assert_stderr("just testing\n"); 171 } 172 173 static void test_sc_die_on_error__errno(void) 174 { 175 // Check that sc_die_on_error() dies if called with an errno-based error. 176 if (g_test_subprocess()) { 177 struct sc_error *err = 178 sc_error_init_from_errno(ENOENT, "just testing"); 179 sc_die_on_error(err); 180 return; 181 } 182 g_test_trap_subprocess(NULL, 0, 0); 183 g_test_trap_assert_failed(); 184 g_test_trap_assert_stderr("just testing: No such file or directory\n"); 185 } 186 187 static void test_sc_error_forward__nothing(void) 188 { 189 // Check that forwarding NULL does exactly that. 190 struct sc_error *recipient = (void *)0xDEADBEEF; 191 struct sc_error *err = NULL; 192 int rc; 193 rc = sc_error_forward(&recipient, err); 194 g_assert_null(recipient); 195 g_assert_cmpint(rc, ==, 0); 196 } 197 198 static void test_sc_error_forward__something_somewhere(void) 199 { 200 // Check that forwarding a real error works OK. 201 struct sc_error *recipient = NULL; 202 struct sc_error *err = sc_error_init("domain", 42, "just testing"); 203 int rc; 204 g_test_queue_destroy((GDestroyNotify) sc_error_free, err); 205 g_assert_nonnull(err); 206 rc = sc_error_forward(&recipient, err); 207 g_assert_nonnull(recipient); 208 g_assert_cmpint(rc, ==, -1); 209 } 210 211 static void test_sc_error_forward__something_nowhere(void) 212 { 213 // Check that forwarding a real error nowhere calls die() 214 if (g_test_subprocess()) { 215 // NOTE: the code below fools gcc 5.4 but your mileage may vary. 216 struct sc_error **err_ptr = NULL; 217 struct sc_error *err = 218 sc_error_init("domain", 42, "just testing"); 219 g_test_queue_destroy((GDestroyNotify) sc_error_free, err); 220 g_assert_nonnull(err); 221 sc_error_forward(err_ptr, err); 222 g_test_message("expected not to reach this place"); 223 g_test_fail(); 224 return; 225 } 226 g_test_trap_subprocess(NULL, 0, 0); 227 g_test_trap_assert_failed(); 228 g_test_trap_assert_stderr("just testing\n"); 229 } 230 231 static void test_sc_error_match__typical(void) 232 { 233 // NULL error doesn't match anything. 234 g_assert_false(sc_error_match(NULL, "domain", 42)); 235 236 // Non-NULL error matches if domain and code both match. 237 struct sc_error *err = sc_error_init("domain", 42, "just testing"); 238 g_test_queue_destroy((GDestroyNotify) sc_error_free, err); 239 g_assert_true(sc_error_match(err, "domain", 42)); 240 g_assert_false(sc_error_match(err, "domain", 1)); 241 g_assert_false(sc_error_match(err, "other-domain", 42)); 242 g_assert_false(sc_error_match(err, "other-domain", 1)); 243 } 244 245 static void test_sc_error_match__NULL_domain(void) 246 { 247 // Using a NULL domain is a fatal bug. 248 if (g_test_subprocess()) { 249 // NOTE: the code below fools gcc 5.4 but your mileage may vary. 250 struct sc_error *err = NULL; 251 const char *domain = NULL; 252 g_assert_false(sc_error_match(err, domain, 42)); 253 g_test_message("expected not to reach this place"); 254 g_test_fail(); 255 return; 256 } 257 g_test_trap_subprocess(NULL, 0, 0); 258 g_test_trap_assert_failed(); 259 g_test_trap_assert_stderr("cannot match error to a NULL domain\n"); 260 } 261 262 static void __attribute__((constructor)) init(void) 263 { 264 g_test_add_func("/error/sc_error_init", test_sc_error_init); 265 g_test_add_func("/error/sc_error_init_from_errno", 266 test_sc_error_init_from_errno); 267 g_test_add_func("/error/sc_error_init_simple", 268 test_sc_error_init_simple); 269 g_test_add_func("/error/sc_error_init_api_misue", 270 test_sc_error_init_api_misuse); 271 g_test_add_func("/error/sc_error_cleanup", test_sc_error_cleanup); 272 g_test_add_func("/error/sc_error_domain/NULL", 273 test_sc_error_domain__NULL); 274 g_test_add_func("/error/sc_error_code/NULL", test_sc_error_code__NULL); 275 g_test_add_func("/error/sc_error_msg/NULL", test_sc_error_msg__NULL); 276 g_test_add_func("/error/sc_die_on_error/NULL", 277 test_sc_die_on_error__NULL); 278 g_test_add_func("/error/sc_die_on_error/regular", 279 test_sc_die_on_error__regular); 280 g_test_add_func("/error/sc_die_on_error/errno", 281 test_sc_die_on_error__errno); 282 g_test_add_func("/error/sc_error_formward/nothing", 283 test_sc_error_forward__nothing); 284 g_test_add_func("/error/sc_error_formward/something_somewhere", 285 test_sc_error_forward__something_somewhere); 286 g_test_add_func("/error/sc_error_formward/something_nowhere", 287 test_sc_error_forward__something_nowhere); 288 g_test_add_func("/error/sc_error_match/typical", 289 test_sc_error_match__typical); 290 g_test_add_func("/error/sc_error_match/NULL_domain", 291 test_sc_error_match__NULL_domain); 292 }