]> git.proxmox.com Git - libgit2.git/blame - tests/config/write.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / tests / config / write.c
CommitLineData
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
6void 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
14void 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
22void 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
60void 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 */
84void 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 */
117void 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 */
155void 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
200void 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
236static 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
247void 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
283void 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
300void 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
309void 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
342void 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 361void 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
400void 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
416void 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
432void 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
465void 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
479void 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
497void 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
510void 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
552void 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
588void 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
607void 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
624void 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
641void 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
699void 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
726void 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
749void 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}