github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/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 20 #include <glib.h> 21 #include <unistd.h> 22 23 #include "infofile.c" 24 25 static void test_infofile_get_key(void) { 26 int rc; 27 sc_error *err; 28 29 char text[] = 30 "key=value\n" 31 "other-key=other-value\n" 32 "dup-key=value-one\n" 33 "dup-key=value-two\n"; 34 FILE *stream = fmemopen(text, sizeof text - 1, "r"); 35 g_assert_nonnull(stream); 36 37 char *value; 38 39 /* Caller must provide the stream to scan. */ 40 rc = sc_infofile_get_key(NULL, "key", &value, &err); 41 g_assert_cmpint(rc, ==, -1); 42 g_assert_nonnull(err); 43 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 44 g_assert_cmpint(sc_error_code(err), ==, SC_API_MISUSE); 45 g_assert_cmpstr(sc_error_msg(err), ==, "stream cannot be NULL"); 46 sc_error_free(err); 47 48 /* Caller must provide the key to look for. */ 49 rc = sc_infofile_get_key(stream, NULL, &value, &err); 50 g_assert_cmpint(rc, ==, -1); 51 g_assert_nonnull(err); 52 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 53 g_assert_cmpint(sc_error_code(err), ==, SC_API_MISUSE); 54 g_assert_cmpstr(sc_error_msg(err), ==, "key cannot be NULL"); 55 sc_error_free(err); 56 57 /* Caller must provide storage for the value. */ 58 rc = sc_infofile_get_key(stream, "key", NULL, &err); 59 g_assert_cmpint(rc, ==, -1); 60 g_assert_nonnull(err); 61 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 62 g_assert_cmpint(sc_error_code(err), ==, SC_API_MISUSE); 63 g_assert_cmpstr(sc_error_msg(err), ==, "value cannot be NULL"); 64 sc_error_free(err); 65 66 /* Keys that are not found get NULL values. */ 67 value = (void *)0xfefefefe; 68 rewind(stream); 69 rc = sc_infofile_get_key(stream, "missing-key", &value, &err); 70 g_assert_cmpint(rc, ==, 0); 71 g_assert_null(err); 72 g_assert_null(value); 73 74 /* Keys that are found get strdup-duplicated values. */ 75 value = NULL; 76 rewind(stream); 77 rc = sc_infofile_get_key(stream, "key", &value, &err); 78 g_assert_cmpint(rc, ==, 0); 79 g_assert_null(err); 80 g_assert_nonnull(value); 81 g_assert_cmpstr(value, ==, "value"); 82 free(value); 83 84 /* When duplicate keys are present the first value is extracted. */ 85 char *dup_value; 86 rewind(stream); 87 rc = sc_infofile_get_key(stream, "dup-key", &dup_value, &err); 88 g_assert_cmpint(rc, ==, 0); 89 g_assert_null(err); 90 g_assert_nonnull(dup_value); 91 g_assert_cmpstr(dup_value, ==, "value-one"); 92 free(dup_value); 93 94 fclose(stream); 95 96 /* Key without a value. */ 97 char *tricky_value; 98 char tricky1[] = "key\n"; 99 stream = fmemopen(tricky1, sizeof tricky1 - 1, "r"); 100 g_assert_nonnull(stream); 101 rc = sc_infofile_get_key(stream, "key", &tricky_value, &err); 102 g_assert_cmpint(rc, ==, -1); 103 g_assert_nonnull(err); 104 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 105 g_assert_cmpint(sc_error_code(err), ==, 0); 106 g_assert_cmpstr(sc_error_msg(err), ==, "line 1 is not a key=value assignment"); 107 g_assert_null(tricky_value); 108 sc_error_free(err); 109 fclose(stream); 110 111 /* Key-value pair with embedded NUL byte. */ 112 char tricky2[] = "key=value\0garbage\n"; 113 stream = fmemopen(tricky2, sizeof tricky2 - 1, "r"); 114 g_assert_nonnull(stream); 115 rc = sc_infofile_get_key(stream, "key", &tricky_value, &err); 116 g_assert_cmpint(rc, ==, -1); 117 g_assert_nonnull(err); 118 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 119 g_assert_cmpint(sc_error_code(err), ==, 0); 120 g_assert_cmpstr(sc_error_msg(err), ==, "line 1 contains NUL byte"); 121 g_assert_null(tricky_value); 122 sc_error_free(err); 123 fclose(stream); 124 125 /* Key with empty value but without trailing newline. */ 126 char tricky3[] = "key="; 127 stream = fmemopen(tricky3, sizeof tricky3 - 1, "r"); 128 g_assert_nonnull(stream); 129 rc = sc_infofile_get_key(stream, "key", &tricky_value, &err); 130 g_assert_cmpint(rc, ==, -1); 131 g_assert_nonnull(err); 132 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 133 g_assert_cmpint(sc_error_code(err), ==, 0); 134 g_assert_cmpstr(sc_error_msg(err), ==, "line 1 does not end with a newline"); 135 g_assert_null(tricky_value); 136 sc_error_free(err); 137 fclose(stream); 138 139 /* Key with empty value with a trailing newline (which is also valid). */ 140 char tricky4[] = "key=\n"; 141 stream = fmemopen(tricky4, sizeof tricky4 - 1, "r"); 142 g_assert_nonnull(stream); 143 rc = sc_infofile_get_key(stream, "key", &tricky_value, &err); 144 g_assert_cmpint(rc, ==, 0); 145 g_assert_null(err); 146 g_assert_cmpstr(tricky_value, ==, ""); 147 sc_error_free(err); 148 fclose(stream); 149 free(tricky_value); 150 151 /* The equals character alone (key is empty) */ 152 char tricky5[] = "=\n"; 153 stream = fmemopen(tricky5, sizeof tricky5 - 1, "r"); 154 g_assert_nonnull(stream); 155 rc = sc_infofile_get_key(stream, "key", &tricky_value, &err); 156 g_assert_cmpint(rc, ==, -1); 157 g_assert_nonnull(err); 158 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 159 g_assert_cmpint(sc_error_code(err), ==, 0); 160 g_assert_cmpstr(sc_error_msg(err), ==, "line 1 contains empty key"); 161 g_assert_null(tricky_value); 162 sc_error_free(err); 163 fclose(stream); 164 165 /* Unexpected section */ 166 char tricky6[] = "[section]\n"; 167 stream = fmemopen(tricky6, sizeof tricky6 - 1, "r"); 168 g_assert_nonnull(stream); 169 rc = sc_infofile_get_key(stream, "key", &tricky_value, &err); 170 g_assert_cmpint(rc, ==, -1); 171 g_assert_nonnull(err); 172 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 173 g_assert_cmpint(sc_error_code(err), ==, 0); 174 g_assert_cmpstr(sc_error_msg(err), ==, "line 1 contains unexpected section"); 175 g_assert_null(tricky_value); 176 sc_error_free(err); 177 fclose(stream); 178 } 179 180 static void test_infofile_get_ini_key(void) { 181 int rc; 182 sc_error *err; 183 184 char text[] = 185 "[section1]\n" 186 "key=value\n" 187 "[section2]\n" 188 "key2=value-two\n" 189 "other-key2=other-value-two\n" 190 "key=value-one-two\n"; 191 FILE *stream = fmemopen(text, sizeof text - 1, "r"); 192 g_assert_nonnull(stream); 193 194 char *value; 195 196 /* Key in matching in the first section */ 197 value = NULL; 198 rewind(stream); 199 rc = sc_infofile_get_ini_section_key(stream, "section1", "key", &value, &err); 200 g_assert_cmpint(rc, ==, 0); 201 g_assert_null(err); 202 g_assert_nonnull(value); 203 g_assert_cmpstr(value, ==, "value"); 204 free(value); 205 206 /* Key matching in the second section */ 207 value = NULL; 208 rewind(stream); 209 rc = sc_infofile_get_ini_section_key(stream, "section2", "key2", &value, &err); 210 g_assert_cmpint(rc, ==, 0); 211 g_assert_null(err); 212 g_assert_nonnull(value); 213 g_assert_cmpstr(value, ==, "value-two"); 214 free(value); 215 216 /* Key matching in the second section (identical to the key from 1st section) */ 217 value = NULL; 218 rewind(stream); 219 rc = sc_infofile_get_ini_section_key(stream, "section2", "key", &value, &err); 220 g_assert_cmpint(rc, ==, 0); 221 g_assert_null(err); 222 g_assert_nonnull(value); 223 g_assert_cmpstr(value, ==, "value-one-two"); 224 free(value); 225 226 /* No matching section */ 227 value = NULL; 228 rewind(stream); 229 rc = sc_infofile_get_ini_section_key(stream, "section-x", "key", &value, &err); 230 g_assert_cmpint(rc, ==, 0); 231 g_assert_null(err); 232 g_assert_null(value); 233 234 /* Invalid empty section name */ 235 value = NULL; 236 rewind(stream); 237 rc = sc_infofile_get_ini_section_key(stream, "", "key", &value, &err); 238 g_assert_cmpint(rc, ==, -1); 239 g_assert_nonnull(err); 240 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 241 g_assert_cmpint(sc_error_code(err), ==, SC_API_MISUSE); 242 g_assert_cmpstr(sc_error_msg(err), ==, "section name cannot be empty"); 243 g_assert_null(value); 244 sc_error_free(err); 245 246 /* Malformed section */ 247 value = NULL; 248 char malformed[] = "[section\n"; 249 stream = fmemopen(malformed, sizeof malformed - 1, "r"); 250 g_assert_nonnull(stream); 251 rc = sc_infofile_get_ini_section_key(stream, "section", "key", &value, &err); 252 g_assert_cmpint(rc, ==, -1); 253 g_assert_nonnull(err); 254 g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_DOMAIN); 255 g_assert_cmpint(sc_error_code(err), ==, 0); 256 g_assert_cmpstr(sc_error_msg(err), ==, "line 1 is not a valid ini section"); 257 g_assert_null(value); 258 sc_error_free(err); 259 fclose(stream); 260 } 261 262 static void __attribute__((constructor)) init(void) { 263 g_test_add_func("/infofile/get_key", test_infofile_get_key); 264 g_test_add_func("/infofile/get_ini_key", test_infofile_get_ini_key); 265 }