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); }