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  }