]> git.proxmox.com Git - libgit2.git/blob - tests/config/write.c
Merge pull request #3059 from libgit2/cmn/negotiation-notify
[libgit2.git] / tests / config / write.c
1 #include "clar_libgit2.h"
2 #include "buffer.h"
3 #include "fileops.h"
4
5 void test_config_write__initialize(void)
6 {
7 cl_fixture_sandbox("config/config9");
8 cl_fixture_sandbox("config/config15");
9 cl_fixture_sandbox("config/config17");
10 }
11
12 void test_config_write__cleanup(void)
13 {
14 cl_fixture_cleanup("config9");
15 cl_fixture_cleanup("config15");
16 cl_fixture_cleanup("config17");
17 }
18
19 void test_config_write__replace_value(void)
20 {
21 git_config *cfg;
22 int i;
23 int64_t l, expected = +9223372036854775803;
24
25 /* By freeing the config, we make sure we flush the values */
26 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
27 cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5));
28 git_config_free(cfg);
29
30 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
31 cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy"));
32 cl_assert(i == 5);
33 git_config_free(cfg);
34
35 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
36 cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1));
37 git_config_free(cfg);
38
39 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
40 cl_git_pass(git_config_set_int64(cfg, "core.verylong", expected));
41 git_config_free(cfg);
42
43 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
44 cl_git_pass(git_config_get_int64(&l, cfg, "core.verylong"));
45 cl_assert(l == expected);
46 git_config_free(cfg);
47
48 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
49 cl_must_fail(git_config_get_int32(&i, cfg, "core.verylong"));
50 git_config_free(cfg);
51
52 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
53 cl_git_pass(git_config_set_int64(cfg, "core.verylong", 1));
54 git_config_free(cfg);
55 }
56
57 void test_config_write__delete_value(void)
58 {
59 git_config *cfg;
60 int32_t i;
61
62 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
63 cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5));
64 git_config_free(cfg);
65
66 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
67 cl_git_pass(git_config_delete_entry(cfg, "core.dummy"));
68 git_config_free(cfg);
69
70 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
71 cl_assert(git_config_get_int32(&i, cfg, "core.dummy") == GIT_ENOTFOUND);
72 cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1));
73 git_config_free(cfg);
74 }
75
76 /*
77 * At the beginning of the test:
78 * - config9 has: core.dummy2=42
79 * - config15 has: core.dummy2=7
80 */
81 void test_config_write__delete_value_at_specific_level(void)
82 {
83 git_config *cfg, *cfg_specific;
84 int32_t i;
85
86 cl_git_pass(git_config_open_ondisk(&cfg, "config15"));
87 cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2"));
88 cl_assert(i == 7);
89 git_config_free(cfg);
90
91 cl_git_pass(git_config_new(&cfg));
92 cl_git_pass(git_config_add_file_ondisk(cfg, "config9",
93 GIT_CONFIG_LEVEL_LOCAL, 0));
94 cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
95 GIT_CONFIG_LEVEL_GLOBAL, 0));
96
97 cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL));
98
99 cl_git_pass(git_config_delete_entry(cfg_specific, "core.dummy2"));
100 git_config_free(cfg);
101
102 cl_git_pass(git_config_open_ondisk(&cfg, "config15"));
103 cl_assert(git_config_get_int32(&i, cfg, "core.dummy2") == GIT_ENOTFOUND);
104 cl_git_pass(git_config_set_int32(cfg, "core.dummy2", 7));
105
106 git_config_free(cfg_specific);
107 git_config_free(cfg);
108 }
109
110 /*
111 * This test exposes a bug where duplicate empty section headers could prevent
112 * deletion of config entries.
113 */
114 void test_config_write__delete_value_with_duplicate_header(void)
115 {
116 const char *file_name = "config-duplicate-header";
117 const char *entry_name = "remote.origin.url";
118 git_config *cfg;
119 git_config_entry *entry;
120
121 /* This config can occur after removing and re-adding the origin remote */
122 const char *file_content =
123 "[remote \"origin\"]\n" \
124 "[branch \"master\"]\n" \
125 " remote = \"origin\"\n" \
126 "[remote \"origin\"]\n" \
127 " url = \"foo\"\n";
128
129 /* Write the test config and make sure the expected entry exists */
130 cl_git_mkfile(file_name, file_content);
131 cl_git_pass(git_config_open_ondisk(&cfg, file_name));
132 cl_git_pass(git_config_get_entry(&entry, cfg, entry_name));
133
134 /* Delete that entry */
135 cl_git_pass(git_config_delete_entry(cfg, entry_name));
136
137 /* Reopen the file and make sure the entry no longer exists */
138 git_config_entry_free(entry);
139 git_config_free(cfg);
140 cl_git_pass(git_config_open_ondisk(&cfg, file_name));
141 cl_git_fail(git_config_get_entry(&entry, cfg, entry_name));
142
143 /* Cleanup */
144 git_config_entry_free(entry);
145 git_config_free(cfg);
146 }
147
148 void test_config_write__write_subsection(void)
149 {
150 git_config *cfg;
151 git_buf buf = GIT_BUF_INIT;
152
153 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
154 cl_git_pass(git_config_set_string(cfg, "my.own.var", "works"));
155 git_config_free(cfg);
156
157 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
158 cl_git_pass(git_config_get_string_buf(&buf, cfg, "my.own.var"));
159 cl_assert_equal_s("works", git_buf_cstr(&buf));
160
161 git_buf_free(&buf);
162 git_config_free(cfg);
163 }
164
165 void test_config_write__delete_inexistent(void)
166 {
167 git_config *cfg;
168
169 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
170 cl_assert(git_config_delete_entry(cfg, "core.imaginary") == GIT_ENOTFOUND);
171 git_config_free(cfg);
172 }
173
174 void test_config_write__value_containing_quotes(void)
175 {
176 git_config *cfg;
177 git_buf buf = GIT_BUF_INIT;
178
179 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
180 cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes"));
181 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
182 cl_assert_equal_s("this \"has\" quotes", git_buf_cstr(&buf));
183 git_buf_clear(&buf);
184 git_config_free(cfg);
185
186 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
187 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
188 cl_assert_equal_s("this \"has\" quotes", git_buf_cstr(&buf));
189 git_buf_clear(&buf);
190 git_config_free(cfg);
191
192 /* The code path for values that already exist is different, check that one as well */
193 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
194 cl_git_pass(git_config_set_string(cfg, "core.somevar", "this also \"has\" quotes"));
195 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
196 cl_assert_equal_s("this also \"has\" quotes", git_buf_cstr(&buf));
197 git_buf_clear(&buf);
198 git_config_free(cfg);
199
200 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
201 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
202 cl_assert_equal_s("this also \"has\" quotes", git_buf_cstr(&buf));
203 git_buf_free(&buf);
204 git_config_free(cfg);
205 }
206
207 void test_config_write__escape_value(void)
208 {
209 git_config *cfg;
210 git_buf buf = GIT_BUF_INIT;
211
212 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
213 cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes and \t"));
214 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
215 cl_assert_equal_s("this \"has\" quotes and \t", git_buf_cstr(&buf));
216 git_buf_clear(&buf);
217 git_config_free(cfg);
218
219 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
220 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
221 cl_assert_equal_s("this \"has\" quotes and \t", git_buf_cstr(&buf));
222 git_buf_free(&buf);
223 git_config_free(cfg);
224 }
225
226 void test_config_write__add_value_at_specific_level(void)
227 {
228 git_config *cfg, *cfg_specific;
229 int i;
230 int64_t l, expected = +9223372036854775803;
231 git_buf buf = GIT_BUF_INIT;
232
233 // open config15 as global level config file
234 cl_git_pass(git_config_new(&cfg));
235 cl_git_pass(git_config_add_file_ondisk(cfg, "config9",
236 GIT_CONFIG_LEVEL_LOCAL, 0));
237 cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
238 GIT_CONFIG_LEVEL_GLOBAL, 0));
239
240 cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL));
241
242 cl_git_pass(git_config_set_int32(cfg_specific, "core.int32global", 28));
243 cl_git_pass(git_config_set_int64(cfg_specific, "core.int64global", expected));
244 cl_git_pass(git_config_set_bool(cfg_specific, "core.boolglobal", true));
245 cl_git_pass(git_config_set_string(cfg_specific, "core.stringglobal", "I'm a global config value!"));
246 git_config_free(cfg_specific);
247 git_config_free(cfg);
248
249 // open config15 as local level config file
250 cl_git_pass(git_config_open_ondisk(&cfg, "config15"));
251
252 cl_git_pass(git_config_get_int32(&i, cfg, "core.int32global"));
253 cl_assert_equal_i(28, i);
254 cl_git_pass(git_config_get_int64(&l, cfg, "core.int64global"));
255 cl_assert(l == expected);
256 cl_git_pass(git_config_get_bool(&i, cfg, "core.boolglobal"));
257 cl_assert_equal_b(true, i);
258 cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.stringglobal"));
259 cl_assert_equal_s("I'm a global config value!", git_buf_cstr(&buf));
260
261 git_buf_free(&buf);
262 git_config_free(cfg);
263 }
264
265 void test_config_write__add_value_at_file_with_no_clrf_at_the_end(void)
266 {
267 git_config *cfg;
268 int i;
269
270 cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
271 cl_git_pass(git_config_set_int32(cfg, "core.newline", 7));
272 git_config_free(cfg);
273
274 cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
275 cl_git_pass(git_config_get_int32(&i, cfg, "core.newline"));
276 cl_assert_equal_i(7, i);
277
278 git_config_free(cfg);
279 }
280
281 void test_config_write__add_section_at_file_with_no_clrf_at_the_end(void)
282 {
283 git_config *cfg;
284 int i;
285
286 cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
287 cl_git_pass(git_config_set_int32(cfg, "diff.context", 10));
288 git_config_free(cfg);
289
290 cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
291 cl_git_pass(git_config_get_int32(&i, cfg, "diff.context"));
292 cl_assert_equal_i(10, i);
293
294 git_config_free(cfg);
295 }
296
297 void test_config_write__add_value_which_needs_quotes(void)
298 {
299 git_config *cfg, *base;
300 const char* str1;
301 const char* str2;
302 const char* str3;
303 const char* str4;
304 const char* str5;
305
306 cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
307 cl_git_pass(git_config_set_string(cfg, "core.startwithspace", " Something"));
308 cl_git_pass(git_config_set_string(cfg, "core.endwithspace", "Something "));
309 cl_git_pass(git_config_set_string(cfg, "core.containscommentchar1", "some#thing"));
310 cl_git_pass(git_config_set_string(cfg, "core.containscommentchar2", "some;thing"));
311 cl_git_pass(git_config_set_string(cfg, "core.startwhithsapceandcontainsdoublequote", " some\"thing"));
312 git_config_free(cfg);
313
314 cl_git_pass(git_config_open_ondisk(&base, "config17"));
315 cl_git_pass(git_config_snapshot(&cfg, base));
316 cl_git_pass(git_config_get_string(&str1, cfg, "core.startwithspace"));
317 cl_assert_equal_s(" Something", str1);
318 cl_git_pass(git_config_get_string(&str2, cfg, "core.endwithspace"));
319 cl_assert_equal_s("Something ", str2);
320 cl_git_pass(git_config_get_string(&str3, cfg, "core.containscommentchar1"));
321 cl_assert_equal_s("some#thing", str3);
322 cl_git_pass(git_config_get_string(&str4, cfg, "core.containscommentchar2"));
323 cl_assert_equal_s("some;thing", str4);
324 cl_git_pass(git_config_get_string(&str5, cfg, "core.startwhithsapceandcontainsdoublequote"));
325 cl_assert_equal_s(" some\"thing", str5);
326 git_config_free(cfg);
327 git_config_free(base);
328 }
329
330 void test_config_write__can_set_a_value_to_NULL(void)
331 {
332 git_repository *repository;
333 git_config *config;
334
335 repository = cl_git_sandbox_init("testrepo.git");
336
337 cl_git_pass(git_repository_config(&config, repository));
338 cl_git_fail(git_config_set_string(config, "a.b.c", NULL));
339 git_config_free(config);
340
341 cl_git_sandbox_cleanup();
342 }
343
344 void test_config_write__can_set_an_empty_value(void)
345 {
346 git_repository *repository;
347 git_config *config;
348 git_buf buf = {0};
349
350 repository = cl_git_sandbox_init("testrepo.git");
351 cl_git_pass(git_repository_config(&config, repository));
352
353 cl_git_pass(git_config_set_string(config, "core.somevar", ""));
354 cl_git_pass(git_config_get_string_buf(&buf, config, "core.somevar"));
355 cl_assert_equal_s("", buf.ptr);
356
357 git_buf_free(&buf);
358 git_config_free(config);
359 cl_git_sandbox_cleanup();
360 }
361
362 void test_config_write__updating_a_locked_config_file_returns_ELOCKED(void)
363 {
364 git_config *cfg;
365
366 cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
367
368 cl_git_mkfile("config9.lock", "[core]\n");
369
370 cl_git_fail_with(git_config_set_string(cfg, "core.dump", "boom"), GIT_ELOCKED);
371
372 git_config_free(cfg);
373 }
374
375 void test_config_write__outside_change(void)
376 {
377 int32_t tmp;
378 git_config *cfg;
379 const char *filename = "config-ext-change";
380
381 cl_git_mkfile(filename, "[old]\nvalue = 5\n");
382
383 cl_git_pass(git_config_open_ondisk(&cfg, filename));
384
385 cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value"));
386
387 /* Change the value on the file itself (simulate external process) */
388 cl_git_mkfile(filename, "[old]\nvalue = 6\n");
389
390 cl_git_pass(git_config_set_int32(cfg, "new.value", 7));
391
392 cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value"));
393 cl_assert_equal_i(6, tmp);
394
395 git_config_free(cfg);
396 }
397
398 void test_config_write__to_empty_file(void)
399 {
400 git_config *cfg;
401 const char *filename = "config-file";
402 git_buf result = GIT_BUF_INIT;
403
404 cl_git_mkfile(filename, "");
405 cl_git_pass(git_config_open_ondisk(&cfg, filename));
406 cl_git_pass(git_config_set_string(cfg, "section.name", "value"));
407 git_config_free(cfg);
408
409 cl_git_pass(git_futils_readbuffer(&result, "config-file"));
410 cl_assert_equal_s("[section]\n\tname = value\n", result.ptr);
411
412 git_buf_free(&result);
413 }
414
415 void test_config_write__to_file_with_only_comment(void)
416 {
417 git_config *cfg;
418 const char *filename = "config-file";
419 git_buf result = GIT_BUF_INIT;
420
421 cl_git_mkfile(filename, "\n\n");
422 cl_git_pass(git_config_open_ondisk(&cfg, filename));
423 cl_git_pass(git_config_set_string(cfg, "section.name", "value"));
424 git_config_free(cfg);
425
426 cl_git_pass(git_futils_readbuffer(&result, "config-file"));
427 cl_assert_equal_s("\n\n[section]\n\tname = value\n", result.ptr);
428
429 git_buf_free(&result);
430 }