]> git.proxmox.com Git - libgit2.git/blob - tests/config/write.c
Merge pull request #3418 from DimStar77/master
[libgit2.git] / tests / config / write.c
1 #include "clar_libgit2.h"
2 #include "buffer.h"
3 #include "fileops.h"
4 #include "git2/sys/config.h"
5 #include "config_file.h"
6 #include "config.h"
7
8 void test_config_write__initialize(void)
9 {
10 cl_fixture_sandbox("config/config9");
11 cl_fixture_sandbox("config/config15");
12 cl_fixture_sandbox("config/config17");
13 }
14
15 void test_config_write__cleanup(void)
16 {
17 cl_fixture_cleanup("config9");
18 cl_fixture_cleanup("config15");
19 cl_fixture_cleanup("config17");
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"));
34 cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy"));
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"));
47 cl_git_pass(git_config_get_int64(&l, cfg, "core.verylong"));
48 cl_assert(l == expected);
49 git_config_free(cfg);
50
51 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
52 cl_must_fail(git_config_get_int32(&i, cfg, "core.verylong"));
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"));
70 cl_git_pass(git_config_delete_entry(cfg, "core.dummy"));
71 git_config_free(cfg);
72
73 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
74 cl_assert(git_config_get_int32(&i, cfg, "core.dummy") == GIT_ENOTFOUND);
75 cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1));
76 git_config_free(cfg);
77 }
78
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",
96 GIT_CONFIG_LEVEL_LOCAL, 0));
97 cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
98 GIT_CONFIG_LEVEL_GLOBAL, 0));
99
100 cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL));
101
102 cl_git_pass(git_config_delete_entry(cfg_specific, "core.dummy2"));
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
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 {
119 const char *file_name = "config-duplicate-header";
120 const char *entry_name = "remote.origin.url";
121 git_config *cfg;
122 git_config_entry *entry;
123
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);
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
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
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
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
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;
253 int n = 0;
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 */
270 cl_git_pass(git_config_set_multivar(cfg, entry_name, ".*", "newurl"));
271 git_config_entry_free(entry);
272 git_config_free(cfg);
273
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);
278
279 /* Cleanup */
280 git_config_free(cfg);
281 }
282
283 void test_config_write__write_subsection(void)
284 {
285 git_config *cfg;
286 git_buf buf = GIT_BUF_INIT;
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"));
293 cl_git_pass(git_config_get_string_buf(&buf, cfg, "my.own.var"));
294 cl_assert_equal_s("works", git_buf_cstr(&buf));
295
296 git_buf_free(&buf);
297 git_config_free(cfg);
298 }
299
300 void test_config_write__delete_inexistent(void)
301 {
302 git_config *cfg;
303
304 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
305 cl_assert(git_config_delete_entry(cfg, "core.imaginary") == GIT_ENOTFOUND);
306 git_config_free(cfg);
307 }
308
309 void test_config_write__value_containing_quotes(void)
310 {
311 git_config *cfg;
312 git_buf buf = GIT_BUF_INIT;
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"));
316 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
317 cl_assert_equal_s("this \"has\" quotes", git_buf_cstr(&buf));
318 git_buf_clear(&buf);
319 git_config_free(cfg);
320
321 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
322 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
323 cl_assert_equal_s("this \"has\" quotes", git_buf_cstr(&buf));
324 git_buf_clear(&buf);
325 git_config_free(cfg);
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"));
330 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
331 cl_assert_equal_s("this also \"has\" quotes", git_buf_cstr(&buf));
332 git_buf_clear(&buf);
333 git_config_free(cfg);
334
335 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
336 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
337 cl_assert_equal_s("this also \"has\" quotes", git_buf_cstr(&buf));
338 git_buf_free(&buf);
339 git_config_free(cfg);
340 }
341
342 void test_config_write__escape_value(void)
343 {
344 git_config *cfg;
345 git_buf buf = GIT_BUF_INIT;
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"));
349 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
350 cl_assert_equal_s("this \"has\" quotes and \t", git_buf_cstr(&buf));
351 git_buf_clear(&buf);
352 git_config_free(cfg);
353
354 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
355 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
356 cl_assert_equal_s("this \"has\" quotes and \t", git_buf_cstr(&buf));
357 git_buf_free(&buf);
358 git_config_free(cfg);
359 }
360
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;
366 git_buf buf = GIT_BUF_INIT;
367
368 // open config15 as global level config file
369 cl_git_pass(git_config_new(&cfg));
370 cl_git_pass(git_config_add_file_ondisk(cfg, "config9",
371 GIT_CONFIG_LEVEL_LOCAL, 0));
372 cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
373 GIT_CONFIG_LEVEL_GLOBAL, 0));
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
384 // open config15 as local level config file
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);
393 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.stringglobal"));
394 cl_assert_equal_s("I'm a global config value!", git_buf_cstr(&buf));
395
396 git_buf_free(&buf);
397 git_config_free(cfg);
398 }
399
400 void test_config_write__add_value_at_file_with_no_clrf_at_the_end(void)
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 }
415
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
432 void test_config_write__add_value_which_needs_quotes(void)
433 {
434 git_config *cfg, *base;
435 const char* str1;
436 const char* str2;
437 const char* str3;
438 const char* str4;
439 const char* str5;
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"));
446 cl_git_pass(git_config_set_string(cfg, "core.startwhithsapceandcontainsdoublequote", " some\"thing"));
447 git_config_free(cfg);
448
449 cl_git_pass(git_config_open_ondisk(&base, "config17"));
450 cl_git_pass(git_config_snapshot(&cfg, base));
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);
459 cl_git_pass(git_config_get_string(&str5, cfg, "core.startwhithsapceandcontainsdoublequote"));
460 cl_assert_equal_s(" some\"thing", str5);
461 git_config_free(cfg);
462 git_config_free(base);
463 }
464
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 }
478
479 void test_config_write__can_set_an_empty_value(void)
480 {
481 git_repository *repository;
482 git_config *config;
483 git_buf buf = {0};
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", ""));
489 cl_git_pass(git_config_get_string_buf(&buf, config, "core.somevar"));
490 cl_assert_equal_s("", buf.ptr);
491
492 git_buf_free(&buf);
493 git_config_free(config);
494 cl_git_sandbox_cleanup();
495 }
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 }
509
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"));
528 cl_assert_equal_i(6, tmp);
529
530 git_config_free(cfg);
531 }
532
533 #define SECTION_FOO \
534 "\n" \
535 " \n" \
536 " [section \"foo\"] \n" \
537 " # here's a comment\n" \
538 "\tname = \"value\"\n" \
539 " name2 = \"value2\"\n" \
540 "; another comment!\n"
541
542 #define SECTION_BAR \
543 "[section \"bar\"]\t\n" \
544 "\t \n" \
545 " barname=\"value\"\n"
546
547
548 void test_config_write__preserves_whitespace_and_comments(void)
549 {
550 const char *file_name = "config-duplicate-header";
551 const char *n;
552 git_config *cfg;
553 git_buf newfile = GIT_BUF_INIT;
554
555 /* This config can occur after removing and re-adding the origin remote */
556 const char *file_content = SECTION_FOO SECTION_BAR;
557
558 /* Write the test config and make sure the expected entry exists */
559 cl_git_mkfile(file_name, file_content);
560 cl_git_pass(git_config_open_ondisk(&cfg, file_name));
561 cl_git_pass(git_config_set_string(cfg, "section.foo.other", "otherval"));
562 cl_git_pass(git_config_set_string(cfg, "newsection.newname", "new_value"));
563
564 /* Ensure that we didn't needlessly mangle the config file */
565 cl_git_pass(git_futils_readbuffer(&newfile, file_name));
566 n = newfile.ptr;
567
568 cl_assert_equal_strn(SECTION_FOO, n, strlen(SECTION_FOO));
569 n += strlen(SECTION_FOO);
570
571 cl_assert_equal_strn("\tother = otherval\n", n, strlen("\tother = otherval\n"));
572 n += strlen("\tother = otherval\n");
573
574 cl_assert_equal_strn(SECTION_BAR, n, strlen(SECTION_BAR));
575 n += strlen(SECTION_BAR);
576
577 cl_assert_equal_s("[newsection]\n\tnewname = new_value\n", n);
578
579 git_buf_free(&newfile);
580 git_config_free(cfg);
581 }
582
583 void test_config_write__preserves_entry_with_name_only(void)
584 {
585 const char *file_name = "config-empty-value";
586 git_config *cfg;
587 git_buf newfile = GIT_BUF_INIT;
588
589 /* Write the test config and make sure the expected entry exists */
590 cl_git_mkfile(file_name, "[section \"foo\"]\n\tname\n");
591 cl_git_pass(git_config_open_ondisk(&cfg, file_name));
592 cl_git_pass(git_config_set_string(cfg, "newsection.newname", "new_value"));
593 cl_git_pass(git_config_set_string(cfg, "section.foo.other", "otherval"));
594
595 cl_git_pass(git_futils_readbuffer(&newfile, file_name));
596 cl_assert_equal_s("[section \"foo\"]\n\tname\n\tother = otherval\n[newsection]\n\tnewname = new_value\n", newfile.ptr);
597
598 git_buf_free(&newfile);
599 git_config_free(cfg);
600 }
601
602 void test_config_write__to_empty_file(void)
603 {
604 git_config *cfg;
605 const char *filename = "config-file";
606 git_buf result = GIT_BUF_INIT;
607
608 cl_git_mkfile(filename, "");
609 cl_git_pass(git_config_open_ondisk(&cfg, filename));
610 cl_git_pass(git_config_set_string(cfg, "section.name", "value"));
611 git_config_free(cfg);
612
613 cl_git_pass(git_futils_readbuffer(&result, "config-file"));
614 cl_assert_equal_s("[section]\n\tname = value\n", result.ptr);
615
616 git_buf_free(&result);
617 }
618
619 void test_config_write__to_file_with_only_comment(void)
620 {
621 git_config *cfg;
622 const char *filename = "config-file";
623 git_buf result = GIT_BUF_INIT;
624
625 cl_git_mkfile(filename, "\n\n");
626 cl_git_pass(git_config_open_ondisk(&cfg, filename));
627 cl_git_pass(git_config_set_string(cfg, "section.name", "value"));
628 git_config_free(cfg);
629
630 cl_git_pass(git_futils_readbuffer(&result, "config-file"));
631 cl_assert_equal_s("\n\n[section]\n\tname = value\n", result.ptr);
632
633 git_buf_free(&result);
634 }
635
636 void test_config_write__locking(void)
637 {
638 git_config *cfg, *cfg2;
639 git_config_entry *entry;
640 git_transaction *tx;
641 const char *filename = "locked-file";
642
643 /* Open the config and lock it */
644 cl_git_mkfile(filename, "[section]\n\tname = value\n");
645 cl_git_pass(git_config_open_ondisk(&cfg, filename));
646 cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
647 cl_assert_equal_s("value", entry->value);
648 git_config_entry_free(entry);
649 cl_git_pass(git_config_lock(&tx, cfg));
650
651 /* Change entries in the locked backend */
652 cl_git_pass(git_config_set_string(cfg, "section.name", "other value"));
653 cl_git_pass(git_config_set_string(cfg, "section2.name3", "more value"));
654
655 /* We can see that the file we read from hasn't changed */
656 cl_git_pass(git_config_open_ondisk(&cfg2, filename));
657 cl_git_pass(git_config_get_entry(&entry, cfg2, "section.name"));
658 cl_assert_equal_s("value", entry->value);
659 git_config_entry_free(entry);
660 cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg2, "section2.name3"));
661 git_config_free(cfg2);
662
663 /* And we also get the old view when we read from the locked config */
664 cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
665 cl_assert_equal_s("value", entry->value);
666 git_config_entry_free(entry);
667 cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg, "section2.name3"));
668
669 cl_git_pass(git_transaction_commit(tx));
670 git_transaction_free(tx);
671
672 /* Now that we've unlocked it, we should see both updates */
673 cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
674 cl_assert_equal_s("other value", entry->value);
675 git_config_entry_free(entry);
676 cl_git_pass(git_config_get_entry(&entry, cfg, "section2.name3"));
677 cl_assert_equal_s("more value", entry->value);
678 git_config_entry_free(entry);
679
680 git_config_free(cfg);
681
682 /* We should also see the changes after reopening the config */
683 cl_git_pass(git_config_open_ondisk(&cfg, filename));
684 cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
685 cl_assert_equal_s("other value", entry->value);
686 git_config_entry_free(entry);
687 cl_git_pass(git_config_get_entry(&entry, cfg, "section2.name3"));
688 cl_assert_equal_s("more value", entry->value);
689 git_config_entry_free(entry);
690
691 git_config_free(cfg);
692 }