]> git.proxmox.com Git - libgit2.git/blame - tests/config/write.c
Merge branch 'cmn/ignore-dir-check'
[libgit2.git] / tests / config / write.c
CommitLineData
3fd1520c 1#include "clar_libgit2.h"
9a97f49e 2#include "buffer.h"
6dc55872 3#include "fileops.h"
b1667039
CMN
4#include "git2/sys/config.h"
5#include "config_file.h"
6#include "config.h"
9462c471
VM
7
8void test_config_write__initialize(void)
9{
10 cl_fixture_sandbox("config/config9");
a1abe66a 11 cl_fixture_sandbox("config/config15");
f8ede948 12 cl_fixture_sandbox("config/config17");
9462c471
VM
13}
14
15void test_config_write__cleanup(void)
16{
17 cl_fixture_cleanup("config9");
a1abe66a 18 cl_fixture_cleanup("config15");
f8ede948 19 cl_fixture_cleanup("config17");
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",
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
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
CMN
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);
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
CMN
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);
750be86a
AR
319 git_config_free(cfg);
320
321 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
9a97f49e
CMN
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);
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
CMN
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);
67d334c1
CMN
333 git_config_free(cfg);
334
335 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
9a97f49e
CMN
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);
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
CMN
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);
67d334c1
CMN
352 git_config_free(cfg);
353
354 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
9a97f49e
CMN
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);
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
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);
9a97f49e
CMN
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));
a1abe66a 395
9a97f49e 396 git_buf_free(&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
9a97f49e 492 git_buf_free(&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
7ee61b8e
ET
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
548void test_config_write__preserves_whitespace_and_comments(void)
549{
550 const char *file_name = "config-duplicate-header";
7ee61b8e
ET
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
583void test_config_write__preserves_entry_with_name_only(void)
584{
585 const char *file_name = "config-empty-value";
7ee61b8e
ET
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
6dc55872
ET
602void 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
619void 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}
7ee61b8e 635
b1667039
CMN
636void test_config_write__locking(void)
637{
36f784b5 638 git_config *cfg, *cfg2;
b1667039 639 git_config_entry *entry;
5340d63d 640 git_transaction *tx;
b1667039
CMN
641 const char *filename = "locked-file";
642
643 /* Open the config and lock it */
644 cl_git_mkfile(filename, "[section]\n\tname = value\n");
36f784b5
CMN
645 cl_git_pass(git_config_open_ondisk(&cfg, filename));
646 cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
b1667039
CMN
647 cl_assert_equal_s("value", entry->value);
648 git_config_entry_free(entry);
5340d63d 649 cl_git_pass(git_config_lock(&tx, cfg));
b1667039
CMN
650
651 /* Change entries in the locked backend */
36f784b5
CMN
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"));
b1667039
CMN
654
655 /* We can see that the file we read from hasn't changed */
36f784b5
CMN
656 cl_git_pass(git_config_open_ondisk(&cfg2, filename));
657 cl_git_pass(git_config_get_entry(&entry, cfg2, "section.name"));
b1667039
CMN
658 cl_assert_equal_s("value", entry->value);
659 git_config_entry_free(entry);
36f784b5
CMN
660 cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg2, "section2.name3"));
661 git_config_free(cfg2);
b1667039 662
36f784b5
CMN
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
5340d63d
CMN
669 cl_git_pass(git_transaction_commit(tx));
670 git_transaction_free(tx);
b1667039
CMN
671
672 /* Now that we've unlocked it, we should see both updates */
36f784b5
CMN
673 cl_git_pass(git_config_open_ondisk(&cfg, filename));
674 cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
b1667039
CMN
675 cl_assert_equal_s("other value", entry->value);
676 git_config_entry_free(entry);
36f784b5 677 cl_git_pass(git_config_get_entry(&entry, cfg, "section2.name3"));
b1667039
CMN
678 cl_assert_equal_s("more value", entry->value);
679 git_config_entry_free(entry);
680
36f784b5 681 git_config_free(cfg);
b1667039 682}