1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.eclipse.jgit.lib;
17
18 import static java.nio.charset.StandardCharsets.UTF_8;
19 import static java.util.concurrent.TimeUnit.DAYS;
20 import static java.util.concurrent.TimeUnit.HOURS;
21 import static java.util.concurrent.TimeUnit.MICROSECONDS;
22 import static java.util.concurrent.TimeUnit.MILLISECONDS;
23 import static java.util.concurrent.TimeUnit.MINUTES;
24 import static java.util.concurrent.TimeUnit.NANOSECONDS;
25 import static java.util.concurrent.TimeUnit.SECONDS;
26 import static org.eclipse.jgit.util.FileUtils.pathToString;
27 import static org.junit.Assert.assertArrayEquals;
28 import static org.junit.Assert.assertEquals;
29 import static org.junit.Assert.assertFalse;
30 import static org.junit.Assert.assertNull;
31 import static org.junit.Assert.assertSame;
32 import static org.junit.Assert.assertThrows;
33 import static org.junit.Assert.assertTrue;
34 import static org.junit.Assert.fail;
35
36 import java.io.File;
37 import java.io.IOException;
38 import java.nio.file.Files;
39 import java.text.MessageFormat;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.Iterator;
44 import java.util.LinkedList;
45 import java.util.List;
46 import java.util.Set;
47 import java.util.concurrent.TimeUnit;
48 import java.util.function.Consumer;
49
50 import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
51 import org.eclipse.jgit.errors.ConfigInvalidException;
52 import org.eclipse.jgit.internal.JGitText;
53 import org.eclipse.jgit.junit.MockSystemReader;
54 import org.eclipse.jgit.merge.MergeConfig;
55 import org.eclipse.jgit.storage.file.FileBasedConfig;
56 import org.eclipse.jgit.transport.RefSpec;
57 import org.eclipse.jgit.util.FS;
58 import org.eclipse.jgit.util.SystemReader;
59 import org.junit.After;
60 import org.junit.Rule;
61 import org.junit.Test;
62 import org.junit.rules.TemporaryFolder;
63
64
65
66
67 @SuppressWarnings("boxing")
68 public class ConfigTest {
69
70 private static final char WS = '\u2002';
71
72 private static final String REFS_ORIGIN = "+refs/heads/*:refs/remotes/origin/*";
73
74 private static final String REFS_UPSTREAM = "+refs/heads/*:refs/remotes/upstream/*";
75
76 private static final String REFS_BACKUP = "+refs/heads/*:refs/remotes/backup/*";
77
78 @Rule
79 public TemporaryFolder tmp = new TemporaryFolder();
80
81 @After
82 public void tearDown() {
83 SystemReader.setInstance(null);
84 }
85
86 @Test
87 public void test001_ReadBareKey() throws ConfigInvalidException {
88 final Config c = parse("[foo]\nbar\n");
89 assertTrue(c.getBoolean("foo", null, "bar", false));
90 assertEquals("", c.getString("foo", null, "bar"));
91 }
92
93 @Test
94 public void test002_ReadWithSubsection() throws ConfigInvalidException {
95 final Config c = parse("[foo \"zip\"]\nbar\n[foo \"zap\"]\nbar=false\nn=3\n");
96 assertTrue(c.getBoolean("foo", "zip", "bar", false));
97 assertEquals("", c.getString("foo","zip", "bar"));
98 assertFalse(c.getBoolean("foo", "zap", "bar", true));
99 assertEquals("false", c.getString("foo", "zap", "bar"));
100 assertEquals(3, c.getInt("foo", "zap", "n", 4));
101 assertEquals(4, c.getInt("foo", "zap","m", 4));
102 }
103
104 @Test
105 public void test003_PutRemote() {
106 final Config c = new Config();
107 c.setString("sec", "ext", "name", "value");
108 c.setString("sec", "ext", "name2", "value2");
109 final String expText = "[sec \"ext\"]\n\tname = value\n\tname2 = value2\n";
110 assertEquals(expText, c.toText());
111 }
112
113 @Test
114 public void test004_PutGetSimple() {
115 Config c = new Config();
116 c.setString("my", null, "somename", "false");
117 assertEquals("false", c.getString("my", null, "somename"));
118 assertEquals("[my]\n\tsomename = false\n", c.toText());
119 }
120
121 @Test
122 public void test005_PutGetStringList() {
123 Config c = new Config();
124 final LinkedList<String> values = new LinkedList<>();
125 values.add("value1");
126 values.add("value2");
127 c.setStringList("my", null, "somename", values);
128
129 final Object[] expArr = values.toArray();
130 final String[] actArr = c.getStringList("my", null, "somename");
131 assertArrayEquals(expArr, actArr);
132
133 final String expText = "[my]\n\tsomename = value1\n\tsomename = value2\n";
134 assertEquals(expText, c.toText());
135 }
136
137 @Test
138 public void test006_readCaseInsensitive() throws ConfigInvalidException {
139 final Config c = parse("[Foo]\nBar\n");
140 assertTrue(c.getBoolean("foo", null, "bar", false));
141 assertEquals("", c.getString("foo", null, "bar"));
142 }
143
144 @Test
145 public void test007_readUserConfig() {
146 final MockSystemReader mockSystemReader = new MockSystemReader();
147 SystemReader.setInstance(mockSystemReader);
148 final String hostname = mockSystemReader.getHostname();
149 final Config userGitConfig = mockSystemReader.openUserConfig(null,
150 FS.DETECTED);
151 final Config localConfig = new Config(userGitConfig);
152 mockSystemReader.clearProperties();
153
154 String authorName;
155 String authorEmail;
156
157
158 authorName = localConfig.get(UserConfig.KEY).getAuthorName();
159 authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
160 assertEquals(Constants.UNKNOWN_USER_DEFAULT, authorName);
161 assertEquals(Constants.UNKNOWN_USER_DEFAULT + "@" + hostname, authorEmail);
162 assertTrue(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
163 assertTrue(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
164
165
166 mockSystemReader.setProperty(Constants.OS_USER_NAME_KEY, "os user name");
167 localConfig.uncache(UserConfig.KEY);
168 authorName = localConfig.get(UserConfig.KEY).getAuthorName();
169 assertEquals("os user name", authorName);
170 assertTrue(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
171
172 if (hostname != null && hostname.length() != 0) {
173 authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
174 assertEquals("os user name@" + hostname, authorEmail);
175 }
176 assertTrue(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
177
178
179 mockSystemReader.setProperty(Constants.GIT_AUTHOR_NAME_KEY, "git author name");
180 mockSystemReader.setProperty(Constants.GIT_AUTHOR_EMAIL_KEY, "author@email");
181 localConfig.uncache(UserConfig.KEY);
182 authorName = localConfig.get(UserConfig.KEY).getAuthorName();
183 authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
184 assertEquals("git author name", authorName);
185 assertEquals("author@email", authorEmail);
186 assertFalse(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
187 assertFalse(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
188
189
190
191
192 mockSystemReader.clearProperties();
193 userGitConfig.setString("user", null, "name", "global username");
194 userGitConfig.setString("user", null, "email", "author@globalemail");
195 authorName = localConfig.get(UserConfig.KEY).getAuthorName();
196 authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
197 assertEquals("global username", authorName);
198 assertEquals("author@globalemail", authorEmail);
199 assertFalse(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
200 assertFalse(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
201
202
203 localConfig.setString("user", null, "name", "local username");
204 localConfig.setString("user", null, "email", "author@localemail");
205 authorName = localConfig.get(UserConfig.KEY).getAuthorName();
206 authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
207 assertEquals("local username", authorName);
208 assertEquals("author@localemail", authorEmail);
209 assertFalse(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
210 assertFalse(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
211
212 authorName = localConfig.get(UserConfig.KEY).getCommitterName();
213 authorEmail = localConfig.get(UserConfig.KEY).getCommitterEmail();
214 assertEquals("local username", authorName);
215 assertEquals("author@localemail", authorEmail);
216 assertFalse(localConfig.get(UserConfig.KEY).isCommitterNameImplicit());
217 assertFalse(localConfig.get(UserConfig.KEY).isCommitterEmailImplicit());
218
219
220 mockSystemReader.setProperty(Constants.GIT_AUTHOR_NAME_KEY,
221 "git author name");
222 mockSystemReader.setProperty(Constants.GIT_AUTHOR_EMAIL_KEY,
223 "author@email");
224 localConfig.setString("user", null, "name", "local username");
225 localConfig.setString("user", null, "email", "author@localemail");
226 authorName = localConfig.get(UserConfig.KEY).getAuthorName();
227 authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
228 assertEquals("git author name", authorName);
229 assertEquals("author@email", authorEmail);
230 assertFalse(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
231 assertFalse(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
232 }
233
234 @Test
235 public void testReadUserConfigWithInvalidCharactersStripped() {
236 final MockSystemReader mockSystemReader = new MockSystemReader();
237 final Config localConfig = new Config(mockSystemReader.openUserConfig(
238 null, FS.DETECTED));
239
240 localConfig.setString("user", null, "name", "foo<bar");
241 localConfig.setString("user", null, "email", "baz>\nqux@example.com");
242
243 UserConfig userConfig = localConfig.get(UserConfig.KEY);
244 assertEquals("foobar", userConfig.getAuthorName());
245 assertEquals("bazqux@example.com", userConfig.getAuthorEmail());
246 }
247
248 @Test
249 public void testReadBoolean_TrueFalse1() throws ConfigInvalidException {
250 final Config c = parse("[s]\na = true\nb = false\n");
251 assertEquals("true", c.getString("s", null, "a"));
252 assertEquals("false", c.getString("s", null, "b"));
253
254 assertTrue(c.getBoolean("s", "a", false));
255 assertFalse(c.getBoolean("s", "b", true));
256 }
257
258 @Test
259 public void testReadBoolean_TrueFalse2() throws ConfigInvalidException {
260 final Config c = parse("[s]\na = TrUe\nb = fAlSe\n");
261 assertEquals("TrUe", c.getString("s", null, "a"));
262 assertEquals("fAlSe", c.getString("s", null, "b"));
263
264 assertTrue(c.getBoolean("s", "a", false));
265 assertFalse(c.getBoolean("s", "b", true));
266 }
267
268 @Test
269 public void testReadBoolean_YesNo1() throws ConfigInvalidException {
270 final Config c = parse("[s]\na = yes\nb = no\n");
271 assertEquals("yes", c.getString("s", null, "a"));
272 assertEquals("no", c.getString("s", null, "b"));
273
274 assertTrue(c.getBoolean("s", "a", false));
275 assertFalse(c.getBoolean("s", "b", true));
276 }
277
278 @Test
279 public void testReadBoolean_YesNo2() throws ConfigInvalidException {
280 final Config c = parse("[s]\na = yEs\nb = NO\n");
281 assertEquals("yEs", c.getString("s", null, "a"));
282 assertEquals("NO", c.getString("s", null, "b"));
283
284 assertTrue(c.getBoolean("s", "a", false));
285 assertFalse(c.getBoolean("s", "b", true));
286 }
287
288 @Test
289 public void testReadBoolean_OnOff1() throws ConfigInvalidException {
290 final Config c = parse("[s]\na = on\nb = off\n");
291 assertEquals("on", c.getString("s", null, "a"));
292 assertEquals("off", c.getString("s", null, "b"));
293
294 assertTrue(c.getBoolean("s", "a", false));
295 assertFalse(c.getBoolean("s", "b", true));
296 }
297
298 @Test
299 public void testReadBoolean_OnOff2() throws ConfigInvalidException {
300 final Config c = parse("[s]\na = ON\nb = OFF\n");
301 assertEquals("ON", c.getString("s", null, "a"));
302 assertEquals("OFF", c.getString("s", null, "b"));
303
304 assertTrue(c.getBoolean("s", "a", false));
305 assertFalse(c.getBoolean("s", "b", true));
306 }
307
308 enum TestEnum {
309 ONE_TWO;
310 }
311
312 @Test
313 public void testGetEnum() throws ConfigInvalidException {
314 Config c = parse("[s]\na = ON\nb = input\nc = true\nd = off\n");
315 assertSame(CoreConfig.AutoCRLF.TRUE, c.getEnum("s", null, "a",
316 CoreConfig.AutoCRLF.FALSE));
317
318 assertSame(CoreConfig.AutoCRLF.INPUT, c.getEnum("s", null, "b",
319 CoreConfig.AutoCRLF.FALSE));
320
321 assertSame(CoreConfig.AutoCRLF.TRUE, c.getEnum("s", null, "c",
322 CoreConfig.AutoCRLF.FALSE));
323
324 assertSame(CoreConfig.AutoCRLF.FALSE, c.getEnum("s", null, "d",
325 CoreConfig.AutoCRLF.TRUE));
326
327 c = new Config();
328 assertSame(CoreConfig.AutoCRLF.FALSE, c.getEnum("s", null, "d",
329 CoreConfig.AutoCRLF.FALSE));
330
331 c = parse("[s \"b\"]\n\tc = one two\n");
332 assertSame(TestEnum.ONE_TWO, c.getEnum("s", "b", "c", TestEnum.ONE_TWO));
333
334 c = parse("[s \"b\"]\n\tc = one-two\n");
335 assertSame(TestEnum.ONE_TWO, c.getEnum("s", "b", "c", TestEnum.ONE_TWO));
336 }
337
338 @Test
339 public void testGetInvalidEnum() throws ConfigInvalidException {
340 Config c = parse("[a]\n\tb = invalid\n");
341 try {
342 c.getEnum("a", null, "b", TestEnum.ONE_TWO);
343 fail();
344 } catch (IllegalArgumentException e) {
345 assertEquals("Invalid value: a.b=invalid", e.getMessage());
346 }
347
348 c = parse("[a \"b\"]\n\tc = invalid\n");
349 try {
350 c.getEnum("a", "b", "c", TestEnum.ONE_TWO);
351 fail();
352 } catch (IllegalArgumentException e) {
353 assertEquals("Invalid value: a.b.c=invalid", e.getMessage());
354 }
355 }
356
357 @Test
358 public void testSetEnum() {
359 final Config c = new Config();
360 c.setEnum("s", "b", "c", TestEnum.ONE_TWO);
361 assertEquals("[s \"b\"]\n\tc = one two\n", c.toText());
362 }
363
364 @Test
365 public void testGetFastForwardMergeoptions() throws ConfigInvalidException {
366 Config c = new Config(null);
367 assertSame(FastForwardMode.FF, c.getEnum(
368 ConfigConstants.CONFIG_BRANCH_SECTION, "side",
369 ConfigConstants.CONFIG_KEY_MERGEOPTIONS, FastForwardMode.FF));
370 MergeConfig mergeConfig = c.get(MergeConfig.getParser("side"));
371 assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
372 c = parse("[branch \"side\"]\n\tmergeoptions = --ff-only\n");
373 assertSame(FastForwardMode.FF_ONLY, c.getEnum(
374 ConfigConstants.CONFIG_BRANCH_SECTION, "side",
375 ConfigConstants.CONFIG_KEY_MERGEOPTIONS,
376 FastForwardMode.FF_ONLY));
377 mergeConfig = c.get(MergeConfig.getParser("side"));
378 assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
379 c = parse("[branch \"side\"]\n\tmergeoptions = --ff\n");
380 assertSame(FastForwardMode.FF, c.getEnum(
381 ConfigConstants.CONFIG_BRANCH_SECTION, "side",
382 ConfigConstants.CONFIG_KEY_MERGEOPTIONS, FastForwardMode.FF));
383 mergeConfig = c.get(MergeConfig.getParser("side"));
384 assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
385 c = parse("[branch \"side\"]\n\tmergeoptions = --no-ff\n");
386 assertSame(FastForwardMode.NO_FF, c.getEnum(
387 ConfigConstants.CONFIG_BRANCH_SECTION, "side",
388 ConfigConstants.CONFIG_KEY_MERGEOPTIONS, FastForwardMode.NO_FF));
389 mergeConfig = c.get(MergeConfig.getParser("side"));
390 assertSame(FastForwardMode.NO_FF, mergeConfig.getFastForwardMode());
391 }
392
393 @Test
394 public void testSetFastForwardMergeoptions() {
395 final Config c = new Config();
396 c.setEnum("branch", "side", "mergeoptions", FastForwardMode.FF);
397 assertEquals("[branch \"side\"]\n\tmergeoptions = --ff\n", c.toText());
398 c.setEnum("branch", "side", "mergeoptions", FastForwardMode.FF_ONLY);
399 assertEquals("[branch \"side\"]\n\tmergeoptions = --ff-only\n",
400 c.toText());
401 c.setEnum("branch", "side", "mergeoptions", FastForwardMode.NO_FF);
402 assertEquals("[branch \"side\"]\n\tmergeoptions = --no-ff\n",
403 c.toText());
404 }
405
406 @Test
407 public void testGetFastForwardMerge() throws ConfigInvalidException {
408 Config c = new Config(null);
409 assertSame(FastForwardMode.Merge.TRUE, c.getEnum(
410 ConfigConstants.CONFIG_KEY_MERGE, null,
411 ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.TRUE));
412 MergeConfig mergeConfig = c.get(MergeConfig.getParser("side"));
413 assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
414 c = parse("[merge]\n\tff = only\n");
415 assertSame(FastForwardMode.Merge.ONLY, c.getEnum(
416 ConfigConstants.CONFIG_KEY_MERGE, null,
417 ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.ONLY));
418 mergeConfig = c.get(MergeConfig.getParser("side"));
419 assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
420 c = parse("[merge]\n\tff = true\n");
421 assertSame(FastForwardMode.Merge.TRUE, c.getEnum(
422 ConfigConstants.CONFIG_KEY_MERGE, null,
423 ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.TRUE));
424 mergeConfig = c.get(MergeConfig.getParser("side"));
425 assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
426 c = parse("[merge]\n\tff = false\n");
427 assertSame(FastForwardMode.Merge.FALSE, c.getEnum(
428 ConfigConstants.CONFIG_KEY_MERGE, null,
429 ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.FALSE));
430 mergeConfig = c.get(MergeConfig.getParser("side"));
431 assertSame(FastForwardMode.NO_FF, mergeConfig.getFastForwardMode());
432 }
433
434 @Test
435 public void testCombinedMergeOptions() throws ConfigInvalidException {
436 Config c = new Config(null);
437 MergeConfig mergeConfig = c.get(MergeConfig.getParser("side"));
438 assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
439 assertTrue(mergeConfig.isCommit());
440 assertFalse(mergeConfig.isSquash());
441
442 c = parse("[merge]\n\tff = false\n"
443 + "[branch \"side\"]\n\tmergeoptions = --ff-only\n");
444 mergeConfig = c.get(MergeConfig.getParser("side"));
445 assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
446 assertTrue(mergeConfig.isCommit());
447 assertFalse(mergeConfig.isSquash());
448
449 c = parse("[merge]\n\tff = only\n"
450 + "[branch \"side\"]\n\tmergeoptions = --squash\n");
451 mergeConfig = c.get(MergeConfig.getParser("side"));
452 assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
453 assertTrue(mergeConfig.isCommit());
454 assertTrue(mergeConfig.isSquash());
455
456 c = parse("[merge]\n\tff = false\n"
457 + "[branch \"side\"]\n\tmergeoptions = --ff-only --no-commit\n");
458 mergeConfig = c.get(MergeConfig.getParser("side"));
459 assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
460 assertFalse(mergeConfig.isCommit());
461 assertFalse(mergeConfig.isSquash());
462 }
463
464 @Test
465 public void testSetFastForwardMerge() {
466 final Config c = new Config();
467 c.setEnum("merge", null, "ff",
468 FastForwardMode.Merge.valueOf(FastForwardMode.FF));
469 assertEquals("[merge]\n\tff = true\n", c.toText());
470 c.setEnum("merge", null, "ff",
471 FastForwardMode.Merge.valueOf(FastForwardMode.FF_ONLY));
472 assertEquals("[merge]\n\tff = only\n", c.toText());
473 c.setEnum("merge", null, "ff",
474 FastForwardMode.Merge.valueOf(FastForwardMode.NO_FF));
475 assertEquals("[merge]\n\tff = false\n", c.toText());
476 }
477
478 @Test
479 public void testReadLong() throws ConfigInvalidException {
480 assertReadLong(1L);
481 assertReadLong(-1L);
482 assertReadLong(Long.MIN_VALUE);
483 assertReadLong(Long.MAX_VALUE);
484 assertReadLong(4L * 1024 * 1024 * 1024, "4g");
485 assertReadLong(3L * 1024 * 1024, "3 m");
486 assertReadLong(8L * 1024, "8 k");
487
488 try {
489 assertReadLong(-1, "1.5g");
490 fail("incorrectly accepted 1.5g");
491 } catch (IllegalArgumentException e) {
492 assertEquals("Invalid integer value: s.a=1.5g", e.getMessage());
493 }
494 }
495
496 @Test
497 public void testBooleanWithNoValue() throws ConfigInvalidException {
498 Config c = parse("[my]\n\tempty\n");
499 assertEquals("", c.getString("my", null, "empty"));
500 assertEquals(1, c.getStringList("my", null, "empty").length);
501 assertEquals("", c.getStringList("my", null, "empty")[0]);
502 assertTrue(c.getBoolean("my", "empty", false));
503 assertEquals("[my]\n\tempty\n", c.toText());
504 }
505
506 @Test
507 public void testUnsetBranchSection() throws ConfigInvalidException {
508 Config c = parse(""
509 + "[branch \"keep\"]\n"
510 + " merge = master.branch.to.keep.in.the.file\n"
511 + "\n"
512 + "[branch \"remove\"]\n"
513 + " merge = this.will.get.deleted\n"
514 + " remote = origin-for-some-long-gone-place\n"
515 + "\n"
516 + "[core-section-not-to-remove-in-test]\n"
517 + " packedGitLimit = 14\n");
518 c.unsetSection("branch", "does.not.exist");
519 c.unsetSection("branch", "remove");
520 assertEquals(""
521 + "[branch \"keep\"]\n"
522 + " merge = master.branch.to.keep.in.the.file\n"
523 + "\n"
524 + "[core-section-not-to-remove-in-test]\n"
525 + " packedGitLimit = 14\n", c.toText());
526 }
527
528 @Test
529 public void testUnsetSingleSection() throws ConfigInvalidException {
530 Config c = parse(""
531 + "[branch \"keep\"]\n"
532 + " merge = master.branch.to.keep.in.the.file\n"
533 + "\n"
534 + "[single]\n"
535 + " merge = this.will.get.deleted\n"
536 + " remote = origin-for-some-long-gone-place\n"
537 + "\n"
538 + "[core-section-not-to-remove-in-test]\n"
539 + " packedGitLimit = 14\n");
540 c.unsetSection("single", null);
541 assertEquals(""
542 + "[branch \"keep\"]\n"
543 + " merge = master.branch.to.keep.in.the.file\n"
544 + "\n"
545 + "[core-section-not-to-remove-in-test]\n"
546 + " packedGitLimit = 14\n", c.toText());
547 }
548
549 @Test
550 public void test008_readSectionNames() throws ConfigInvalidException {
551 final Config c = parse("[a]\n [B]\n");
552 Set<String> sections = c.getSections();
553 assertTrue("Sections should contain \"a\"", sections.contains("a"));
554 assertTrue("Sections should contain \"b\"", sections.contains("b"));
555 }
556
557 @Test
558 public void test009_readNamesInSection() throws ConfigInvalidException {
559 String configString = "[core]\n" + "repositoryFormatVersion = 0\n"
560 + "filemode = false\n" + "logAllRefUpdates = true\n";
561 final Config c = parse(configString);
562 Set<String> names = c.getNames("core");
563 assertEquals("Core section size", 3, names.size());
564 assertTrue("Core section should contain \"filemode\"", names
565 .contains("filemode"));
566
567 assertTrue("Core section should contain \"repositoryFormatVersion\"",
568 names.contains("repositoryFormatVersion"));
569
570 assertTrue("Core section should contain \"repositoryformatversion\"",
571 names.contains("repositoryformatversion"));
572
573 Iterator<String> itr = names.iterator();
574 assertEquals("filemode", itr.next());
575 assertEquals("logAllRefUpdates", itr.next());
576 assertEquals("repositoryFormatVersion", itr.next());
577 assertFalse(itr.hasNext());
578 }
579
580 @Test
581 public void test_ReadNamesInSectionRecursive()
582 throws ConfigInvalidException {
583 String baseConfigString = "[core]\n" + "logAllRefUpdates = true\n";
584 String configString = "[core]\n" + "repositoryFormatVersion = 0\n"
585 + "filemode = false\n";
586 final Config c = parse(configString, parse(baseConfigString));
587 Set<String> names = c.getNames("core", true);
588 assertEquals("Core section size", 3, names.size());
589 assertTrue("Core section should contain \"filemode\"",
590 names.contains("filemode"));
591 assertTrue("Core section should contain \"repositoryFormatVersion\"",
592 names.contains("repositoryFormatVersion"));
593 assertTrue("Core section should contain \"logAllRefUpdates\"",
594 names.contains("logAllRefUpdates"));
595 assertTrue("Core section should contain \"logallrefupdates\"",
596 names.contains("logallrefupdates"));
597
598 Iterator<String> itr = names.iterator();
599 assertEquals("filemode", itr.next());
600 assertEquals("repositoryFormatVersion", itr.next());
601 assertEquals("logAllRefUpdates", itr.next());
602 assertFalse(itr.hasNext());
603 }
604
605 @Test
606 public void test010_readNamesInSubSection() throws ConfigInvalidException {
607 String configString = "[a \"sub1\"]\n"
608 + "x = 0\n"
609 + "y = false\n"
610 + "z = true\n"
611 + "[a \"sub2\"]\n"
612 + "a=0\n"
613 + "b=1\n";
614 final Config c = parse(configString);
615 Set<String> names = c.getNames("a", "sub1");
616 assertEquals("Subsection size", 3, names.size());
617 assertTrue("Subsection should contain \"x\"", names.contains("x"));
618 assertTrue("Subsection should contain \"y\"", names.contains("y"));
619 assertTrue("Subsection should contain \"z\"", names.contains("z"));
620 names = c.getNames("a", "sub2");
621 assertEquals("Subsection size", 2, names.size());
622 assertTrue("Subsection should contain \"a\"", names.contains("a"));
623 assertTrue("Subsection should contain \"b\"", names.contains("b"));
624 }
625
626 @Test
627 public void readNamesInSubSectionRecursive() throws ConfigInvalidException {
628 String baseConfigString = "[a \"sub1\"]\n"
629 + "x = 0\n"
630 + "y = false\n"
631 + "[a \"sub2\"]\n"
632 + "A=0\n";
633 String configString = "[a \"sub1\"]\n"
634 + "z = true\n"
635 + "[a \"sub2\"]\n"
636 + "B=1\n";
637 final Config c = parse(configString, parse(baseConfigString));
638 Set<String> names = c.getNames("a", "sub1", true);
639 assertEquals("Subsection size", 3, names.size());
640 assertTrue("Subsection should contain \"x\"", names.contains("x"));
641 assertTrue("Subsection should contain \"y\"", names.contains("y"));
642 assertTrue("Subsection should contain \"z\"", names.contains("z"));
643 names = c.getNames("a", "sub2", true);
644 assertEquals("Subsection size", 2, names.size());
645 assertTrue("Subsection should contain \"A\"", names.contains("A"));
646 assertTrue("Subsection should contain \"a\"", names.contains("a"));
647 assertTrue("Subsection should contain \"B\"", names.contains("B"));
648 }
649
650
651 @Test
652 public void testNoFinalNewline() throws ConfigInvalidException {
653 Config c = parse("[a]\n"
654 + "x = 0\n"
655 + "y = 1");
656 assertEquals("0", c.getString("a", null, "x"));
657 assertEquals("1", c.getString("a", null, "y"));
658 }
659
660 @Test
661 public void testExplicitlySetEmptyString() throws Exception {
662 Config c = new Config();
663 c.setString("a", null, "x", "0");
664 c.setString("a", null, "y", "");
665
666 assertEquals("0", c.getString("a", null, "x"));
667 assertEquals(0, c.getInt("a", null, "x", 1));
668
669 assertEquals("", c.getString("a", null, "y"));
670 assertArrayEquals(new String[]{""}, c.getStringList("a", null, "y"));
671 assertEquals(1, c.getInt("a", null, "y", 1));
672
673 assertNull(c.getString("a", null, "z"));
674 assertArrayEquals(new String[]{}, c.getStringList("a", null, "z"));
675 }
676
677 @Test
678 public void testParsedEmptyString() throws Exception {
679 Config c = parse("[a]\n"
680 + "x = 0\n"
681 + "y =\n");
682
683 assertEquals("0", c.getString("a", null, "x"));
684 assertEquals(0, c.getInt("a", null, "x", 1));
685
686 assertNull(c.getString("a", null, "y"));
687 assertArrayEquals(new String[]{null}, c.getStringList("a", null, "y"));
688 assertEquals(1, c.getInt("a", null, "y", 1));
689
690 assertNull(c.getString("a", null, "z"));
691 assertArrayEquals(new String[]{}, c.getStringList("a", null, "z"));
692 }
693
694 @Test
695 public void testSetStringListWithEmptyValue() throws Exception {
696 Config c = new Config();
697 c.setStringList("a", null, "x", Arrays.asList(""));
698 assertArrayEquals(new String[]{""}, c.getStringList("a", null, "x"));
699 }
700
701 @Test
702 public void testEmptyValueAtEof() throws Exception {
703 String text = "[a]\nx =";
704 Config c = parse(text);
705 assertNull(c.getString("a", null, "x"));
706 assertArrayEquals(new String[]{null},
707 c.getStringList("a", null, "x"));
708 c = parse(text + "\n");
709 assertNull(c.getString("a", null, "x"));
710 assertArrayEquals(new String[]{null},
711 c.getStringList("a", null, "x"));
712 }
713
714 @Test
715 public void testReadMultipleValuesForName() throws ConfigInvalidException {
716 Config c = parse("[foo]\nbar=false\nbar=true\n");
717 assertTrue(c.getBoolean("foo", "bar", false));
718 }
719
720 @Test
721 public void testIncludeInvalidName() {
722 assertThrows(JGitText.get().invalidLineInConfigFile,
723 ConfigInvalidException.class, () -> parse("[include]\nbar\n"));
724 }
725
726 @Test
727 public void testIncludeNoValue() {
728 assertThrows(JGitText.get().invalidLineInConfigFile,
729 ConfigInvalidException.class, () -> parse("[include]\npath\n"));
730 }
731
732 @Test
733 public void testIncludeEmptyValue() {
734 assertThrows(JGitText.get().invalidLineInConfigFile,
735 ConfigInvalidException.class,
736 () -> parse("[include]\npath=\n"));
737 }
738
739 @Test
740 public void testIncludeValuePathNotFound() throws ConfigInvalidException {
741
742 String notFound = "/not/found";
743 Config parsed = parse("[include]\npath=" + notFound + "\n");
744 assertEquals(1, parsed.getSections().size());
745 assertEquals(notFound, parsed.getString("include", null, "path"));
746 }
747
748 @Test
749 public void testIncludeValuePathWithTilde() throws ConfigInvalidException {
750
751
752 String notSupported = "~/someFile";
753 Config parsed = parse("[include]\npath=" + notSupported + "\n");
754 assertEquals(1, parsed.getSections().size());
755 assertEquals(notSupported, parsed.getString("include", null, "path"));
756 }
757
758 @Test
759 public void testIncludeValuePathRelative() throws ConfigInvalidException {
760
761
762 String notSupported = "someRelativeFile";
763 Config parsed = parse("[include]\npath=" + notSupported + "\n");
764 assertEquals(1, parsed.getSections().size());
765 assertEquals(notSupported, parsed.getString("include", null, "path"));
766 }
767
768 @Test
769 public void testIncludeTooManyRecursions() throws IOException {
770 File config = tmp.newFile("config");
771 String include = "[include]\npath=" + pathToString(config) + "\n";
772 Files.write(config.toPath(), include.getBytes(UTF_8));
773 try {
774 loadConfig(config);
775 fail();
776 } catch (ConfigInvalidException cie) {
777 for (Throwable t = cie; t != null; t = t.getCause()) {
778 if (t.getMessage()
779 .equals(JGitText.get().tooManyIncludeRecursions)) {
780 return;
781 }
782 }
783 fail("Expected to find expected exception message: "
784 + JGitText.get().tooManyIncludeRecursions);
785 }
786 }
787
788 @Test
789 public void testIncludeIsNoop() throws IOException, ConfigInvalidException {
790 File config = tmp.newFile("config");
791
792 String fooBar = "[foo]\nbar=true\n";
793 Files.write(config.toPath(), fooBar.getBytes(UTF_8));
794
795 Config parsed = parse("[include]\npath=" + pathToString(config) + "\n");
796 assertFalse(parsed.getBoolean("foo", "bar", false));
797 }
798
799 @Test
800 public void testIncludeCaseInsensitiveSection()
801 throws IOException, ConfigInvalidException {
802 File included = tmp.newFile("included");
803 String content = "[foo]\nbar=true\n";
804 Files.write(included.toPath(), content.getBytes(UTF_8));
805
806 File config = tmp.newFile("config");
807 content = "[Include]\npath=" + pathToString(included) + "\n";
808 Files.write(config.toPath(), content.getBytes(UTF_8));
809
810 FileBasedConfig fbConfig = loadConfig(config);
811 assertTrue(fbConfig.getBoolean("foo", "bar", false));
812 }
813
814 @Test
815 public void testIncludeCaseInsensitiveKey()
816 throws IOException, ConfigInvalidException {
817 File included = tmp.newFile("included");
818 String content = "[foo]\nbar=true\n";
819 Files.write(included.toPath(), content.getBytes(UTF_8));
820
821 File config = tmp.newFile("config");
822 content = "[include]\nPath=" + pathToString(included) + "\n";
823 Files.write(config.toPath(), content.getBytes(UTF_8));
824
825 FileBasedConfig fbConfig = loadConfig(config);
826 assertTrue(fbConfig.getBoolean("foo", "bar", false));
827 }
828
829 @Test
830 public void testIncludeExceptionContainsLine() {
831 try {
832 parse("[include]\npath=\n");
833 fail("Expected ConfigInvalidException");
834 } catch (ConfigInvalidException e) {
835 assertTrue(
836 "Expected to find the problem line in the exception message",
837 e.getMessage().contains("include.path"));
838 }
839 }
840
841 @Test
842 public void testIncludeExceptionContainsFile() throws IOException {
843 File included = tmp.newFile("included");
844 String includedPath = pathToString(included);
845 String content = "[include]\npath=\n";
846 Files.write(included.toPath(), content.getBytes(UTF_8));
847
848 File config = tmp.newFile("config");
849 String include = "[include]\npath=" + includedPath + "\n";
850 Files.write(config.toPath(), include.getBytes(UTF_8));
851 try {
852 loadConfig(config);
853 fail("Expected ConfigInvalidException");
854 } catch (ConfigInvalidException e) {
855
856
857 for (Throwable t = e; t != null; t = t.getCause()) {
858 if (t.getMessage().contains(includedPath)) {
859 return;
860 }
861 }
862 fail("Expected to find the path in the exception message: "
863 + includedPath);
864 }
865 }
866
867 @Test
868 public void testIncludeSetValueMustNotTouchIncludedLines1()
869 throws IOException, ConfigInvalidException {
870 File includedFile = createAllTypesIncludedContent();
871
872 File configFile = tmp.newFile("config");
873 String content = createAllTypesSampleContent("Alice Parker", false, 11,
874 21, 31, CoreConfig.AutoCRLF.FALSE,
875 "+refs/heads/*:refs/remotes/origin/*") + "\n[include]\npath="
876 + pathToString(includedFile);
877 Files.write(configFile.toPath(), content.getBytes(UTF_8));
878
879 FileBasedConfig fbConfig = loadConfig(configFile);
880 assertValuesAsIncluded(fbConfig, REFS_ORIGIN, REFS_UPSTREAM);
881 assertSections(fbConfig, "user", "core", "remote", "include");
882
883 setAllValuesNew(fbConfig);
884 assertValuesAsIsSaveLoad(fbConfig, config -> {
885 assertValuesAsIncluded(config, REFS_BACKUP, REFS_UPSTREAM);
886 assertSections(fbConfig, "user", "core", "remote", "include");
887 });
888 }
889
890 @Test
891 public void testIncludeSetValueMustNotTouchIncludedLines2()
892 throws IOException, ConfigInvalidException {
893 File includedFile = createAllTypesIncludedContent();
894
895 File configFile = tmp.newFile("config");
896 String content = "[include]\npath=" + pathToString(includedFile) + "\n"
897 + createAllTypesSampleContent("Alice Parker", false, 11, 21, 31,
898 CoreConfig.AutoCRLF.FALSE,
899 "+refs/heads/*:refs/remotes/origin/*");
900 Files.write(configFile.toPath(), content.getBytes(UTF_8));
901
902 FileBasedConfig fbConfig = loadConfig(configFile);
903 assertValuesAsConfig(fbConfig, REFS_UPSTREAM, REFS_ORIGIN);
904 assertSections(fbConfig, "include", "user", "core", "remote");
905
906 setAllValuesNew(fbConfig);
907 assertValuesAsIsSaveLoad(fbConfig, config -> {
908 assertValuesAsNew(config, REFS_UPSTREAM, REFS_BACKUP);
909 assertSections(fbConfig, "include", "user", "core", "remote");
910 });
911 }
912
913 @Test
914 public void testIncludeSetValueOnFileWithJustContainsInclude()
915 throws IOException, ConfigInvalidException {
916 File includedFile = createAllTypesIncludedContent();
917
918 File configFile = tmp.newFile("config");
919 String content = "[include]\npath=" + pathToString(includedFile);
920 Files.write(configFile.toPath(), content.getBytes(UTF_8));
921
922 FileBasedConfig fbConfig = loadConfig(configFile);
923 assertValuesAsIncluded(fbConfig, REFS_UPSTREAM);
924 assertSections(fbConfig, "include", "user", "core", "remote");
925
926 setAllValuesNew(fbConfig);
927 assertValuesAsIsSaveLoad(fbConfig, config -> {
928 assertValuesAsNew(config, REFS_UPSTREAM, REFS_BACKUP);
929 assertSections(fbConfig, "include", "user", "core", "remote");
930 });
931 }
932
933 @Test
934 public void testIncludeSetValueOnFileWithJustEmptySection1()
935 throws IOException, ConfigInvalidException {
936 File includedFile = createAllTypesIncludedContent();
937
938 File configFile = tmp.newFile("config");
939 String content = "[user]\n[include]\npath="
940 + pathToString(includedFile);
941 Files.write(configFile.toPath(), content.getBytes(UTF_8));
942
943 FileBasedConfig fbConfig = loadConfig(configFile);
944 assertValuesAsIncluded(fbConfig, REFS_UPSTREAM);
945 assertSections(fbConfig, "user", "include", "core", "remote");
946
947 setAllValuesNew(fbConfig);
948 assertValuesAsIsSaveLoad(fbConfig, config -> {
949 assertValuesAsNewWithName(config, "Alice Muller", REFS_UPSTREAM,
950 REFS_BACKUP);
951 assertSections(fbConfig, "user", "include", "core", "remote");
952 });
953 }
954
955 @Test
956 public void testIncludeSetValueOnFileWithJustEmptySection2()
957 throws IOException, ConfigInvalidException {
958 File includedFile = createAllTypesIncludedContent();
959
960 File configFile = tmp.newFile("config");
961 String content = "[include]\npath=" + pathToString(includedFile)
962 + "\n[user]";
963 Files.write(configFile.toPath(), content.getBytes(UTF_8));
964
965 FileBasedConfig fbConfig = loadConfig(configFile);
966 assertValuesAsIncluded(fbConfig, REFS_UPSTREAM);
967 assertSections(fbConfig, "include", "user", "core", "remote");
968
969 setAllValuesNew(fbConfig);
970 assertValuesAsIsSaveLoad(fbConfig, config -> {
971 assertValuesAsNew(config, REFS_UPSTREAM, REFS_BACKUP);
972 assertSections(fbConfig, "include", "user", "core", "remote");
973 });
974 }
975
976 @Test
977 public void testIncludeSetValueOnFileWithJustExistingSection1()
978 throws IOException, ConfigInvalidException {
979 File includedFile = createAllTypesIncludedContent();
980
981 File configFile = tmp.newFile("config");
982 String content = "[user]\nemail=alice@home\n[include]\npath="
983 + pathToString(includedFile);
984 Files.write(configFile.toPath(), content.getBytes(UTF_8));
985
986 FileBasedConfig fbConfig = loadConfig(configFile);
987 assertValuesAsIncluded(fbConfig, REFS_UPSTREAM);
988 assertSections(fbConfig, "user", "include", "core", "remote");
989
990 setAllValuesNew(fbConfig);
991 assertValuesAsIsSaveLoad(fbConfig, config -> {
992 assertValuesAsNewWithName(config, "Alice Muller", REFS_UPSTREAM,
993 REFS_BACKUP);
994 assertSections(fbConfig, "user", "include", "core", "remote");
995 });
996 }
997
998 @Test
999 public void testIncludeSetValueOnFileWithJustExistingSection2()
1000 throws IOException, ConfigInvalidException {
1001 File includedFile = createAllTypesIncludedContent();
1002
1003 File configFile = tmp.newFile("config");
1004 String content = "[include]\npath=" + pathToString(includedFile)
1005 + "\n[user]\nemail=alice@home\n";
1006 Files.write(configFile.toPath(), content.getBytes(UTF_8));
1007
1008 FileBasedConfig fbConfig = loadConfig(configFile);
1009 assertValuesAsIncluded(fbConfig, REFS_UPSTREAM);
1010 assertSections(fbConfig, "include", "user", "core", "remote");
1011
1012 setAllValuesNew(fbConfig);
1013 assertValuesAsIsSaveLoad(fbConfig, config -> {
1014 assertValuesAsNew(config, REFS_UPSTREAM, REFS_BACKUP);
1015 assertSections(fbConfig, "include", "user", "core", "remote");
1016 });
1017 }
1018
1019 @Test
1020 public void testIncludeUnsetSectionMustNotTouchIncludedLines()
1021 throws IOException, ConfigInvalidException {
1022 File includedFile = tmp.newFile("included");
1023 RefSpec includedRefSpec = new RefSpec(REFS_UPSTREAM);
1024 String includedContent = "[remote \"origin\"]\n" + "fetch="
1025 + includedRefSpec;
1026 Files.write(includedFile.toPath(), includedContent.getBytes(UTF_8));
1027
1028 File configFile = tmp.newFile("config");
1029 RefSpec refSpec = new RefSpec(REFS_ORIGIN);
1030 String content = "[include]\npath=" + pathToString(includedFile) + "\n"
1031 + "[remote \"origin\"]\n" + "fetch=" + refSpec;
1032 Files.write(configFile.toPath(), content.getBytes(UTF_8));
1033
1034 FileBasedConfig fbConfig = loadConfig(configFile);
1035
1036 Consumer<FileBasedConfig> assertion = config -> {
1037 assertEquals(Arrays.asList(includedRefSpec, refSpec),
1038 config.getRefSpecs("remote", "origin", "fetch"));
1039 };
1040 assertion.accept(fbConfig);
1041
1042 fbConfig.unsetSection("remote", "origin");
1043 assertValuesAsIsSaveLoad(fbConfig, config -> {
1044 assertEquals(Collections.singletonList(includedRefSpec),
1045 config.getRefSpecs("remote", "origin", "fetch"));
1046 });
1047 }
1048
1049 private File createAllTypesIncludedContent() throws IOException {
1050 File includedFile = tmp.newFile("included");
1051 String includedContent = createAllTypesSampleContent("Alice Muller",
1052 true, 10, 20, 30, CoreConfig.AutoCRLF.TRUE,
1053 "+refs/heads/*:refs/remotes/upstream/*");
1054 Files.write(includedFile.toPath(), includedContent.getBytes(UTF_8));
1055 return includedFile;
1056 }
1057
1058 private static void assertValuesAsIsSaveLoad(FileBasedConfig fbConfig,
1059 Consumer<FileBasedConfig> assertion)
1060 throws IOException, ConfigInvalidException {
1061 assertion.accept(fbConfig);
1062
1063 fbConfig.save();
1064 assertion.accept(fbConfig);
1065
1066 fbConfig = loadConfig(fbConfig.getFile());
1067 assertion.accept(fbConfig);
1068 }
1069
1070 private static void setAllValuesNew(Config config) {
1071 config.setString("user", null, "name", "Alice Bauer");
1072 config.setBoolean("core", null, "fileMode", false);
1073 config.setInt("core", null, "deltaBaseCacheLimit", 12);
1074 config.setLong("core", null, "packedGitLimit", 22);
1075 config.setLong("core", null, "repositoryCacheExpireAfter", 32);
1076 config.setEnum("core", null, "autocrlf", CoreConfig.AutoCRLF.FALSE);
1077 config.setString("remote", "origin", "fetch",
1078 "+refs/heads/*:refs/remotes/backup/*");
1079 }
1080
1081 private static void assertValuesAsIncluded(Config config, String... refs) {
1082 assertAllTypesSampleContent("Alice Muller", true, 10, 20, 30,
1083 CoreConfig.AutoCRLF.TRUE, config, refs);
1084 }
1085
1086 private static void assertValuesAsConfig(Config config, String... refs) {
1087 assertAllTypesSampleContent("Alice Parker", false, 11, 21, 31,
1088 CoreConfig.AutoCRLF.FALSE, config, refs);
1089 }
1090
1091 private static void assertValuesAsNew(Config config, String... refs) {
1092 assertValuesAsNewWithName(config, "Alice Bauer", refs);
1093 }
1094
1095 private static void assertValuesAsNewWithName(Config config, String name,
1096 String... refs) {
1097 assertAllTypesSampleContent(name, false, 12, 22, 32,
1098 CoreConfig.AutoCRLF.FALSE, config, refs);
1099 }
1100
1101 private static void assertSections(Config config, String... sections) {
1102 assertEquals(Arrays.asList(sections),
1103 new ArrayList<>(config.getSections()));
1104 }
1105
1106 private static String createAllTypesSampleContent(String name,
1107 boolean fileMode, int deltaBaseCacheLimit, long packedGitLimit,
1108 long repositoryCacheExpireAfter, CoreConfig.AutoCRLF autoCRLF,
1109 String fetchRefSpec) {
1110 final StringBuilder builder = new StringBuilder();
1111 builder.append("[user]\n");
1112 builder.append("name=");
1113 builder.append(name);
1114 builder.append("\n");
1115
1116 builder.append("[core]\n");
1117 builder.append("fileMode=");
1118 builder.append(fileMode);
1119 builder.append("\n");
1120
1121 builder.append("deltaBaseCacheLimit=");
1122 builder.append(deltaBaseCacheLimit);
1123 builder.append("\n");
1124
1125 builder.append("packedGitLimit=");
1126 builder.append(packedGitLimit);
1127 builder.append("\n");
1128
1129 builder.append("repositoryCacheExpireAfter=");
1130 builder.append(repositoryCacheExpireAfter);
1131 builder.append("\n");
1132
1133 builder.append("autocrlf=");
1134 builder.append(autoCRLF.name());
1135 builder.append("\n");
1136
1137 builder.append("[remote \"origin\"]\n");
1138 builder.append("fetch=");
1139 builder.append(fetchRefSpec);
1140 builder.append("\n");
1141 return builder.toString();
1142 }
1143
1144 private static void assertAllTypesSampleContent(String name,
1145 boolean fileMode, int deltaBaseCacheLimit, long packedGitLimit,
1146 long repositoryCacheExpireAfter, CoreConfig.AutoCRLF autoCRLF,
1147 Config config, String... fetchRefSpecs) {
1148 assertEquals(name, config.getString("user", null, "name"));
1149 assertEquals(fileMode,
1150 config.getBoolean("core", "fileMode", !fileMode));
1151 assertEquals(deltaBaseCacheLimit,
1152 config.getInt("core", "deltaBaseCacheLimit", -1));
1153 assertEquals(packedGitLimit,
1154 config.getLong("core", "packedGitLimit", -1));
1155 assertEquals(repositoryCacheExpireAfter, config.getTimeUnit("core",
1156 null, "repositoryCacheExpireAfter", -1, MILLISECONDS));
1157 assertEquals(autoCRLF, config.getEnum("core", null, "autocrlf",
1158 CoreConfig.AutoCRLF.INPUT));
1159 final List<RefSpec> refspecs = new ArrayList<>();
1160 for (String fetchRefSpec : fetchRefSpecs) {
1161 refspecs.add(new RefSpec(fetchRefSpec));
1162 }
1163
1164 assertEquals(refspecs, config.getRefSpecs("remote", "origin", "fetch"));
1165 }
1166
1167 private static void assertReadLong(long exp) throws ConfigInvalidException {
1168 assertReadLong(exp, String.valueOf(exp));
1169 }
1170
1171 private static void assertReadLong(long exp, String act)
1172 throws ConfigInvalidException {
1173 final Config c = parse("[s]\na = " + act + "\n");
1174 assertEquals(exp, c.getLong("s", null, "a", 0L));
1175 }
1176
1177 private static Config parse(String content)
1178 throws ConfigInvalidException {
1179 return parse(content, null);
1180 }
1181
1182 private static Config parse(String content, Config baseConfig)
1183 throws ConfigInvalidException {
1184 final Config c = new Config(baseConfig);
1185 c.fromText(content);
1186 return c;
1187 }
1188
1189 @Test
1190 public void testTimeUnit() throws ConfigInvalidException {
1191 assertEquals(0, parseTime("0", NANOSECONDS));
1192 assertEquals(2, parseTime("2ns", NANOSECONDS));
1193 assertEquals(200, parseTime("200 nanoseconds", NANOSECONDS));
1194
1195 assertEquals(0, parseTime("0", MICROSECONDS));
1196 assertEquals(2, parseTime("2us", MICROSECONDS));
1197 assertEquals(2, parseTime("2000 nanoseconds", MICROSECONDS));
1198 assertEquals(200, parseTime("200 microseconds", MICROSECONDS));
1199
1200 assertEquals(0, parseTime("0", MILLISECONDS));
1201 assertEquals(2, parseTime("2ms", MILLISECONDS));
1202 assertEquals(2, parseTime("2000microseconds", MILLISECONDS));
1203 assertEquals(200, parseTime("200 milliseconds", MILLISECONDS));
1204
1205 assertEquals(0, parseTime("0s", SECONDS));
1206 assertEquals(2, parseTime("2s", SECONDS));
1207 assertEquals(231, parseTime("231sec", SECONDS));
1208 assertEquals(1, parseTime("1second", SECONDS));
1209 assertEquals(300, parseTime("300 seconds", SECONDS));
1210
1211 assertEquals(2, parseTime("2m", MINUTES));
1212 assertEquals(2, parseTime("2min", MINUTES));
1213 assertEquals(1, parseTime("1 minute", MINUTES));
1214 assertEquals(10, parseTime("10 minutes", MINUTES));
1215
1216 assertEquals(5, parseTime("5h", HOURS));
1217 assertEquals(5, parseTime("5hr", HOURS));
1218 assertEquals(1, parseTime("1hour", HOURS));
1219 assertEquals(48, parseTime("48hours", HOURS));
1220
1221 assertEquals(5, parseTime("5 h", HOURS));
1222 assertEquals(5, parseTime("5 hr", HOURS));
1223 assertEquals(1, parseTime("1 hour", HOURS));
1224 assertEquals(48, parseTime("48 hours", HOURS));
1225 assertEquals(48, parseTime("48 \t \r hours", HOURS));
1226
1227 assertEquals(4, parseTime("4d", DAYS));
1228 assertEquals(1, parseTime("1day", DAYS));
1229 assertEquals(14, parseTime("14days", DAYS));
1230
1231 assertEquals(7, parseTime("1w", DAYS));
1232 assertEquals(7, parseTime("1week", DAYS));
1233 assertEquals(14, parseTime("2w", DAYS));
1234 assertEquals(14, parseTime("2weeks", DAYS));
1235
1236 assertEquals(30, parseTime("1mon", DAYS));
1237 assertEquals(30, parseTime("1month", DAYS));
1238 assertEquals(60, parseTime("2mon", DAYS));
1239 assertEquals(60, parseTime("2months", DAYS));
1240
1241 assertEquals(365, parseTime("1y", DAYS));
1242 assertEquals(365, parseTime("1year", DAYS));
1243 assertEquals(365 * 2, parseTime("2years", DAYS));
1244 }
1245
1246 private long parseTime(String value, TimeUnit unit)
1247 throws ConfigInvalidException {
1248 Config c = parse("[a]\na=" + value + "\n");
1249 return c.getTimeUnit("a", null, "a", 0, unit);
1250 }
1251
1252 @Test
1253 public void testTimeUnitDefaultValue() throws ConfigInvalidException {
1254
1255 assertEquals(20, parse("[a]\na=0\n").getTimeUnit("a", null, "b", 20,
1256 MILLISECONDS));
1257
1258 assertEquals(20, parse("[a]\na=\" \"\n").getTimeUnit("a", null, "a", 20,
1259 MILLISECONDS));
1260
1261
1262 assertEquals(20, parse("[a]\na=test\n").getTimeUnit("a", null, "a", 20,
1263 MILLISECONDS));
1264 }
1265
1266 @Test
1267 public void testTimeUnitInvalid() {
1268 assertThrows("Invalid time unit value: a.a=1 monttthhh",
1269 IllegalArgumentException.class,
1270 () -> parseTime("1 monttthhh", DAYS));
1271 }
1272
1273 @Test
1274 public void testTimeUnitInvalidWithSection() throws ConfigInvalidException {
1275 Config c = parse("[a \"b\"]\na=1 monttthhh\n");
1276 assertThrows("Invalid time unit value: a.b.a=1 monttthhh",
1277 IllegalArgumentException.class,
1278 () -> c.getTimeUnit("a", "b", "a", 0, DAYS));
1279 }
1280
1281 @Test
1282 public void testTimeUnitNegative() {
1283 assertThrows(IllegalArgumentException.class,
1284 () -> parseTime("-1", MILLISECONDS));
1285 }
1286
1287 @Test
1288 public void testEscapeSpacesOnly() throws ConfigInvalidException {
1289
1290 assertEquals("", Config.escapeValue(""));
1291
1292 assertValueRoundTrip(" ", "\" \"");
1293 assertValueRoundTrip(" ", "\" \"");
1294 }
1295
1296 @Test
1297 public void testEscapeLeadingSpace() throws ConfigInvalidException {
1298 assertValueRoundTrip("x", "x");
1299 assertValueRoundTrip(" x", "\" x\"");
1300 assertValueRoundTrip(" x", "\" x\"");
1301 }
1302
1303 @Test
1304 public void testEscapeTrailingSpace() throws ConfigInvalidException {
1305 assertValueRoundTrip("x", "x");
1306 assertValueRoundTrip("x ","\"x \"");
1307 assertValueRoundTrip("x ","\"x \"");
1308 }
1309
1310 @Test
1311 public void testEscapeLeadingAndTrailingSpace()
1312 throws ConfigInvalidException {
1313 assertValueRoundTrip(" x ", "\" x \"");
1314 assertValueRoundTrip(" x ", "\" x \"");
1315 assertValueRoundTrip(" x ", "\" x \"");
1316 assertValueRoundTrip(" x ", "\" x \"");
1317 }
1318
1319 @Test
1320 public void testNoEscapeInternalSpaces() throws ConfigInvalidException {
1321 assertValueRoundTrip("x y");
1322 assertValueRoundTrip("x y");
1323 assertValueRoundTrip("x y");
1324 assertValueRoundTrip("x y z");
1325 assertValueRoundTrip("x " + WS + " y");
1326 }
1327
1328 @Test
1329 public void testNoEscapeSpecialCharacters() throws ConfigInvalidException {
1330 assertValueRoundTrip("x\\y", "x\\\\y");
1331 assertValueRoundTrip("x\"y", "x\\\"y");
1332 assertValueRoundTrip("x\ny", "x\\ny");
1333 assertValueRoundTrip("x\ty", "x\\ty");
1334 assertValueRoundTrip("x\by", "x\\by");
1335 }
1336
1337 @Test
1338 public void testParseLiteralBackspace() throws ConfigInvalidException {
1339
1340
1341 assertEquals("x\by", parseEscapedValue("x\by"));
1342 }
1343
1344 @Test
1345 public void testEscapeCommentCharacters() throws ConfigInvalidException {
1346 assertValueRoundTrip("x#y", "\"x#y\"");
1347 assertValueRoundTrip("x;y", "\"x;y\"");
1348 }
1349
1350 @Test
1351 public void testEscapeValueInvalidCharacters() {
1352 assertIllegalArgumentException(() -> Config.escapeSubsection("x\0y"));
1353 }
1354
1355 @Test
1356 public void testEscapeSubsectionInvalidCharacters() {
1357 assertIllegalArgumentException(() -> Config.escapeSubsection("x\ny"));
1358 assertIllegalArgumentException(() -> Config.escapeSubsection("x\0y"));
1359 }
1360
1361 @Test
1362 public void testParseMultipleQuotedRegions() throws ConfigInvalidException {
1363 assertEquals("b a z; \n", parseEscapedValue("b\" a\"\" z; \\n\""));
1364 }
1365
1366 @Test
1367 public void testParseComments() throws ConfigInvalidException {
1368 assertEquals("baz", parseEscapedValue("baz; comment"));
1369 assertEquals("baz", parseEscapedValue("baz# comment"));
1370 assertEquals("baz", parseEscapedValue("baz ; comment"));
1371 assertEquals("baz", parseEscapedValue("baz # comment"));
1372
1373 assertEquals("baz", parseEscapedValue("baz ; comment"));
1374 assertEquals("baz", parseEscapedValue("baz # comment"));
1375 assertEquals("baz", parseEscapedValue("baz " + WS + " ; comment"));
1376 assertEquals("baz", parseEscapedValue("baz " + WS + " # comment"));
1377
1378 assertEquals("baz ", parseEscapedValue("\"baz \"; comment"));
1379 assertEquals("baz ", parseEscapedValue("\"baz \"# comment"));
1380 assertEquals("baz ", parseEscapedValue("\"baz \" ; comment"));
1381 assertEquals("baz ", parseEscapedValue("\"baz \" # comment"));
1382 }
1383
1384 @Test
1385 public void testEscapeSubsection() throws ConfigInvalidException {
1386 assertSubsectionRoundTrip("", "\"\"");
1387 assertSubsectionRoundTrip("x", "\"x\"");
1388 assertSubsectionRoundTrip(" x", "\" x\"");
1389 assertSubsectionRoundTrip("x ", "\"x \"");
1390 assertSubsectionRoundTrip(" x ", "\" x \"");
1391 assertSubsectionRoundTrip("x y", "\"x y\"");
1392 assertSubsectionRoundTrip("x y", "\"x y\"");
1393 assertSubsectionRoundTrip("x\\y", "\"x\\\\y\"");
1394 assertSubsectionRoundTrip("x\"y", "\"x\\\"y\"");
1395
1396
1397 assertSubsectionRoundTrip("x\by", "\"x\by\"");
1398 assertSubsectionRoundTrip("x\ty", "\"x\ty\"");
1399 }
1400
1401 @Test
1402 public void testParseInvalidValues() {
1403 assertInvalidValue(JGitText.get().newlineInQuotesNotAllowed, "x\"\n\"y");
1404 assertInvalidValue(JGitText.get().endOfFileInEscape, "x\\");
1405 assertInvalidValue(
1406 MessageFormat.format(JGitText.get().badEscape, 'q'), "x\\q");
1407 }
1408
1409 @Test
1410 public void testParseInvalidSubsections() {
1411 assertInvalidSubsection(
1412 JGitText.get().newlineInQuotesNotAllowed, "\"x\ny\"");
1413 }
1414
1415 @Test
1416 public void testDropBackslashFromInvalidEscapeSequenceInSubsectionName()
1417 throws ConfigInvalidException {
1418 assertEquals("x0", parseEscapedSubsection("\"x\\0\""));
1419 assertEquals("xq", parseEscapedSubsection("\"x\\q\""));
1420
1421 assertEquals("xb", parseEscapedSubsection("\"x\\b\""));
1422 assertEquals("xn", parseEscapedSubsection("\"x\\n\""));
1423 assertEquals("xt", parseEscapedSubsection("\"x\\t\""));
1424 }
1425
1426 @Test
1427 public void testInvalidGroupHeader() {
1428 assertThrows(JGitText.get().badGroupHeader,
1429 ConfigInvalidException.class,
1430 () -> parse("[foo \"bar\" ]\nfoo=bar\n"));
1431 }
1432
1433 @Test
1434 public void testCrLf() throws ConfigInvalidException {
1435 assertEquals("true", parseEscapedValue("true\r\n"));
1436 }
1437
1438 @Test
1439 public void testLfContinuation() throws ConfigInvalidException {
1440 assertEquals("true", parseEscapedValue("tr\\\nue"));
1441 }
1442
1443 @Test
1444 public void testCrCharContinuation() {
1445 assertThrows("Bad escape: \\u000d", ConfigInvalidException.class,
1446 () -> parseEscapedValue("tr\\\rue"));
1447 }
1448
1449 @Test
1450 public void testCrEOFContinuation() {
1451 assertThrows("Bad escape: \\u000d", ConfigInvalidException.class,
1452 () -> parseEscapedValue("tr\\\r"));
1453 }
1454
1455 @Test
1456 public void testCrLfContinuation() throws ConfigInvalidException {
1457 assertEquals("true", parseEscapedValue("tr\\\r\nue"));
1458 }
1459
1460 @Test
1461 public void testWhitespaceContinuation() throws ConfigInvalidException {
1462 assertEquals("tr ue", parseEscapedValue("tr \\\n ue"));
1463 assertEquals("tr ue", parseEscapedValue("tr \\\r\n ue"));
1464 }
1465
1466 private static void assertValueRoundTrip(String value)
1467 throws ConfigInvalidException {
1468 assertValueRoundTrip(value, value);
1469 }
1470
1471 private static void assertValueRoundTrip(String value, String expectedEscaped)
1472 throws ConfigInvalidException {
1473 String escaped = Config.escapeValue(value);
1474 assertEquals("escape failed;", expectedEscaped, escaped);
1475 assertEquals("parse failed;", value, parseEscapedValue(escaped));
1476 }
1477
1478 private static String parseEscapedValue(String escapedValue)
1479 throws ConfigInvalidException {
1480 String text = "[foo]\nbar=" + escapedValue;
1481 Config c = parse(text);
1482 return c.getString("foo", null, "bar");
1483 }
1484
1485 private static void assertInvalidValue(String expectedMessage,
1486 String escapedValue) {
1487 try {
1488 parseEscapedValue(escapedValue);
1489 fail("expected ConfigInvalidException");
1490 } catch (ConfigInvalidException e) {
1491 assertEquals(expectedMessage, e.getMessage());
1492 }
1493 }
1494
1495 private static void assertSubsectionRoundTrip(String subsection,
1496 String expectedEscaped) throws ConfigInvalidException {
1497 String escaped = Config.escapeSubsection(subsection);
1498 assertEquals("escape failed;", expectedEscaped, escaped);
1499 assertEquals("parse failed;", subsection, parseEscapedSubsection(escaped));
1500 }
1501
1502 private static String parseEscapedSubsection(String escapedSubsection)
1503 throws ConfigInvalidException {
1504 String text = "[foo " + escapedSubsection + "]\nbar = value";
1505 Config c = parse(text);
1506 Set<String> subsections = c.getSubsections("foo");
1507 assertEquals("only one section", 1, subsections.size());
1508 return subsections.iterator().next();
1509 }
1510
1511 private static void assertIllegalArgumentException(Runnable r) {
1512 try {
1513 r.run();
1514 fail("expected IllegalArgumentException");
1515 } catch (IllegalArgumentException e) {
1516
1517 }
1518 }
1519
1520 private static void assertInvalidSubsection(String expectedMessage,
1521 String escapedSubsection) {
1522 try {
1523 parseEscapedSubsection(escapedSubsection);
1524 fail("expected ConfigInvalidException");
1525 } catch (ConfigInvalidException e) {
1526 assertEquals(expectedMessage, e.getMessage());
1527 }
1528 }
1529
1530 private static FileBasedConfig loadConfig(File file)
1531 throws IOException, ConfigInvalidException {
1532 final FileBasedConfig config = new FileBasedConfig(null, file,
1533 FS.DETECTED);
1534 config.load();
1535 return config;
1536 }
1537 }