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