github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/cmd/libsnap-confine-private/infofile-test.c (about)

     1  /*
     2   * Copyright (C) 2019 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 "infofile.h"
    19  #include "infofile.c"
    20  
    21  #include <glib.h>
    22  #include <unistd.h>
    23  
    24  static void test_infofile_get_key(void) {
    25      int rc;
    26      sc_error *err;
    27  
    28      char text[] =
    29          "key=value\n"
    30          "other-key=other-value\n"
    31          "dup-key=value-one\n"
    32          "dup-key=value-two\n";
    33      FILE *stream = fmemopen(text, sizeof text - 1, "r");
    34      g_assert_nonnull(stream);
    35  
    36      char *value;
    37  
    38      /* Caller must provide the stream to scan. */
    39      rc = sc_infofile_get_key(NULL, "key", &value, &err);
    40      g_assert_cmpint(rc, ==, -1);
    41      g_assert_nonnull(err);
    42      g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN);
    43      g_assert_cmpint(sc_error_code(err), ==, SC_API_MISUSE);
    44      g_assert_cmpstr(sc_error_msg(err), ==, "stream cannot be NULL");
    45      sc_error_free(err);
    46  
    47      /* Caller must provide the key to look for. */
    48      rc = sc_infofile_get_key(stream, NULL, &value, &err);
    49      g_assert_cmpint(rc, ==, -1);
    50      g_assert_nonnull(err);
    51      g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN);
    52      g_assert_cmpint(sc_error_code(err), ==, SC_API_MISUSE);
    53      g_assert_cmpstr(sc_error_msg(err), ==, "key cannot be NULL");
    54      sc_error_free(err);
    55  
    56      /* Caller must provide storage for the value. */
    57      rc = sc_infofile_get_key(stream, "key", NULL, &err);
    58      g_assert_cmpint(rc, ==, -1);
    59      g_assert_nonnull(err);
    60      g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN);
    61      g_assert_cmpint(sc_error_code(err), ==, SC_API_MISUSE);
    62      g_assert_cmpstr(sc_error_msg(err), ==, "value cannot be NULL");
    63      sc_error_free(err);
    64  
    65      /* Keys that are not found get NULL values. */
    66      value = (void *)0xfefefefe;
    67      rewind(stream);
    68      rc = sc_infofile_get_key(stream, "missing-key", &value, &err);
    69      g_assert_cmpint(rc, ==, 0);
    70      g_assert_null(err);
    71      g_assert_null(value);
    72  
    73      /* Keys that are found get strdup-duplicated values. */
    74      value = NULL;
    75      rewind(stream);
    76      rc = sc_infofile_get_key(stream, "key", &value, &err);
    77      g_assert_cmpint(rc, ==, 0);
    78      g_assert_null(err);
    79      g_assert_nonnull(value);
    80      g_assert_cmpstr(value, ==, "value");
    81      free(value);
    82  
    83      /* When duplicate keys are present the first value is extracted. */
    84      char *dup_value;
    85      rewind(stream);
    86      rc = sc_infofile_get_key(stream, "dup-key", &dup_value, &err);
    87      g_assert_cmpint(rc, ==, 0);
    88      g_assert_null(err);
    89      g_assert_nonnull(dup_value);
    90      g_assert_cmpstr(dup_value, ==, "value-one");
    91      free(dup_value);
    92  
    93      fclose(stream);
    94  
    95      /* Key without a value. */
    96      char *tricky_value;
    97      char tricky1[] = "key\n";
    98      stream = fmemopen(tricky1, sizeof tricky1 - 1, "r");
    99      g_assert_nonnull(stream);
   100      rc = sc_infofile_get_key(stream, "key", &tricky_value, &err);
   101      g_assert_cmpint(rc, ==, -1);
   102      g_assert_nonnull(err);
   103      g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN);
   104      g_assert_cmpint(sc_error_code(err), ==, 0);
   105      g_assert_cmpstr(sc_error_msg(err), ==, "line 1 is not a key=value assignment");
   106      g_assert_null(tricky_value);
   107      sc_error_free(err);
   108      fclose(stream);
   109  
   110      /* Key-value pair with embedded NUL byte. */
   111      char tricky2[] = "key=value\0garbage\n";
   112      stream = fmemopen(tricky2, sizeof tricky2 - 1, "r");
   113      g_assert_nonnull(stream);
   114      rc = sc_infofile_get_key(stream, "key", &tricky_value, &err);
   115      g_assert_cmpint(rc, ==, -1);
   116      g_assert_nonnull(err);
   117      g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN);
   118      g_assert_cmpint(sc_error_code(err), ==, 0);
   119      g_assert_cmpstr(sc_error_msg(err), ==, "line 1 contains NUL byte");
   120      g_assert_null(tricky_value);
   121      sc_error_free(err);
   122      fclose(stream);
   123  
   124      /* Key with empty value but without trailing newline. */
   125      char tricky3[] = "key=";
   126      stream = fmemopen(tricky3, sizeof tricky3 - 1, "r");
   127      g_assert_nonnull(stream);
   128      rc = sc_infofile_get_key(stream, "key", &tricky_value, &err);
   129      g_assert_cmpint(rc, ==, -1);
   130      g_assert_nonnull(err);
   131      g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN);
   132      g_assert_cmpint(sc_error_code(err), ==, 0);
   133      g_assert_cmpstr(sc_error_msg(err), ==, "line 1 does not end with a newline");
   134      g_assert_null(tricky_value);
   135      sc_error_free(err);
   136      fclose(stream);
   137  
   138      /* Key with empty value with a trailing newline (which is also valid). */
   139      char tricky4[] = "key=\n";
   140      stream = fmemopen(tricky4, sizeof tricky4 - 1, "r");
   141      g_assert_nonnull(stream);
   142      rc = sc_infofile_get_key(stream, "key", &tricky_value, &err);
   143      g_assert_cmpint(rc, ==, 0);
   144      g_assert_null(err);
   145      g_assert_cmpstr(tricky_value, ==, "");
   146      sc_error_free(err);
   147      fclose(stream);
   148      free(tricky_value);
   149  
   150      /* The equals character alone (key is empty) */
   151      char tricky5[] = "=\n";
   152      stream = fmemopen(tricky5, sizeof tricky5 - 1, "r");
   153      g_assert_nonnull(stream);
   154      rc = sc_infofile_get_key(stream, "key", &tricky_value, &err);
   155      g_assert_cmpint(rc, ==, -1);
   156      g_assert_nonnull(err);
   157      g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN);
   158      g_assert_cmpint(sc_error_code(err), ==, 0);
   159      g_assert_cmpstr(sc_error_msg(err), ==, "line 1 contains empty key");
   160      g_assert_null(tricky_value);
   161      sc_error_free(err);
   162      fclose(stream);
   163  }
   164  
   165  static void __attribute__((constructor)) init(void) { g_test_add_func("/infofile/get_key", test_infofile_get_key); }