]>
Commit | Line | Data |
---|---|---|
3fd1520c | 1 | #include "clar_libgit2.h" |
22a2d3d5 | 2 | #include "futils.h" |
b1667039 | 3 | #include "git2/sys/config.h" |
b1667039 | 4 | #include "config.h" |
9462c471 VM |
5 | |
6 | void test_config_write__initialize(void) | |
7 | { | |
8 | cl_fixture_sandbox("config/config9"); | |
a1abe66a | 9 | cl_fixture_sandbox("config/config15"); |
f8ede948 | 10 | cl_fixture_sandbox("config/config17"); |
e579e0f7 | 11 | cl_fixture_sandbox("config/config22"); |
9462c471 VM |
12 | } |
13 | ||
14 | void test_config_write__cleanup(void) | |
15 | { | |
16 | cl_fixture_cleanup("config9"); | |
a1abe66a | 17 | cl_fixture_cleanup("config15"); |
f8ede948 | 18 | cl_fixture_cleanup("config17"); |
e579e0f7 | 19 | cl_fixture_cleanup("config22"); |
9462c471 VM |
20 | } |
21 | ||
22 | void test_config_write__replace_value(void) | |
23 | { | |
24 | git_config *cfg; | |
25 | int i; | |
26 | int64_t l, expected = +9223372036854775803; | |
27 | ||
28 | /* By freeing the config, we make sure we flush the values */ | |
29 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
30 | cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); | |
31 | git_config_free(cfg); | |
32 | ||
33 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
255c38c5 | 34 | cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy")); |
9462c471 VM |
35 | cl_assert(i == 5); |
36 | git_config_free(cfg); | |
37 | ||
38 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
39 | cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1)); | |
40 | git_config_free(cfg); | |
41 | ||
42 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
43 | cl_git_pass(git_config_set_int64(cfg, "core.verylong", expected)); | |
44 | git_config_free(cfg); | |
45 | ||
46 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
255c38c5 | 47 | cl_git_pass(git_config_get_int64(&l, cfg, "core.verylong")); |
9462c471 VM |
48 | cl_assert(l == expected); |
49 | git_config_free(cfg); | |
50 | ||
51 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
255c38c5 | 52 | cl_must_fail(git_config_get_int32(&i, cfg, "core.verylong")); |
9462c471 VM |
53 | git_config_free(cfg); |
54 | ||
55 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
56 | cl_git_pass(git_config_set_int64(cfg, "core.verylong", 1)); | |
57 | git_config_free(cfg); | |
58 | } | |
59 | ||
60 | void test_config_write__delete_value(void) | |
61 | { | |
62 | git_config *cfg; | |
63 | int32_t i; | |
64 | ||
65 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
66 | cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); | |
67 | git_config_free(cfg); | |
68 | ||
69 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
54b2a37a | 70 | cl_git_pass(git_config_delete_entry(cfg, "core.dummy")); |
9462c471 VM |
71 | git_config_free(cfg); |
72 | ||
73 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
904b67e6 | 74 | cl_assert(git_config_get_int32(&i, cfg, "core.dummy") == GIT_ENOTFOUND); |
9462c471 VM |
75 | cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1)); |
76 | git_config_free(cfg); | |
77 | } | |
78 | ||
a1abe66a | 79 | /* |
80 | * At the beginning of the test: | |
81 | * - config9 has: core.dummy2=42 | |
82 | * - config15 has: core.dummy2=7 | |
83 | */ | |
84 | void test_config_write__delete_value_at_specific_level(void) | |
85 | { | |
86 | git_config *cfg, *cfg_specific; | |
87 | int32_t i; | |
88 | ||
89 | cl_git_pass(git_config_open_ondisk(&cfg, "config15")); | |
90 | cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2")); | |
91 | cl_assert(i == 7); | |
92 | git_config_free(cfg); | |
93 | ||
94 | cl_git_pass(git_config_new(&cfg)); | |
95 | cl_git_pass(git_config_add_file_ondisk(cfg, "config9", | |
eae0bfdc | 96 | GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); |
a1abe66a | 97 | cl_git_pass(git_config_add_file_ondisk(cfg, "config15", |
eae0bfdc | 98 | GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); |
a1abe66a | 99 | |
100 | cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL)); | |
101 | ||
54b2a37a | 102 | cl_git_pass(git_config_delete_entry(cfg_specific, "core.dummy2")); |
a1abe66a | 103 | git_config_free(cfg); |
104 | ||
105 | cl_git_pass(git_config_open_ondisk(&cfg, "config15")); | |
106 | cl_assert(git_config_get_int32(&i, cfg, "core.dummy2") == GIT_ENOTFOUND); | |
107 | cl_git_pass(git_config_set_int32(cfg, "core.dummy2", 7)); | |
108 | ||
109 | git_config_free(cfg_specific); | |
110 | git_config_free(cfg); | |
111 | } | |
112 | ||
a060cccc RRC |
113 | /* |
114 | * This test exposes a bug where duplicate empty section headers could prevent | |
115 | * deletion of config entries. | |
116 | */ | |
117 | void test_config_write__delete_value_with_duplicate_header(void) | |
118 | { | |
f56a417d | 119 | const char *file_name = "config-duplicate-header"; |
a060cccc RRC |
120 | const char *entry_name = "remote.origin.url"; |
121 | git_config *cfg; | |
122 | git_config_entry *entry; | |
123 | ||
f56a417d RRC |
124 | /* This config can occur after removing and re-adding the origin remote */ |
125 | const char *file_content = | |
126 | "[remote \"origin\"]\n" \ | |
127 | "[branch \"master\"]\n" \ | |
128 | " remote = \"origin\"\n" \ | |
129 | "[remote \"origin\"]\n" \ | |
130 | " url = \"foo\"\n"; | |
131 | ||
132 | /* Write the test config and make sure the expected entry exists */ | |
133 | cl_git_mkfile(file_name, file_content); | |
a060cccc RRC |
134 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); |
135 | cl_git_pass(git_config_get_entry(&entry, cfg, entry_name)); | |
136 | ||
137 | /* Delete that entry */ | |
138 | cl_git_pass(git_config_delete_entry(cfg, entry_name)); | |
139 | ||
140 | /* Reopen the file and make sure the entry no longer exists */ | |
141 | git_config_entry_free(entry); | |
142 | git_config_free(cfg); | |
143 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
144 | cl_git_fail(git_config_get_entry(&entry, cfg, entry_name)); | |
145 | ||
146 | /* Cleanup */ | |
147 | git_config_entry_free(entry); | |
148 | git_config_free(cfg); | |
149 | } | |
150 | ||
5a70df94 RRC |
151 | /* |
152 | * This test exposes a bug where duplicate section headers could cause | |
153 | * config_write to add a new entry when one already exists. | |
154 | */ | |
155 | void test_config_write__add_value_with_duplicate_header(void) | |
156 | { | |
157 | const char *file_name = "config-duplicate-insert"; | |
158 | const char *entry_name = "foo.c"; | |
159 | const char *old_val = "old"; | |
160 | const char *new_val = "new"; | |
161 | const char *str; | |
162 | git_config *cfg, *snapshot; | |
163 | ||
164 | /* c = old should be replaced by c = new. | |
165 | * The bug causes c = new to be inserted under the first 'foo' header. | |
166 | */ | |
167 | const char *file_content = | |
168 | "[foo]\n" \ | |
169 | " a = b\n" \ | |
170 | "[other]\n" \ | |
171 | " a = b\n" \ | |
172 | "[foo]\n" \ | |
173 | " c = old\n"; | |
174 | ||
175 | /* Write the test config */ | |
176 | cl_git_mkfile(file_name, file_content); | |
177 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
178 | ||
179 | /* make sure the expected entry (foo.c) exists */ | |
180 | cl_git_pass(git_config_snapshot(&snapshot, cfg)); | |
181 | cl_git_pass(git_config_get_string(&str, snapshot, entry_name)); | |
182 | cl_assert_equal_s(old_val, str); | |
183 | git_config_free(snapshot); | |
184 | ||
185 | /* Try setting foo.c to something else */ | |
186 | cl_git_pass(git_config_set_string(cfg, entry_name, new_val)); | |
187 | git_config_free(cfg); | |
188 | ||
189 | /* Reopen the file and make sure the new value was set */ | |
190 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
191 | cl_git_pass(git_config_snapshot(&snapshot, cfg)); | |
192 | cl_git_pass(git_config_get_string(&str, snapshot, entry_name)); | |
193 | cl_assert_equal_s(new_val, str); | |
194 | ||
195 | /* Cleanup */ | |
196 | git_config_free(snapshot); | |
197 | git_config_free(cfg); | |
198 | } | |
199 | ||
f79c7322 ET |
200 | void test_config_write__overwrite_value_with_duplicate_header(void) |
201 | { | |
202 | const char *file_name = "config-duplicate-header"; | |
203 | const char *entry_name = "remote.origin.url"; | |
204 | git_config *cfg; | |
205 | git_config_entry *entry; | |
206 | ||
207 | /* This config can occur after removing and re-adding the origin remote */ | |
208 | const char *file_content = | |
209 | "[remote \"origin\"]\n" \ | |
210 | "[branch \"master\"]\n" \ | |
211 | " remote = \"origin\"\n" \ | |
212 | "[remote \"origin\"]\n" \ | |
213 | " url = \"foo\"\n"; | |
214 | ||
215 | /* Write the test config and make sure the expected entry exists */ | |
216 | cl_git_mkfile(file_name, file_content); | |
217 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
218 | cl_git_pass(git_config_get_entry(&entry, cfg, entry_name)); | |
219 | ||
220 | /* Update that entry */ | |
221 | cl_git_pass(git_config_set_string(cfg, entry_name, "newurl")); | |
222 | ||
223 | /* Reopen the file and make sure the entry was updated */ | |
224 | git_config_entry_free(entry); | |
225 | git_config_free(cfg); | |
226 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
227 | cl_git_pass(git_config_get_entry(&entry, cfg, entry_name)); | |
228 | ||
229 | cl_assert_equal_s("newurl", entry->value); | |
230 | ||
231 | /* Cleanup */ | |
232 | git_config_entry_free(entry); | |
233 | git_config_free(cfg); | |
234 | } | |
235 | ||
d6b7e404 ET |
236 | static int multivar_cb(const git_config_entry *entry, void *data) |
237 | { | |
238 | int *n = (int *)data; | |
239 | ||
240 | cl_assert_equal_s(entry->value, "newurl"); | |
241 | ||
242 | (*n)++; | |
243 | ||
244 | return 0; | |
245 | } | |
246 | ||
bf99390e ET |
247 | void test_config_write__overwrite_multivar_within_duplicate_header(void) |
248 | { | |
249 | const char *file_name = "config-duplicate-header"; | |
250 | const char *entry_name = "remote.origin.url"; | |
251 | git_config *cfg; | |
252 | git_config_entry *entry; | |
d6b7e404 | 253 | int n = 0; |
bf99390e ET |
254 | |
255 | /* This config can occur after removing and re-adding the origin remote */ | |
256 | const char *file_content = | |
257 | "[remote \"origin\"]\n" \ | |
258 | " url = \"bar\"\n" \ | |
259 | "[branch \"master\"]\n" \ | |
260 | " remote = \"origin\"\n" \ | |
261 | "[remote \"origin\"]\n" \ | |
262 | " url = \"foo\"\n"; | |
263 | ||
264 | /* Write the test config and make sure the expected entry exists */ | |
265 | cl_git_mkfile(file_name, file_content); | |
266 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
267 | cl_git_pass(git_config_get_entry(&entry, cfg, entry_name)); | |
268 | ||
269 | /* Update that entry */ | |
0daf998d | 270 | cl_git_pass(git_config_set_multivar(cfg, entry_name, ".*", "newurl")); |
bf99390e ET |
271 | git_config_entry_free(entry); |
272 | git_config_free(cfg); | |
bf99390e | 273 | |
d6b7e404 ET |
274 | /* Reopen the file and make sure the entry was updated */ |
275 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
276 | cl_git_pass(git_config_get_multivar_foreach(cfg, entry_name, NULL, multivar_cb, &n)); | |
277 | cl_assert_equal_i(2, n); | |
bf99390e ET |
278 | |
279 | /* Cleanup */ | |
bf99390e ET |
280 | git_config_free(cfg); |
281 | } | |
282 | ||
54fef6eb CMN |
283 | void test_config_write__write_subsection(void) |
284 | { | |
285 | git_config *cfg; | |
9a97f49e | 286 | git_buf buf = GIT_BUF_INIT; |
54fef6eb CMN |
287 | |
288 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
289 | cl_git_pass(git_config_set_string(cfg, "my.own.var", "works")); | |
290 | git_config_free(cfg); | |
291 | ||
292 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
9a97f49e | 293 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "my.own.var")); |
e579e0f7 | 294 | cl_assert_equal_s("works", buf.ptr); |
9a97f49e | 295 | |
ac3d33df | 296 | git_buf_dispose(&buf); |
54fef6eb CMN |
297 | git_config_free(cfg); |
298 | } | |
299 | ||
9462c471 VM |
300 | void test_config_write__delete_inexistent(void) |
301 | { | |
302 | git_config *cfg; | |
303 | ||
304 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
54b2a37a | 305 | cl_assert(git_config_delete_entry(cfg, "core.imaginary") == GIT_ENOTFOUND); |
9462c471 VM |
306 | git_config_free(cfg); |
307 | } | |
750be86a AR |
308 | |
309 | void test_config_write__value_containing_quotes(void) | |
310 | { | |
311 | git_config *cfg; | |
9a97f49e | 312 | git_buf buf = GIT_BUF_INIT; |
750be86a AR |
313 | |
314 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
315 | cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes")); | |
9a97f49e | 316 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar")); |
e579e0f7 MB |
317 | cl_assert_equal_s("this \"has\" quotes", buf.ptr); |
318 | git_buf_dispose(&buf); | |
750be86a AR |
319 | git_config_free(cfg); |
320 | ||
321 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
9a97f49e | 322 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar")); |
e579e0f7 MB |
323 | cl_assert_equal_s("this \"has\" quotes", buf.ptr); |
324 | git_buf_dispose(&buf); | |
750be86a | 325 | git_config_free(cfg); |
67d334c1 CMN |
326 | |
327 | /* The code path for values that already exist is different, check that one as well */ | |
328 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
329 | cl_git_pass(git_config_set_string(cfg, "core.somevar", "this also \"has\" quotes")); | |
9a97f49e | 330 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar")); |
e579e0f7 MB |
331 | cl_assert_equal_s("this also \"has\" quotes", buf.ptr); |
332 | git_buf_dispose(&buf); | |
67d334c1 CMN |
333 | git_config_free(cfg); |
334 | ||
335 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
9a97f49e | 336 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar")); |
e579e0f7 | 337 | cl_assert_equal_s("this also \"has\" quotes", buf.ptr); |
ac3d33df | 338 | git_buf_dispose(&buf); |
67d334c1 CMN |
339 | git_config_free(cfg); |
340 | } | |
341 | ||
342 | void test_config_write__escape_value(void) | |
343 | { | |
344 | git_config *cfg; | |
9a97f49e | 345 | git_buf buf = GIT_BUF_INIT; |
67d334c1 CMN |
346 | |
347 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
348 | cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes and \t")); | |
9a97f49e | 349 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar")); |
e579e0f7 MB |
350 | cl_assert_equal_s("this \"has\" quotes and \t", buf.ptr); |
351 | git_buf_dispose(&buf); | |
67d334c1 CMN |
352 | git_config_free(cfg); |
353 | ||
354 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
9a97f49e | 355 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar")); |
e579e0f7 | 356 | cl_assert_equal_s("this \"has\" quotes and \t", buf.ptr); |
ac3d33df | 357 | git_buf_dispose(&buf); |
67d334c1 | 358 | git_config_free(cfg); |
750be86a | 359 | } |
f8ede948 | 360 | |
a1abe66a | 361 | void test_config_write__add_value_at_specific_level(void) |
362 | { | |
363 | git_config *cfg, *cfg_specific; | |
364 | int i; | |
365 | int64_t l, expected = +9223372036854775803; | |
9a97f49e | 366 | git_buf buf = GIT_BUF_INIT; |
a1abe66a | 367 | |
ac3d33df | 368 | /* open config15 as global level config file */ |
a1abe66a | 369 | cl_git_pass(git_config_new(&cfg)); |
370 | cl_git_pass(git_config_add_file_ondisk(cfg, "config9", | |
eae0bfdc | 371 | GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); |
a1abe66a | 372 | cl_git_pass(git_config_add_file_ondisk(cfg, "config15", |
eae0bfdc | 373 | GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); |
a1abe66a | 374 | |
375 | cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL)); | |
376 | ||
377 | cl_git_pass(git_config_set_int32(cfg_specific, "core.int32global", 28)); | |
378 | cl_git_pass(git_config_set_int64(cfg_specific, "core.int64global", expected)); | |
379 | cl_git_pass(git_config_set_bool(cfg_specific, "core.boolglobal", true)); | |
380 | cl_git_pass(git_config_set_string(cfg_specific, "core.stringglobal", "I'm a global config value!")); | |
381 | git_config_free(cfg_specific); | |
382 | git_config_free(cfg); | |
383 | ||
ac3d33df | 384 | /* open config15 as local level config file */ |
a1abe66a | 385 | cl_git_pass(git_config_open_ondisk(&cfg, "config15")); |
386 | ||
387 | cl_git_pass(git_config_get_int32(&i, cfg, "core.int32global")); | |
388 | cl_assert_equal_i(28, i); | |
389 | cl_git_pass(git_config_get_int64(&l, cfg, "core.int64global")); | |
390 | cl_assert(l == expected); | |
391 | cl_git_pass(git_config_get_bool(&i, cfg, "core.boolglobal")); | |
392 | cl_assert_equal_b(true, i); | |
9a97f49e | 393 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.stringglobal")); |
e579e0f7 | 394 | cl_assert_equal_s("I'm a global config value!", buf.ptr); |
a1abe66a | 395 | |
ac3d33df | 396 | git_buf_dispose(&buf); |
a1abe66a | 397 | git_config_free(cfg); |
398 | } | |
399 | ||
400 | void test_config_write__add_value_at_file_with_no_clrf_at_the_end(void) | |
f8ede948 | 401 | { |
402 | git_config *cfg; | |
403 | int i; | |
404 | ||
405 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
406 | cl_git_pass(git_config_set_int32(cfg, "core.newline", 7)); | |
407 | git_config_free(cfg); | |
408 | ||
409 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
410 | cl_git_pass(git_config_get_int32(&i, cfg, "core.newline")); | |
411 | cl_assert_equal_i(7, i); | |
412 | ||
413 | git_config_free(cfg); | |
414 | } | |
48bde2f1 | 415 | |
69374869 L |
416 | void test_config_write__add_section_at_file_with_no_clrf_at_the_end(void) |
417 | { | |
418 | git_config *cfg; | |
419 | int i; | |
420 | ||
421 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
422 | cl_git_pass(git_config_set_int32(cfg, "diff.context", 10)); | |
423 | git_config_free(cfg); | |
424 | ||
425 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
426 | cl_git_pass(git_config_get_int32(&i, cfg, "diff.context")); | |
427 | cl_assert_equal_i(10, i); | |
428 | ||
429 | git_config_free(cfg); | |
430 | } | |
431 | ||
a9f7236a SS |
432 | void test_config_write__add_value_which_needs_quotes(void) |
433 | { | |
9a97f49e | 434 | git_config *cfg, *base; |
a9f7236a SS |
435 | const char* str1; |
436 | const char* str2; | |
437 | const char* str3; | |
438 | const char* str4; | |
7dd28dde | 439 | const char* str5; |
a9f7236a SS |
440 | |
441 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
442 | cl_git_pass(git_config_set_string(cfg, "core.startwithspace", " Something")); | |
443 | cl_git_pass(git_config_set_string(cfg, "core.endwithspace", "Something ")); | |
444 | cl_git_pass(git_config_set_string(cfg, "core.containscommentchar1", "some#thing")); | |
445 | cl_git_pass(git_config_set_string(cfg, "core.containscommentchar2", "some;thing")); | |
7dd28dde | 446 | cl_git_pass(git_config_set_string(cfg, "core.startwhithsapceandcontainsdoublequote", " some\"thing")); |
a9f7236a SS |
447 | git_config_free(cfg); |
448 | ||
9a97f49e CMN |
449 | cl_git_pass(git_config_open_ondisk(&base, "config17")); |
450 | cl_git_pass(git_config_snapshot(&cfg, base)); | |
a9f7236a SS |
451 | cl_git_pass(git_config_get_string(&str1, cfg, "core.startwithspace")); |
452 | cl_assert_equal_s(" Something", str1); | |
453 | cl_git_pass(git_config_get_string(&str2, cfg, "core.endwithspace")); | |
454 | cl_assert_equal_s("Something ", str2); | |
455 | cl_git_pass(git_config_get_string(&str3, cfg, "core.containscommentchar1")); | |
456 | cl_assert_equal_s("some#thing", str3); | |
457 | cl_git_pass(git_config_get_string(&str4, cfg, "core.containscommentchar2")); | |
458 | cl_assert_equal_s("some;thing", str4); | |
7dd28dde SS |
459 | cl_git_pass(git_config_get_string(&str5, cfg, "core.startwhithsapceandcontainsdoublequote")); |
460 | cl_assert_equal_s(" some\"thing", str5); | |
a9f7236a | 461 | git_config_free(cfg); |
9a97f49e | 462 | git_config_free(base); |
a9f7236a SS |
463 | } |
464 | ||
48bde2f1 CMN |
465 | void test_config_write__can_set_a_value_to_NULL(void) |
466 | { | |
467 | git_repository *repository; | |
468 | git_config *config; | |
469 | ||
470 | repository = cl_git_sandbox_init("testrepo.git"); | |
471 | ||
472 | cl_git_pass(git_repository_config(&config, repository)); | |
473 | cl_git_fail(git_config_set_string(config, "a.b.c", NULL)); | |
474 | git_config_free(config); | |
475 | ||
476 | cl_git_sandbox_cleanup(); | |
477 | } | |
c57f6682 NV |
478 | |
479 | void test_config_write__can_set_an_empty_value(void) | |
480 | { | |
481 | git_repository *repository; | |
482 | git_config *config; | |
9a97f49e | 483 | git_buf buf = {0}; |
c57f6682 NV |
484 | |
485 | repository = cl_git_sandbox_init("testrepo.git"); | |
486 | cl_git_pass(git_repository_config(&config, repository)); | |
487 | ||
488 | cl_git_pass(git_config_set_string(config, "core.somevar", "")); | |
9a97f49e CMN |
489 | cl_git_pass(git_config_get_string_buf(&buf, config, "core.somevar")); |
490 | cl_assert_equal_s("", buf.ptr); | |
c57f6682 | 491 | |
ac3d33df | 492 | git_buf_dispose(&buf); |
c57f6682 NV |
493 | git_config_free(config); |
494 | cl_git_sandbox_cleanup(); | |
495 | } | |
e8162fd0 | 496 | |
497 | void test_config_write__updating_a_locked_config_file_returns_ELOCKED(void) | |
498 | { | |
499 | git_config *cfg; | |
500 | ||
501 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
502 | ||
503 | cl_git_mkfile("config9.lock", "[core]\n"); | |
504 | ||
505 | cl_git_fail_with(git_config_set_string(cfg, "core.dump", "boom"), GIT_ELOCKED); | |
506 | ||
507 | git_config_free(cfg); | |
508 | } | |
96869a4e | 509 | |
36913b8c CMN |
510 | void test_config_write__outside_change(void) |
511 | { | |
512 | int32_t tmp; | |
513 | git_config *cfg; | |
514 | const char *filename = "config-ext-change"; | |
515 | ||
516 | cl_git_mkfile(filename, "[old]\nvalue = 5\n"); | |
517 | ||
518 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); | |
519 | ||
520 | cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value")); | |
521 | ||
522 | /* Change the value on the file itself (simulate external process) */ | |
523 | cl_git_mkfile(filename, "[old]\nvalue = 6\n"); | |
524 | ||
525 | cl_git_pass(git_config_set_int32(cfg, "new.value", 7)); | |
526 | ||
527 | cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value")); | |
eaf37034 | 528 | cl_assert_equal_i(6, tmp); |
36913b8c | 529 | |
36913b8c CMN |
530 | git_config_free(cfg); |
531 | } | |
6dc55872 | 532 | |
08313c4b L |
533 | #define FOO_COMMENT \ |
534 | "; another comment!\n" | |
535 | ||
7ee61b8e ET |
536 | #define SECTION_FOO \ |
537 | "\n" \ | |
538 | " \n" \ | |
539 | " [section \"foo\"] \n" \ | |
540 | " # here's a comment\n" \ | |
541 | "\tname = \"value\"\n" \ | |
542 | " name2 = \"value2\"\n" \ | |
08313c4b L |
543 | |
544 | #define SECTION_FOO_WITH_COMMENT SECTION_FOO FOO_COMMENT | |
7ee61b8e ET |
545 | |
546 | #define SECTION_BAR \ | |
547 | "[section \"bar\"]\t\n" \ | |
548 | "\t \n" \ | |
549 | " barname=\"value\"\n" | |
550 | ||
551 | ||
552 | void test_config_write__preserves_whitespace_and_comments(void) | |
553 | { | |
554 | const char *file_name = "config-duplicate-header"; | |
7ee61b8e ET |
555 | const char *n; |
556 | git_config *cfg; | |
e579e0f7 | 557 | git_str newfile = GIT_STR_INIT; |
7ee61b8e ET |
558 | |
559 | /* This config can occur after removing and re-adding the origin remote */ | |
08313c4b | 560 | const char *file_content = SECTION_FOO_WITH_COMMENT SECTION_BAR; |
7ee61b8e ET |
561 | |
562 | /* Write the test config and make sure the expected entry exists */ | |
563 | cl_git_mkfile(file_name, file_content); | |
564 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
565 | cl_git_pass(git_config_set_string(cfg, "section.foo.other", "otherval")); | |
566 | cl_git_pass(git_config_set_string(cfg, "newsection.newname", "new_value")); | |
567 | ||
568 | /* Ensure that we didn't needlessly mangle the config file */ | |
569 | cl_git_pass(git_futils_readbuffer(&newfile, file_name)); | |
570 | n = newfile.ptr; | |
571 | ||
572 | cl_assert_equal_strn(SECTION_FOO, n, strlen(SECTION_FOO)); | |
573 | n += strlen(SECTION_FOO); | |
7ee61b8e ET |
574 | cl_assert_equal_strn("\tother = otherval\n", n, strlen("\tother = otherval\n")); |
575 | n += strlen("\tother = otherval\n"); | |
08313c4b L |
576 | cl_assert_equal_strn(FOO_COMMENT, n, strlen(FOO_COMMENT)); |
577 | n += strlen(FOO_COMMENT); | |
7ee61b8e ET |
578 | |
579 | cl_assert_equal_strn(SECTION_BAR, n, strlen(SECTION_BAR)); | |
580 | n += strlen(SECTION_BAR); | |
581 | ||
582 | cl_assert_equal_s("[newsection]\n\tnewname = new_value\n", n); | |
583 | ||
e579e0f7 | 584 | git_str_dispose(&newfile); |
7ee61b8e ET |
585 | git_config_free(cfg); |
586 | } | |
587 | ||
588 | void test_config_write__preserves_entry_with_name_only(void) | |
589 | { | |
590 | const char *file_name = "config-empty-value"; | |
7ee61b8e | 591 | git_config *cfg; |
e579e0f7 | 592 | git_str newfile = GIT_STR_INIT; |
7ee61b8e ET |
593 | |
594 | /* Write the test config and make sure the expected entry exists */ | |
595 | cl_git_mkfile(file_name, "[section \"foo\"]\n\tname\n"); | |
596 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
597 | cl_git_pass(git_config_set_string(cfg, "newsection.newname", "new_value")); | |
598 | cl_git_pass(git_config_set_string(cfg, "section.foo.other", "otherval")); | |
599 | ||
600 | cl_git_pass(git_futils_readbuffer(&newfile, file_name)); | |
601 | cl_assert_equal_s("[section \"foo\"]\n\tname\n\tother = otherval\n[newsection]\n\tnewname = new_value\n", newfile.ptr); | |
602 | ||
e579e0f7 | 603 | git_str_dispose(&newfile); |
7ee61b8e ET |
604 | git_config_free(cfg); |
605 | } | |
606 | ||
6dc55872 ET |
607 | void test_config_write__to_empty_file(void) |
608 | { | |
609 | git_config *cfg; | |
610 | const char *filename = "config-file"; | |
e579e0f7 | 611 | git_str result = GIT_STR_INIT; |
6dc55872 ET |
612 | |
613 | cl_git_mkfile(filename, ""); | |
614 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); | |
615 | cl_git_pass(git_config_set_string(cfg, "section.name", "value")); | |
616 | git_config_free(cfg); | |
617 | ||
618 | cl_git_pass(git_futils_readbuffer(&result, "config-file")); | |
619 | cl_assert_equal_s("[section]\n\tname = value\n", result.ptr); | |
620 | ||
e579e0f7 | 621 | git_str_dispose(&result); |
6dc55872 ET |
622 | } |
623 | ||
624 | void test_config_write__to_file_with_only_comment(void) | |
625 | { | |
626 | git_config *cfg; | |
627 | const char *filename = "config-file"; | |
e579e0f7 | 628 | git_str result = GIT_STR_INIT; |
6dc55872 ET |
629 | |
630 | cl_git_mkfile(filename, "\n\n"); | |
631 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); | |
632 | cl_git_pass(git_config_set_string(cfg, "section.name", "value")); | |
633 | git_config_free(cfg); | |
634 | ||
635 | cl_git_pass(git_futils_readbuffer(&result, "config-file")); | |
636 | cl_assert_equal_s("\n\n[section]\n\tname = value\n", result.ptr); | |
637 | ||
e579e0f7 | 638 | git_str_dispose(&result); |
6dc55872 | 639 | } |
7ee61b8e | 640 | |
b1667039 CMN |
641 | void test_config_write__locking(void) |
642 | { | |
36f784b5 | 643 | git_config *cfg, *cfg2; |
b1667039 | 644 | git_config_entry *entry; |
5340d63d | 645 | git_transaction *tx; |
b1667039 CMN |
646 | const char *filename = "locked-file"; |
647 | ||
648 | /* Open the config and lock it */ | |
649 | cl_git_mkfile(filename, "[section]\n\tname = value\n"); | |
36f784b5 CMN |
650 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); |
651 | cl_git_pass(git_config_get_entry(&entry, cfg, "section.name")); | |
b1667039 CMN |
652 | cl_assert_equal_s("value", entry->value); |
653 | git_config_entry_free(entry); | |
5340d63d | 654 | cl_git_pass(git_config_lock(&tx, cfg)); |
b1667039 CMN |
655 | |
656 | /* Change entries in the locked backend */ | |
36f784b5 CMN |
657 | cl_git_pass(git_config_set_string(cfg, "section.name", "other value")); |
658 | cl_git_pass(git_config_set_string(cfg, "section2.name3", "more value")); | |
b1667039 CMN |
659 | |
660 | /* We can see that the file we read from hasn't changed */ | |
36f784b5 CMN |
661 | cl_git_pass(git_config_open_ondisk(&cfg2, filename)); |
662 | cl_git_pass(git_config_get_entry(&entry, cfg2, "section.name")); | |
b1667039 CMN |
663 | cl_assert_equal_s("value", entry->value); |
664 | git_config_entry_free(entry); | |
36f784b5 CMN |
665 | cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg2, "section2.name3")); |
666 | git_config_free(cfg2); | |
b1667039 | 667 | |
36f784b5 CMN |
668 | /* And we also get the old view when we read from the locked config */ |
669 | cl_git_pass(git_config_get_entry(&entry, cfg, "section.name")); | |
670 | cl_assert_equal_s("value", entry->value); | |
671 | git_config_entry_free(entry); | |
672 | cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg, "section2.name3")); | |
673 | ||
5340d63d CMN |
674 | cl_git_pass(git_transaction_commit(tx)); |
675 | git_transaction_free(tx); | |
b1667039 CMN |
676 | |
677 | /* Now that we've unlocked it, we should see both updates */ | |
548cb334 AS |
678 | cl_git_pass(git_config_get_entry(&entry, cfg, "section.name")); |
679 | cl_assert_equal_s("other value", entry->value); | |
680 | git_config_entry_free(entry); | |
681 | cl_git_pass(git_config_get_entry(&entry, cfg, "section2.name3")); | |
682 | cl_assert_equal_s("more value", entry->value); | |
683 | git_config_entry_free(entry); | |
684 | ||
685 | git_config_free(cfg); | |
686 | ||
687 | /* We should also see the changes after reopening the config */ | |
36f784b5 CMN |
688 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); |
689 | cl_git_pass(git_config_get_entry(&entry, cfg, "section.name")); | |
b1667039 CMN |
690 | cl_assert_equal_s("other value", entry->value); |
691 | git_config_entry_free(entry); | |
36f784b5 | 692 | cl_git_pass(git_config_get_entry(&entry, cfg, "section2.name3")); |
b1667039 CMN |
693 | cl_assert_equal_s("more value", entry->value); |
694 | git_config_entry_free(entry); | |
695 | ||
36f784b5 | 696 | git_config_free(cfg); |
b1667039 | 697 | } |
e8d5df9e CMN |
698 | |
699 | void test_config_write__repeated(void) | |
700 | { | |
701 | const char *filename = "config-repeated"; | |
702 | git_config *cfg; | |
e579e0f7 | 703 | git_str result = GIT_STR_INIT; |
e8d5df9e CMN |
704 | const char *expected = "[sample \"prefix\"]\n\ |
705 | \tsetting1 = someValue1\n\ | |
706 | \tsetting2 = someValue2\n\ | |
707 | \tsetting3 = someValue3\n\ | |
708 | \tsetting4 = someValue4\n\ | |
709 | "; | |
710 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); | |
711 | cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting1", "someValue1")); | |
712 | cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting2", "someValue2")); | |
713 | cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting3", "someValue3")); | |
714 | cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting4", "someValue4")); | |
6a35e74c | 715 | git_config_free(cfg); |
e8d5df9e CMN |
716 | |
717 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); | |
718 | ||
719 | cl_git_pass(git_futils_readbuffer(&result, filename)); | |
720 | cl_assert_equal_s(expected, result.ptr); | |
e579e0f7 | 721 | git_str_dispose(&result); |
6a35e74c ET |
722 | |
723 | git_config_free(cfg); | |
e8d5df9e | 724 | } |
eae0bfdc PP |
725 | |
726 | void test_config_write__preserve_case(void) | |
727 | { | |
728 | const char *filename = "config-preserve-case"; | |
729 | git_config *cfg; | |
e579e0f7 | 730 | git_str result = GIT_STR_INIT; |
eae0bfdc PP |
731 | const char *expected = "[sOMe]\n" \ |
732 | "\tThInG = foo\n" \ | |
733 | "\tOtheR = thing\n"; | |
734 | ||
735 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); | |
736 | cl_git_pass(git_config_set_string(cfg, "sOMe.ThInG", "foo")); | |
737 | cl_git_pass(git_config_set_string(cfg, "SomE.OtheR", "thing")); | |
738 | git_config_free(cfg); | |
739 | ||
740 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); | |
741 | ||
742 | cl_git_pass(git_futils_readbuffer(&result, filename)); | |
743 | cl_assert_equal_s(expected, result.ptr); | |
e579e0f7 MB |
744 | git_str_dispose(&result); |
745 | ||
746 | git_config_free(cfg); | |
747 | } | |
748 | ||
749 | void test_config_write__write_config_file_with_multi_line_value(void) | |
750 | { | |
751 | git_config* cfg; | |
752 | git_buf buf = GIT_BUF_INIT; | |
753 | ||
754 | cl_git_pass(git_config_open_ondisk(&cfg, "config22")); | |
755 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "alias.m")); | |
756 | cl_assert_equal_s("cmd ;; ;; bar", buf.ptr); | |
757 | cl_git_pass(git_config_set_string(cfg, "sOMe.ThInG", "foo")); | |
758 | git_buf_dispose(&buf); | |
759 | cl_git_pass(git_config_get_string_buf(&buf, cfg, "alias.m")); | |
760 | cl_assert_equal_s("cmd ;; ;; bar", buf.ptr); | |
761 | git_buf_dispose(&buf); | |
eae0bfdc PP |
762 | |
763 | git_config_free(cfg); | |
764 | } |