]>
Commit | Line | Data |
---|---|---|
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 | |
8 | void 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 | ||
15 | void 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 | ||
22 | void test_config_write__replace_value(void) | |
23 | { | |
24 | git_config *cfg; | |
25 | int i; | |
26 | int64_t l, expected = +9223372036854775803; | |
27 | ||
28 | /* By freeing the config, we make sure we flush the values */ | |
29 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
30 | cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); | |
31 | git_config_free(cfg); | |
32 | ||
33 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
255c38c5 | 34 | cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy")); |
9462c471 VM |
35 | cl_assert(i == 5); |
36 | git_config_free(cfg); | |
37 | ||
38 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
39 | cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1)); | |
40 | git_config_free(cfg); | |
41 | ||
42 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
43 | cl_git_pass(git_config_set_int64(cfg, "core.verylong", expected)); | |
44 | git_config_free(cfg); | |
45 | ||
46 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
255c38c5 | 47 | cl_git_pass(git_config_get_int64(&l, cfg, "core.verylong")); |
9462c471 VM |
48 | cl_assert(l == expected); |
49 | git_config_free(cfg); | |
50 | ||
51 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
255c38c5 | 52 | cl_must_fail(git_config_get_int32(&i, cfg, "core.verylong")); |
9462c471 VM |
53 | git_config_free(cfg); |
54 | ||
55 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
56 | cl_git_pass(git_config_set_int64(cfg, "core.verylong", 1)); | |
57 | git_config_free(cfg); | |
58 | } | |
59 | ||
60 | void test_config_write__delete_value(void) | |
61 | { | |
62 | git_config *cfg; | |
63 | int32_t i; | |
64 | ||
65 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
66 | cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); | |
67 | git_config_free(cfg); | |
68 | ||
69 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
54b2a37a | 70 | cl_git_pass(git_config_delete_entry(cfg, "core.dummy")); |
9462c471 VM |
71 | git_config_free(cfg); |
72 | ||
73 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
904b67e6 | 74 | cl_assert(git_config_get_int32(&i, cfg, "core.dummy") == GIT_ENOTFOUND); |
9462c471 VM |
75 | cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1)); |
76 | git_config_free(cfg); | |
77 | } | |
78 | ||
a1abe66a | 79 | /* |
80 | * At the beginning of the test: | |
81 | * - config9 has: core.dummy2=42 | |
82 | * - config15 has: core.dummy2=7 | |
83 | */ | |
84 | void test_config_write__delete_value_at_specific_level(void) | |
85 | { | |
86 | git_config *cfg, *cfg_specific; | |
87 | int32_t i; | |
88 | ||
89 | cl_git_pass(git_config_open_ondisk(&cfg, "config15")); | |
90 | cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2")); | |
91 | cl_assert(i == 7); | |
92 | git_config_free(cfg); | |
93 | ||
94 | cl_git_pass(git_config_new(&cfg)); | |
95 | cl_git_pass(git_config_add_file_ondisk(cfg, "config9", | |
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 | */ | |
117 | void test_config_write__delete_value_with_duplicate_header(void) | |
118 | { | |
f56a417d | 119 | const char *file_name = "config-duplicate-header"; |
a060cccc RRC |
120 | const char *entry_name = "remote.origin.url"; |
121 | git_config *cfg; | |
122 | git_config_entry *entry; | |
123 | ||
f56a417d RRC |
124 | /* This config can occur after removing and re-adding the origin remote */ |
125 | const char *file_content = | |
126 | "[remote \"origin\"]\n" \ | |
127 | "[branch \"master\"]\n" \ | |
128 | " remote = \"origin\"\n" \ | |
129 | "[remote \"origin\"]\n" \ | |
130 | " url = \"foo\"\n"; | |
131 | ||
132 | /* Write the test config and make sure the expected entry exists */ | |
133 | cl_git_mkfile(file_name, file_content); | |
a060cccc RRC |
134 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); |
135 | cl_git_pass(git_config_get_entry(&entry, cfg, entry_name)); | |
136 | ||
137 | /* Delete that entry */ | |
138 | cl_git_pass(git_config_delete_entry(cfg, entry_name)); | |
139 | ||
140 | /* Reopen the file and make sure the entry no longer exists */ | |
141 | git_config_entry_free(entry); | |
142 | git_config_free(cfg); | |
143 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
144 | cl_git_fail(git_config_get_entry(&entry, cfg, entry_name)); | |
145 | ||
146 | /* Cleanup */ | |
147 | git_config_entry_free(entry); | |
148 | git_config_free(cfg); | |
149 | } | |
150 | ||
5a70df94 RRC |
151 | /* |
152 | * This test exposes a bug where duplicate section headers could cause | |
153 | * config_write to add a new entry when one already exists. | |
154 | */ | |
155 | void test_config_write__add_value_with_duplicate_header(void) | |
156 | { | |
157 | const char *file_name = "config-duplicate-insert"; | |
158 | const char *entry_name = "foo.c"; | |
159 | const char *old_val = "old"; | |
160 | const char *new_val = "new"; | |
161 | const char *str; | |
162 | git_config *cfg, *snapshot; | |
163 | ||
164 | /* c = old should be replaced by c = new. | |
165 | * The bug causes c = new to be inserted under the first 'foo' header. | |
166 | */ | |
167 | const char *file_content = | |
168 | "[foo]\n" \ | |
169 | " a = b\n" \ | |
170 | "[other]\n" \ | |
171 | " a = b\n" \ | |
172 | "[foo]\n" \ | |
173 | " c = old\n"; | |
174 | ||
175 | /* Write the test config */ | |
176 | cl_git_mkfile(file_name, file_content); | |
177 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
178 | ||
179 | /* make sure the expected entry (foo.c) exists */ | |
180 | cl_git_pass(git_config_snapshot(&snapshot, cfg)); | |
181 | cl_git_pass(git_config_get_string(&str, snapshot, entry_name)); | |
182 | cl_assert_equal_s(old_val, str); | |
183 | git_config_free(snapshot); | |
184 | ||
185 | /* Try setting foo.c to something else */ | |
186 | cl_git_pass(git_config_set_string(cfg, entry_name, new_val)); | |
187 | git_config_free(cfg); | |
188 | ||
189 | /* Reopen the file and make sure the new value was set */ | |
190 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
191 | cl_git_pass(git_config_snapshot(&snapshot, cfg)); | |
192 | cl_git_pass(git_config_get_string(&str, snapshot, entry_name)); | |
193 | cl_assert_equal_s(new_val, str); | |
194 | ||
195 | /* Cleanup */ | |
196 | git_config_free(snapshot); | |
197 | git_config_free(cfg); | |
198 | } | |
199 | ||
f79c7322 ET |
200 | void test_config_write__overwrite_value_with_duplicate_header(void) |
201 | { | |
202 | const char *file_name = "config-duplicate-header"; | |
203 | const char *entry_name = "remote.origin.url"; | |
204 | git_config *cfg; | |
205 | git_config_entry *entry; | |
206 | ||
207 | /* This config can occur after removing and re-adding the origin remote */ | |
208 | const char *file_content = | |
209 | "[remote \"origin\"]\n" \ | |
210 | "[branch \"master\"]\n" \ | |
211 | " remote = \"origin\"\n" \ | |
212 | "[remote \"origin\"]\n" \ | |
213 | " url = \"foo\"\n"; | |
214 | ||
215 | /* Write the test config and make sure the expected entry exists */ | |
216 | cl_git_mkfile(file_name, file_content); | |
217 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
218 | cl_git_pass(git_config_get_entry(&entry, cfg, entry_name)); | |
219 | ||
220 | /* Update that entry */ | |
221 | cl_git_pass(git_config_set_string(cfg, entry_name, "newurl")); | |
222 | ||
223 | /* Reopen the file and make sure the entry was updated */ | |
224 | git_config_entry_free(entry); | |
225 | git_config_free(cfg); | |
226 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
227 | cl_git_pass(git_config_get_entry(&entry, cfg, entry_name)); | |
228 | ||
229 | cl_assert_equal_s("newurl", entry->value); | |
230 | ||
231 | /* Cleanup */ | |
232 | git_config_entry_free(entry); | |
233 | git_config_free(cfg); | |
234 | } | |
235 | ||
d6b7e404 ET |
236 | static int multivar_cb(const git_config_entry *entry, void *data) |
237 | { | |
238 | int *n = (int *)data; | |
239 | ||
240 | cl_assert_equal_s(entry->value, "newurl"); | |
241 | ||
242 | (*n)++; | |
243 | ||
244 | return 0; | |
245 | } | |
246 | ||
bf99390e ET |
247 | void test_config_write__overwrite_multivar_within_duplicate_header(void) |
248 | { | |
249 | const char *file_name = "config-duplicate-header"; | |
250 | const char *entry_name = "remote.origin.url"; | |
251 | git_config *cfg; | |
252 | git_config_entry *entry; | |
d6b7e404 | 253 | int n = 0; |
bf99390e ET |
254 | |
255 | /* This config can occur after removing and re-adding the origin remote */ | |
256 | const char *file_content = | |
257 | "[remote \"origin\"]\n" \ | |
258 | " url = \"bar\"\n" \ | |
259 | "[branch \"master\"]\n" \ | |
260 | " remote = \"origin\"\n" \ | |
261 | "[remote \"origin\"]\n" \ | |
262 | " url = \"foo\"\n"; | |
263 | ||
264 | /* Write the test config and make sure the expected entry exists */ | |
265 | cl_git_mkfile(file_name, file_content); | |
266 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
267 | cl_git_pass(git_config_get_entry(&entry, cfg, entry_name)); | |
268 | ||
269 | /* Update that entry */ | |
0daf998d | 270 | cl_git_pass(git_config_set_multivar(cfg, entry_name, ".*", "newurl")); |
bf99390e ET |
271 | git_config_entry_free(entry); |
272 | git_config_free(cfg); | |
bf99390e | 273 | |
d6b7e404 ET |
274 | /* Reopen the file and make sure the entry was updated */ |
275 | cl_git_pass(git_config_open_ondisk(&cfg, file_name)); | |
276 | cl_git_pass(git_config_get_multivar_foreach(cfg, entry_name, NULL, multivar_cb, &n)); | |
277 | cl_assert_equal_i(2, n); | |
bf99390e ET |
278 | |
279 | /* Cleanup */ | |
bf99390e ET |
280 | git_config_free(cfg); |
281 | } | |
282 | ||
54fef6eb CMN |
283 | void test_config_write__write_subsection(void) |
284 | { | |
285 | git_config *cfg; | |
9a97f49e | 286 | git_buf buf = GIT_BUF_INIT; |
54fef6eb CMN |
287 | |
288 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
289 | cl_git_pass(git_config_set_string(cfg, "my.own.var", "works")); | |
290 | git_config_free(cfg); | |
291 | ||
292 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
9a97f49e 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 |
300 | void test_config_write__delete_inexistent(void) |
301 | { | |
302 | git_config *cfg; | |
303 | ||
304 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
54b2a37a | 305 | cl_assert(git_config_delete_entry(cfg, "core.imaginary") == GIT_ENOTFOUND); |
9462c471 VM |
306 | git_config_free(cfg); |
307 | } | |
750be86a AR |
308 | |
309 | void test_config_write__value_containing_quotes(void) | |
310 | { | |
311 | git_config *cfg; | |
9a97f49e | 312 | git_buf buf = GIT_BUF_INIT; |
750be86a AR |
313 | |
314 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
315 | cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes")); | |
9a97f49e 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 | ||
342 | void test_config_write__escape_value(void) | |
343 | { | |
344 | git_config *cfg; | |
9a97f49e | 345 | git_buf buf = GIT_BUF_INIT; |
67d334c1 CMN |
346 | |
347 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
348 | cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes and \t")); | |
9a97f49e 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 | 361 | void test_config_write__add_value_at_specific_level(void) |
362 | { | |
363 | git_config *cfg, *cfg_specific; | |
364 | int i; | |
365 | int64_t l, expected = +9223372036854775803; | |
9a97f49e | 366 | git_buf buf = GIT_BUF_INIT; |
a1abe66a | 367 | |
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 | ||
400 | void test_config_write__add_value_at_file_with_no_clrf_at_the_end(void) | |
f8ede948 | 401 | { |
402 | git_config *cfg; | |
403 | int i; | |
404 | ||
405 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
406 | cl_git_pass(git_config_set_int32(cfg, "core.newline", 7)); | |
407 | git_config_free(cfg); | |
408 | ||
409 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
410 | cl_git_pass(git_config_get_int32(&i, cfg, "core.newline")); | |
411 | cl_assert_equal_i(7, i); | |
412 | ||
413 | git_config_free(cfg); | |
414 | } | |
48bde2f1 | 415 | |
69374869 L |
416 | void test_config_write__add_section_at_file_with_no_clrf_at_the_end(void) |
417 | { | |
418 | git_config *cfg; | |
419 | int i; | |
420 | ||
421 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
422 | cl_git_pass(git_config_set_int32(cfg, "diff.context", 10)); | |
423 | git_config_free(cfg); | |
424 | ||
425 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
426 | cl_git_pass(git_config_get_int32(&i, cfg, "diff.context")); | |
427 | cl_assert_equal_i(10, i); | |
428 | ||
429 | git_config_free(cfg); | |
430 | } | |
431 | ||
a9f7236a SS |
432 | void test_config_write__add_value_which_needs_quotes(void) |
433 | { | |
9a97f49e | 434 | git_config *cfg, *base; |
a9f7236a SS |
435 | const char* str1; |
436 | const char* str2; | |
437 | const char* str3; | |
438 | const char* str4; | |
7dd28dde | 439 | const char* str5; |
a9f7236a SS |
440 | |
441 | cl_git_pass(git_config_open_ondisk(&cfg, "config17")); | |
442 | cl_git_pass(git_config_set_string(cfg, "core.startwithspace", " Something")); | |
443 | cl_git_pass(git_config_set_string(cfg, "core.endwithspace", "Something ")); | |
444 | cl_git_pass(git_config_set_string(cfg, "core.containscommentchar1", "some#thing")); | |
445 | cl_git_pass(git_config_set_string(cfg, "core.containscommentchar2", "some;thing")); | |
7dd28dde | 446 | cl_git_pass(git_config_set_string(cfg, "core.startwhithsapceandcontainsdoublequote", " some\"thing")); |
a9f7236a SS |
447 | git_config_free(cfg); |
448 | ||
9a97f49e CMN |
449 | cl_git_pass(git_config_open_ondisk(&base, "config17")); |
450 | cl_git_pass(git_config_snapshot(&cfg, base)); | |
a9f7236a SS |
451 | cl_git_pass(git_config_get_string(&str1, cfg, "core.startwithspace")); |
452 | cl_assert_equal_s(" Something", str1); | |
453 | cl_git_pass(git_config_get_string(&str2, cfg, "core.endwithspace")); | |
454 | cl_assert_equal_s("Something ", str2); | |
455 | cl_git_pass(git_config_get_string(&str3, cfg, "core.containscommentchar1")); | |
456 | cl_assert_equal_s("some#thing", str3); | |
457 | cl_git_pass(git_config_get_string(&str4, cfg, "core.containscommentchar2")); | |
458 | cl_assert_equal_s("some;thing", str4); | |
7dd28dde SS |
459 | cl_git_pass(git_config_get_string(&str5, cfg, "core.startwhithsapceandcontainsdoublequote")); |
460 | cl_assert_equal_s(" some\"thing", str5); | |
a9f7236a | 461 | git_config_free(cfg); |
9a97f49e | 462 | git_config_free(base); |
a9f7236a SS |
463 | } |
464 | ||
48bde2f1 CMN |
465 | void test_config_write__can_set_a_value_to_NULL(void) |
466 | { | |
467 | git_repository *repository; | |
468 | git_config *config; | |
469 | ||
470 | repository = cl_git_sandbox_init("testrepo.git"); | |
471 | ||
472 | cl_git_pass(git_repository_config(&config, repository)); | |
473 | cl_git_fail(git_config_set_string(config, "a.b.c", NULL)); | |
474 | git_config_free(config); | |
475 | ||
476 | cl_git_sandbox_cleanup(); | |
477 | } | |
c57f6682 NV |
478 | |
479 | void test_config_write__can_set_an_empty_value(void) | |
480 | { | |
481 | git_repository *repository; | |
482 | git_config *config; | |
9a97f49e | 483 | git_buf buf = {0}; |
c57f6682 NV |
484 | |
485 | repository = cl_git_sandbox_init("testrepo.git"); | |
486 | cl_git_pass(git_repository_config(&config, repository)); | |
487 | ||
488 | cl_git_pass(git_config_set_string(config, "core.somevar", "")); | |
9a97f49e CMN |
489 | cl_git_pass(git_config_get_string_buf(&buf, config, "core.somevar")); |
490 | cl_assert_equal_s("", buf.ptr); | |
c57f6682 | 491 | |
9a97f49e | 492 | git_buf_free(&buf); |
c57f6682 NV |
493 | git_config_free(config); |
494 | cl_git_sandbox_cleanup(); | |
495 | } | |
e8162fd0 | 496 | |
497 | void test_config_write__updating_a_locked_config_file_returns_ELOCKED(void) | |
498 | { | |
499 | git_config *cfg; | |
500 | ||
501 | cl_git_pass(git_config_open_ondisk(&cfg, "config9")); | |
502 | ||
503 | cl_git_mkfile("config9.lock", "[core]\n"); | |
504 | ||
505 | cl_git_fail_with(git_config_set_string(cfg, "core.dump", "boom"), GIT_ELOCKED); | |
506 | ||
507 | git_config_free(cfg); | |
508 | } | |
96869a4e | 509 | |
36913b8c CMN |
510 | void test_config_write__outside_change(void) |
511 | { | |
512 | int32_t tmp; | |
513 | git_config *cfg; | |
514 | const char *filename = "config-ext-change"; | |
515 | ||
516 | cl_git_mkfile(filename, "[old]\nvalue = 5\n"); | |
517 | ||
518 | cl_git_pass(git_config_open_ondisk(&cfg, filename)); | |
519 | ||
520 | cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value")); | |
521 | ||
522 | /* Change the value on the file itself (simulate external process) */ | |
523 | cl_git_mkfile(filename, "[old]\nvalue = 6\n"); | |
524 | ||
525 | cl_git_pass(git_config_set_int32(cfg, "new.value", 7)); | |
526 | ||
527 | cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value")); | |
eaf37034 | 528 | cl_assert_equal_i(6, tmp); |
36913b8c | 529 | |
36913b8c CMN |
530 | git_config_free(cfg); |
531 | } | |
6dc55872 | 532 | |
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 | ||
548 | void 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 | ||
583 | void 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 |
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 | } | |
7ee61b8e | 635 | |
b1667039 CMN |
636 | void 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 | } |