]> git.proxmox.com Git - libgit2.git/blob - tests/config/write.c
9d8c3fe94957bc7786996cd15c3e6a885fb3222c
[libgit2.git] / tests / config / write.c
1 #include "clar_libgit2.h"
2 #include "futils.h"
3 #include "git2/sys/config.h"
4 #include "config.h"
5
6 void test_config_write__initialize(void)
7 {
8 cl_fixture_sandbox("config/config9");
9 cl_fixture_sandbox("config/config15");
10 cl_fixture_sandbox("config/config17");
11 cl_fixture_sandbox("config/config22");
12 }
13
14 void test_config_write__cleanup(void)
15 {
16 cl_fixture_cleanup("config9");
17 cl_fixture_cleanup("config15");
18 cl_fixture_cleanup("config17");
19 cl_fixture_cleanup("config22");
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, NULL, 0));
97 cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
98 GIT_CONFIG_LEVEL_GLOBAL, NULL, 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", buf.ptr);
295
296 git_buf_dispose(&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", buf.ptr);
318 git_buf_dispose(&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", buf.ptr);
324 git_buf_dispose(&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", buf.ptr);
332 git_buf_dispose(&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", buf.ptr);
338 git_buf_dispose(&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", buf.ptr);
351 git_buf_dispose(&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", buf.ptr);
357 git_buf_dispose(&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, NULL, 0));
372 cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
373 GIT_CONFIG_LEVEL_GLOBAL, NULL, 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!", buf.ptr);
395
396 git_buf_dispose(&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_dispose(&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 FOO_COMMENT \
534 "; another comment!\n"
535
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" \
543
544 #define SECTION_FOO_WITH_COMMENT SECTION_FOO FOO_COMMENT
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";
555 const char *n;
556 git_config *cfg;
557 git_str newfile = GIT_STR_INIT;
558
559 /* This config can occur after removing and re-adding the origin remote */
560 const char *file_content = SECTION_FOO_WITH_COMMENT SECTION_BAR;
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);
574 cl_assert_equal_strn("\tother = otherval\n", n, strlen("\tother = otherval\n"));
575 n += strlen("\tother = otherval\n");
576 cl_assert_equal_strn(FOO_COMMENT, n, strlen(FOO_COMMENT));
577 n += strlen(FOO_COMMENT);
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
584 git_str_dispose(&newfile);
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";
591 git_config *cfg;
592 git_str newfile = GIT_STR_INIT;
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
603 git_str_dispose(&newfile);
604 git_config_free(cfg);
605 }
606
607 void test_config_write__to_empty_file(void)
608 {
609 git_config *cfg;
610 const char *filename = "config-file";
611 git_str result = GIT_STR_INIT;
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
621 git_str_dispose(&result);
622 }
623
624 void test_config_write__to_file_with_only_comment(void)
625 {
626 git_config *cfg;
627 const char *filename = "config-file";
628 git_str result = GIT_STR_INIT;
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
638 git_str_dispose(&result);
639 }
640
641 void test_config_write__locking(void)
642 {
643 git_config *cfg, *cfg2;
644 git_config_entry *entry;
645 git_transaction *tx;
646 const char *filename = "locked-file";
647
648 /* Open the config and lock it */
649 cl_git_mkfile(filename, "[section]\n\tname = value\n");
650 cl_git_pass(git_config_open_ondisk(&cfg, filename));
651 cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
652 cl_assert_equal_s("value", entry->value);
653 git_config_entry_free(entry);
654 cl_git_pass(git_config_lock(&tx, cfg));
655
656 /* Change entries in the locked backend */
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"));
659
660 /* We can see that the file we read from hasn't changed */
661 cl_git_pass(git_config_open_ondisk(&cfg2, filename));
662 cl_git_pass(git_config_get_entry(&entry, cfg2, "section.name"));
663 cl_assert_equal_s("value", entry->value);
664 git_config_entry_free(entry);
665 cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg2, "section2.name3"));
666 git_config_free(cfg2);
667
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
674 cl_git_pass(git_transaction_commit(tx));
675 git_transaction_free(tx);
676
677 /* Now that we've unlocked it, we should see both updates */
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 */
688 cl_git_pass(git_config_open_ondisk(&cfg, filename));
689 cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
690 cl_assert_equal_s("other value", entry->value);
691 git_config_entry_free(entry);
692 cl_git_pass(git_config_get_entry(&entry, cfg, "section2.name3"));
693 cl_assert_equal_s("more value", entry->value);
694 git_config_entry_free(entry);
695
696 git_config_free(cfg);
697 }
698
699 void test_config_write__repeated(void)
700 {
701 const char *filename = "config-repeated";
702 git_config *cfg;
703 git_str result = GIT_STR_INIT;
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"));
715 git_config_free(cfg);
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);
721 git_str_dispose(&result);
722
723 git_config_free(cfg);
724 }
725
726 void test_config_write__preserve_case(void)
727 {
728 const char *filename = "config-preserve-case";
729 git_config *cfg;
730 git_str result = GIT_STR_INIT;
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);
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);
762
763 git_config_free(cfg);
764 }