You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ConfigTest.java 44KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232
  1. /*
  2. * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
  3. * Copyright (C) 2009-2010, Google Inc.
  4. * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
  5. * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
  6. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  7. * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
  8. * and other copyright owners as documented in the project's IP log.
  9. *
  10. * This program and the accompanying materials are made available
  11. * under the terms of the Eclipse Distribution License v1.0 which
  12. * accompanies this distribution, is reproduced below, and is
  13. * available at http://www.eclipse.org/org/documents/edl-v10.php
  14. *
  15. * All rights reserved.
  16. *
  17. * Redistribution and use in source and binary forms, with or
  18. * without modification, are permitted provided that the following
  19. * conditions are met:
  20. *
  21. * - Redistributions of source code must retain the above copyright
  22. * notice, this list of conditions and the following disclaimer.
  23. *
  24. * - Redistributions in binary form must reproduce the above
  25. * copyright notice, this list of conditions and the following
  26. * disclaimer in the documentation and/or other materials provided
  27. * with the distribution.
  28. *
  29. * - Neither the name of the Eclipse Foundation, Inc. nor the
  30. * names of its contributors may be used to endorse or promote
  31. * products derived from this software without specific prior
  32. * written permission.
  33. *
  34. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  35. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  36. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  38. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  39. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  43. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  46. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  47. */
  48. package org.eclipse.jgit.lib;
  49. import static java.util.concurrent.TimeUnit.DAYS;
  50. import static java.util.concurrent.TimeUnit.HOURS;
  51. import static java.util.concurrent.TimeUnit.MILLISECONDS;
  52. import static java.util.concurrent.TimeUnit.MINUTES;
  53. import static java.util.concurrent.TimeUnit.NANOSECONDS;
  54. import static java.util.concurrent.TimeUnit.MICROSECONDS;
  55. import static java.util.concurrent.TimeUnit.SECONDS;
  56. import static org.eclipse.jgit.util.FileUtils.pathToString;
  57. import static org.junit.Assert.assertArrayEquals;
  58. import static org.junit.Assert.assertEquals;
  59. import static org.junit.Assert.assertFalse;
  60. import static org.junit.Assert.assertNull;
  61. import static org.junit.Assert.assertSame;
  62. import static org.junit.Assert.assertTrue;
  63. import static org.junit.Assert.fail;
  64. import java.io.File;
  65. import java.io.IOException;
  66. import java.nio.file.Files;
  67. import java.text.MessageFormat;
  68. import java.util.Arrays;
  69. import java.util.Iterator;
  70. import java.util.LinkedList;
  71. import java.util.Set;
  72. import java.util.concurrent.TimeUnit;
  73. import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
  74. import org.eclipse.jgit.errors.ConfigInvalidException;
  75. import org.eclipse.jgit.internal.JGitText;
  76. import org.eclipse.jgit.junit.MockSystemReader;
  77. import org.eclipse.jgit.merge.MergeConfig;
  78. import org.eclipse.jgit.storage.file.FileBasedConfig;
  79. import org.eclipse.jgit.util.FS;
  80. import org.eclipse.jgit.util.SystemReader;
  81. import org.junit.After;
  82. import org.junit.Rule;
  83. import org.junit.Test;
  84. import org.junit.rules.ExpectedException;
  85. import org.junit.rules.TemporaryFolder;
  86. /**
  87. * Test reading of git config
  88. */
  89. @SuppressWarnings("boxing")
  90. public class ConfigTest {
  91. // A non-ASCII whitespace character: U+2002 EN QUAD.
  92. private static final char WS = '\u2002';
  93. @Rule
  94. public ExpectedException expectedEx = ExpectedException.none();
  95. @Rule
  96. public TemporaryFolder tmp = new TemporaryFolder();
  97. @After
  98. public void tearDown() {
  99. SystemReader.setInstance(null);
  100. }
  101. @Test
  102. public void test001_ReadBareKey() throws ConfigInvalidException {
  103. final Config c = parse("[foo]\nbar\n");
  104. assertTrue(c.getBoolean("foo", null, "bar", false));
  105. assertEquals("", c.getString("foo", null, "bar"));
  106. }
  107. @Test
  108. public void test002_ReadWithSubsection() throws ConfigInvalidException {
  109. final Config c = parse("[foo \"zip\"]\nbar\n[foo \"zap\"]\nbar=false\nn=3\n");
  110. assertTrue(c.getBoolean("foo", "zip", "bar", false));
  111. assertEquals("", c.getString("foo","zip", "bar"));
  112. assertFalse(c.getBoolean("foo", "zap", "bar", true));
  113. assertEquals("false", c.getString("foo", "zap", "bar"));
  114. assertEquals(3, c.getInt("foo", "zap", "n", 4));
  115. assertEquals(4, c.getInt("foo", "zap","m", 4));
  116. }
  117. @Test
  118. public void test003_PutRemote() {
  119. final Config c = new Config();
  120. c.setString("sec", "ext", "name", "value");
  121. c.setString("sec", "ext", "name2", "value2");
  122. final String expText = "[sec \"ext\"]\n\tname = value\n\tname2 = value2\n";
  123. assertEquals(expText, c.toText());
  124. }
  125. @Test
  126. public void test004_PutGetSimple() {
  127. Config c = new Config();
  128. c.setString("my", null, "somename", "false");
  129. assertEquals("false", c.getString("my", null, "somename"));
  130. assertEquals("[my]\n\tsomename = false\n", c.toText());
  131. }
  132. @Test
  133. public void test005_PutGetStringList() {
  134. Config c = new Config();
  135. final LinkedList<String> values = new LinkedList<>();
  136. values.add("value1");
  137. values.add("value2");
  138. c.setStringList("my", null, "somename", values);
  139. final Object[] expArr = values.toArray();
  140. final String[] actArr = c.getStringList("my", null, "somename");
  141. assertArrayEquals(expArr, actArr);
  142. final String expText = "[my]\n\tsomename = value1\n\tsomename = value2\n";
  143. assertEquals(expText, c.toText());
  144. }
  145. @Test
  146. public void test006_readCaseInsensitive() throws ConfigInvalidException {
  147. final Config c = parse("[Foo]\nBar\n");
  148. assertTrue(c.getBoolean("foo", null, "bar", false));
  149. assertEquals("", c.getString("foo", null, "bar"));
  150. }
  151. @Test
  152. public void test007_readUserConfig() {
  153. final MockSystemReader mockSystemReader = new MockSystemReader();
  154. SystemReader.setInstance(mockSystemReader);
  155. final String hostname = mockSystemReader.getHostname();
  156. final Config userGitConfig = mockSystemReader.openUserConfig(null,
  157. FS.DETECTED);
  158. final Config localConfig = new Config(userGitConfig);
  159. mockSystemReader.clearProperties();
  160. String authorName;
  161. String authorEmail;
  162. // no values defined nowhere
  163. authorName = localConfig.get(UserConfig.KEY).getAuthorName();
  164. authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
  165. assertEquals(Constants.UNKNOWN_USER_DEFAULT, authorName);
  166. assertEquals(Constants.UNKNOWN_USER_DEFAULT + "@" + hostname, authorEmail);
  167. assertTrue(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
  168. assertTrue(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
  169. // the system user name is defined
  170. mockSystemReader.setProperty(Constants.OS_USER_NAME_KEY, "os user name");
  171. localConfig.uncache(UserConfig.KEY);
  172. authorName = localConfig.get(UserConfig.KEY).getAuthorName();
  173. assertEquals("os user name", authorName);
  174. assertTrue(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
  175. if (hostname != null && hostname.length() != 0) {
  176. authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
  177. assertEquals("os user name@" + hostname, authorEmail);
  178. }
  179. assertTrue(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
  180. // the git environment variables are defined
  181. mockSystemReader.setProperty(Constants.GIT_AUTHOR_NAME_KEY, "git author name");
  182. mockSystemReader.setProperty(Constants.GIT_AUTHOR_EMAIL_KEY, "author@email");
  183. localConfig.uncache(UserConfig.KEY);
  184. authorName = localConfig.get(UserConfig.KEY).getAuthorName();
  185. authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
  186. assertEquals("git author name", authorName);
  187. assertEquals("author@email", authorEmail);
  188. assertFalse(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
  189. assertFalse(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
  190. // the values are defined in the global configuration
  191. // first clear environment variables since they would override
  192. // configuration files
  193. mockSystemReader.clearProperties();
  194. userGitConfig.setString("user", null, "name", "global username");
  195. userGitConfig.setString("user", null, "email", "author@globalemail");
  196. authorName = localConfig.get(UserConfig.KEY).getAuthorName();
  197. authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
  198. assertEquals("global username", authorName);
  199. assertEquals("author@globalemail", authorEmail);
  200. assertFalse(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
  201. assertFalse(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
  202. // the values are defined in the local configuration
  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. authorName = localConfig.get(UserConfig.KEY).getCommitterName();
  212. authorEmail = localConfig.get(UserConfig.KEY).getCommitterEmail();
  213. assertEquals("local username", authorName);
  214. assertEquals("author@localemail", authorEmail);
  215. assertFalse(localConfig.get(UserConfig.KEY).isCommitterNameImplicit());
  216. assertFalse(localConfig.get(UserConfig.KEY).isCommitterEmailImplicit());
  217. // also git environment variables are defined
  218. mockSystemReader.setProperty(Constants.GIT_AUTHOR_NAME_KEY,
  219. "git author name");
  220. mockSystemReader.setProperty(Constants.GIT_AUTHOR_EMAIL_KEY,
  221. "author@email");
  222. localConfig.setString("user", null, "name", "local username");
  223. localConfig.setString("user", null, "email", "author@localemail");
  224. authorName = localConfig.get(UserConfig.KEY).getAuthorName();
  225. authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
  226. assertEquals("git author name", authorName);
  227. assertEquals("author@email", authorEmail);
  228. assertFalse(localConfig.get(UserConfig.KEY).isAuthorNameImplicit());
  229. assertFalse(localConfig.get(UserConfig.KEY).isAuthorEmailImplicit());
  230. }
  231. @Test
  232. public void testReadUserConfigWithInvalidCharactersStripped() {
  233. final MockSystemReader mockSystemReader = new MockSystemReader();
  234. final Config localConfig = new Config(mockSystemReader.openUserConfig(
  235. null, FS.DETECTED));
  236. localConfig.setString("user", null, "name", "foo<bar");
  237. localConfig.setString("user", null, "email", "baz>\nqux@example.com");
  238. UserConfig userConfig = localConfig.get(UserConfig.KEY);
  239. assertEquals("foobar", userConfig.getAuthorName());
  240. assertEquals("bazqux@example.com", userConfig.getAuthorEmail());
  241. }
  242. @Test
  243. public void testReadBoolean_TrueFalse1() throws ConfigInvalidException {
  244. final Config c = parse("[s]\na = true\nb = false\n");
  245. assertEquals("true", c.getString("s", null, "a"));
  246. assertEquals("false", c.getString("s", null, "b"));
  247. assertTrue(c.getBoolean("s", "a", false));
  248. assertFalse(c.getBoolean("s", "b", true));
  249. }
  250. @Test
  251. public void testReadBoolean_TrueFalse2() throws ConfigInvalidException {
  252. final Config c = parse("[s]\na = TrUe\nb = fAlSe\n");
  253. assertEquals("TrUe", c.getString("s", null, "a"));
  254. assertEquals("fAlSe", c.getString("s", null, "b"));
  255. assertTrue(c.getBoolean("s", "a", false));
  256. assertFalse(c.getBoolean("s", "b", true));
  257. }
  258. @Test
  259. public void testReadBoolean_YesNo1() throws ConfigInvalidException {
  260. final Config c = parse("[s]\na = yes\nb = no\n");
  261. assertEquals("yes", c.getString("s", null, "a"));
  262. assertEquals("no", c.getString("s", null, "b"));
  263. assertTrue(c.getBoolean("s", "a", false));
  264. assertFalse(c.getBoolean("s", "b", true));
  265. }
  266. @Test
  267. public void testReadBoolean_YesNo2() throws ConfigInvalidException {
  268. final Config c = parse("[s]\na = yEs\nb = NO\n");
  269. assertEquals("yEs", c.getString("s", null, "a"));
  270. assertEquals("NO", c.getString("s", null, "b"));
  271. assertTrue(c.getBoolean("s", "a", false));
  272. assertFalse(c.getBoolean("s", "b", true));
  273. }
  274. @Test
  275. public void testReadBoolean_OnOff1() throws ConfigInvalidException {
  276. final Config c = parse("[s]\na = on\nb = off\n");
  277. assertEquals("on", c.getString("s", null, "a"));
  278. assertEquals("off", c.getString("s", null, "b"));
  279. assertTrue(c.getBoolean("s", "a", false));
  280. assertFalse(c.getBoolean("s", "b", true));
  281. }
  282. @Test
  283. public void testReadBoolean_OnOff2() throws ConfigInvalidException {
  284. final Config c = parse("[s]\na = ON\nb = OFF\n");
  285. assertEquals("ON", c.getString("s", null, "a"));
  286. assertEquals("OFF", c.getString("s", null, "b"));
  287. assertTrue(c.getBoolean("s", "a", false));
  288. assertFalse(c.getBoolean("s", "b", true));
  289. }
  290. static enum TestEnum {
  291. ONE_TWO;
  292. }
  293. @Test
  294. public void testGetEnum() throws ConfigInvalidException {
  295. Config c = parse("[s]\na = ON\nb = input\nc = true\nd = off\n");
  296. assertSame(CoreConfig.AutoCRLF.TRUE, c.getEnum("s", null, "a",
  297. CoreConfig.AutoCRLF.FALSE));
  298. assertSame(CoreConfig.AutoCRLF.INPUT, c.getEnum("s", null, "b",
  299. CoreConfig.AutoCRLF.FALSE));
  300. assertSame(CoreConfig.AutoCRLF.TRUE, c.getEnum("s", null, "c",
  301. CoreConfig.AutoCRLF.FALSE));
  302. assertSame(CoreConfig.AutoCRLF.FALSE, c.getEnum("s", null, "d",
  303. CoreConfig.AutoCRLF.TRUE));
  304. c = new Config();
  305. assertSame(CoreConfig.AutoCRLF.FALSE, c.getEnum("s", null, "d",
  306. CoreConfig.AutoCRLF.FALSE));
  307. c = parse("[s \"b\"]\n\tc = one two\n");
  308. assertSame(TestEnum.ONE_TWO, c.getEnum("s", "b", "c", TestEnum.ONE_TWO));
  309. c = parse("[s \"b\"]\n\tc = one-two\n");
  310. assertSame(TestEnum.ONE_TWO, c.getEnum("s", "b", "c", TestEnum.ONE_TWO));
  311. }
  312. @Test
  313. public void testGetInvalidEnum() throws ConfigInvalidException {
  314. Config c = parse("[a]\n\tb = invalid\n");
  315. try {
  316. c.getEnum("a", null, "b", TestEnum.ONE_TWO);
  317. fail();
  318. } catch (IllegalArgumentException e) {
  319. assertEquals("Invalid value: a.b=invalid", e.getMessage());
  320. }
  321. c = parse("[a \"b\"]\n\tc = invalid\n");
  322. try {
  323. c.getEnum("a", "b", "c", TestEnum.ONE_TWO);
  324. fail();
  325. } catch (IllegalArgumentException e) {
  326. assertEquals("Invalid value: a.b.c=invalid", e.getMessage());
  327. }
  328. }
  329. @Test
  330. public void testSetEnum() {
  331. final Config c = new Config();
  332. c.setEnum("s", "b", "c", TestEnum.ONE_TWO);
  333. assertEquals("[s \"b\"]\n\tc = one two\n", c.toText());
  334. }
  335. @Test
  336. public void testGetFastForwardMergeoptions() throws ConfigInvalidException {
  337. Config c = new Config(null); // not set
  338. assertSame(FastForwardMode.FF, c.getEnum(
  339. ConfigConstants.CONFIG_BRANCH_SECTION, "side",
  340. ConfigConstants.CONFIG_KEY_MERGEOPTIONS, FastForwardMode.FF));
  341. MergeConfig mergeConfig = c.get(MergeConfig.getParser("side"));
  342. assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
  343. c = parse("[branch \"side\"]\n\tmergeoptions = --ff-only\n");
  344. assertSame(FastForwardMode.FF_ONLY, c.getEnum(
  345. ConfigConstants.CONFIG_BRANCH_SECTION, "side",
  346. ConfigConstants.CONFIG_KEY_MERGEOPTIONS,
  347. FastForwardMode.FF_ONLY));
  348. mergeConfig = c.get(MergeConfig.getParser("side"));
  349. assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
  350. c = parse("[branch \"side\"]\n\tmergeoptions = --ff\n");
  351. assertSame(FastForwardMode.FF, c.getEnum(
  352. ConfigConstants.CONFIG_BRANCH_SECTION, "side",
  353. ConfigConstants.CONFIG_KEY_MERGEOPTIONS, FastForwardMode.FF));
  354. mergeConfig = c.get(MergeConfig.getParser("side"));
  355. assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
  356. c = parse("[branch \"side\"]\n\tmergeoptions = --no-ff\n");
  357. assertSame(FastForwardMode.NO_FF, c.getEnum(
  358. ConfigConstants.CONFIG_BRANCH_SECTION, "side",
  359. ConfigConstants.CONFIG_KEY_MERGEOPTIONS, FastForwardMode.NO_FF));
  360. mergeConfig = c.get(MergeConfig.getParser("side"));
  361. assertSame(FastForwardMode.NO_FF, mergeConfig.getFastForwardMode());
  362. }
  363. @Test
  364. public void testSetFastForwardMergeoptions() {
  365. final Config c = new Config();
  366. c.setEnum("branch", "side", "mergeoptions", FastForwardMode.FF);
  367. assertEquals("[branch \"side\"]\n\tmergeoptions = --ff\n", c.toText());
  368. c.setEnum("branch", "side", "mergeoptions", FastForwardMode.FF_ONLY);
  369. assertEquals("[branch \"side\"]\n\tmergeoptions = --ff-only\n",
  370. c.toText());
  371. c.setEnum("branch", "side", "mergeoptions", FastForwardMode.NO_FF);
  372. assertEquals("[branch \"side\"]\n\tmergeoptions = --no-ff\n",
  373. c.toText());
  374. }
  375. @Test
  376. public void testGetFastForwardMerge() throws ConfigInvalidException {
  377. Config c = new Config(null); // not set
  378. assertSame(FastForwardMode.Merge.TRUE, c.getEnum(
  379. ConfigConstants.CONFIG_KEY_MERGE, null,
  380. ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.TRUE));
  381. MergeConfig mergeConfig = c.get(MergeConfig.getParser("side"));
  382. assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
  383. c = parse("[merge]\n\tff = only\n");
  384. assertSame(FastForwardMode.Merge.ONLY, c.getEnum(
  385. ConfigConstants.CONFIG_KEY_MERGE, null,
  386. ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.ONLY));
  387. mergeConfig = c.get(MergeConfig.getParser("side"));
  388. assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
  389. c = parse("[merge]\n\tff = true\n");
  390. assertSame(FastForwardMode.Merge.TRUE, c.getEnum(
  391. ConfigConstants.CONFIG_KEY_MERGE, null,
  392. ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.TRUE));
  393. mergeConfig = c.get(MergeConfig.getParser("side"));
  394. assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
  395. c = parse("[merge]\n\tff = false\n");
  396. assertSame(FastForwardMode.Merge.FALSE, c.getEnum(
  397. ConfigConstants.CONFIG_KEY_MERGE, null,
  398. ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.FALSE));
  399. mergeConfig = c.get(MergeConfig.getParser("side"));
  400. assertSame(FastForwardMode.NO_FF, mergeConfig.getFastForwardMode());
  401. }
  402. @Test
  403. public void testCombinedMergeOptions() throws ConfigInvalidException {
  404. Config c = new Config(null); // not set
  405. MergeConfig mergeConfig = c.get(MergeConfig.getParser("side"));
  406. assertSame(FastForwardMode.FF, mergeConfig.getFastForwardMode());
  407. assertTrue(mergeConfig.isCommit());
  408. assertFalse(mergeConfig.isSquash());
  409. // branch..mergeoptions should win over merge.ff
  410. c = parse("[merge]\n\tff = false\n"
  411. + "[branch \"side\"]\n\tmergeoptions = --ff-only\n");
  412. mergeConfig = c.get(MergeConfig.getParser("side"));
  413. assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
  414. assertTrue(mergeConfig.isCommit());
  415. assertFalse(mergeConfig.isSquash());
  416. // merge.ff used for ff setting if not set via mergeoptions
  417. c = parse("[merge]\n\tff = only\n"
  418. + "[branch \"side\"]\n\tmergeoptions = --squash\n");
  419. mergeConfig = c.get(MergeConfig.getParser("side"));
  420. assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
  421. assertTrue(mergeConfig.isCommit());
  422. assertTrue(mergeConfig.isSquash());
  423. // mergeoptions wins if it has ff options amongst other options
  424. c = parse("[merge]\n\tff = false\n"
  425. + "[branch \"side\"]\n\tmergeoptions = --ff-only --no-commit\n");
  426. mergeConfig = c.get(MergeConfig.getParser("side"));
  427. assertSame(FastForwardMode.FF_ONLY, mergeConfig.getFastForwardMode());
  428. assertFalse(mergeConfig.isCommit());
  429. assertFalse(mergeConfig.isSquash());
  430. }
  431. @Test
  432. public void testSetFastForwardMerge() {
  433. final Config c = new Config();
  434. c.setEnum("merge", null, "ff",
  435. FastForwardMode.Merge.valueOf(FastForwardMode.FF));
  436. assertEquals("[merge]\n\tff = true\n", c.toText());
  437. c.setEnum("merge", null, "ff",
  438. FastForwardMode.Merge.valueOf(FastForwardMode.FF_ONLY));
  439. assertEquals("[merge]\n\tff = only\n", c.toText());
  440. c.setEnum("merge", null, "ff",
  441. FastForwardMode.Merge.valueOf(FastForwardMode.NO_FF));
  442. assertEquals("[merge]\n\tff = false\n", c.toText());
  443. }
  444. @Test
  445. public void testReadLong() throws ConfigInvalidException {
  446. assertReadLong(1L);
  447. assertReadLong(-1L);
  448. assertReadLong(Long.MIN_VALUE);
  449. assertReadLong(Long.MAX_VALUE);
  450. assertReadLong(4L * 1024 * 1024 * 1024, "4g");
  451. assertReadLong(3L * 1024 * 1024, "3 m");
  452. assertReadLong(8L * 1024, "8 k");
  453. try {
  454. assertReadLong(-1, "1.5g");
  455. fail("incorrectly accepted 1.5g");
  456. } catch (IllegalArgumentException e) {
  457. assertEquals("Invalid integer value: s.a=1.5g", e.getMessage());
  458. }
  459. }
  460. @Test
  461. public void testBooleanWithNoValue() throws ConfigInvalidException {
  462. Config c = parse("[my]\n\tempty\n");
  463. assertEquals("", c.getString("my", null, "empty"));
  464. assertEquals(1, c.getStringList("my", null, "empty").length);
  465. assertEquals("", c.getStringList("my", null, "empty")[0]);
  466. assertTrue(c.getBoolean("my", "empty", false));
  467. assertEquals("[my]\n\tempty\n", c.toText());
  468. }
  469. @Test
  470. public void testUnsetBranchSection() throws ConfigInvalidException {
  471. Config c = parse("" //
  472. + "[branch \"keep\"]\n"
  473. + " merge = master.branch.to.keep.in.the.file\n"
  474. + "\n"
  475. + "[branch \"remove\"]\n"
  476. + " merge = this.will.get.deleted\n"
  477. + " remote = origin-for-some-long-gone-place\n"
  478. + "\n"
  479. + "[core-section-not-to-remove-in-test]\n"
  480. + " packedGitLimit = 14\n");
  481. c.unsetSection("branch", "does.not.exist");
  482. c.unsetSection("branch", "remove");
  483. assertEquals("" //
  484. + "[branch \"keep\"]\n"
  485. + " merge = master.branch.to.keep.in.the.file\n"
  486. + "\n"
  487. + "[core-section-not-to-remove-in-test]\n"
  488. + " packedGitLimit = 14\n", c.toText());
  489. }
  490. @Test
  491. public void testUnsetSingleSection() throws ConfigInvalidException {
  492. Config c = parse("" //
  493. + "[branch \"keep\"]\n"
  494. + " merge = master.branch.to.keep.in.the.file\n"
  495. + "\n"
  496. + "[single]\n"
  497. + " merge = this.will.get.deleted\n"
  498. + " remote = origin-for-some-long-gone-place\n"
  499. + "\n"
  500. + "[core-section-not-to-remove-in-test]\n"
  501. + " packedGitLimit = 14\n");
  502. c.unsetSection("single", null);
  503. assertEquals("" //
  504. + "[branch \"keep\"]\n"
  505. + " merge = master.branch.to.keep.in.the.file\n"
  506. + "\n"
  507. + "[core-section-not-to-remove-in-test]\n"
  508. + " packedGitLimit = 14\n", c.toText());
  509. }
  510. @Test
  511. public void test008_readSectionNames() throws ConfigInvalidException {
  512. final Config c = parse("[a]\n [B]\n");
  513. Set<String> sections = c.getSections();
  514. assertTrue("Sections should contain \"a\"", sections.contains("a"));
  515. assertTrue("Sections should contain \"b\"", sections.contains("b"));
  516. }
  517. @Test
  518. public void test009_readNamesInSection() throws ConfigInvalidException {
  519. String configString = "[core]\n" + "repositoryFormatVersion = 0\n"
  520. + "filemode = false\n" + "logAllRefUpdates = true\n";
  521. final Config c = parse(configString);
  522. Set<String> names = c.getNames("core");
  523. assertEquals("Core section size", 3, names.size());
  524. assertTrue("Core section should contain \"filemode\"", names
  525. .contains("filemode"));
  526. assertTrue("Core section should contain \"repositoryFormatVersion\"",
  527. names.contains("repositoryFormatVersion"));
  528. assertTrue("Core section should contain \"repositoryformatversion\"",
  529. names.contains("repositoryformatversion"));
  530. Iterator<String> itr = names.iterator();
  531. assertEquals("filemode", itr.next());
  532. assertEquals("logAllRefUpdates", itr.next());
  533. assertEquals("repositoryFormatVersion", itr.next());
  534. assertFalse(itr.hasNext());
  535. }
  536. @Test
  537. public void test_ReadNamesInSectionRecursive()
  538. throws ConfigInvalidException {
  539. String baseConfigString = "[core]\n" + "logAllRefUpdates = true\n";
  540. String configString = "[core]\n" + "repositoryFormatVersion = 0\n"
  541. + "filemode = false\n";
  542. final Config c = parse(configString, parse(baseConfigString));
  543. Set<String> names = c.getNames("core", true);
  544. assertEquals("Core section size", 3, names.size());
  545. assertTrue("Core section should contain \"filemode\"",
  546. names.contains("filemode"));
  547. assertTrue("Core section should contain \"repositoryFormatVersion\"",
  548. names.contains("repositoryFormatVersion"));
  549. assertTrue("Core section should contain \"logAllRefUpdates\"",
  550. names.contains("logAllRefUpdates"));
  551. assertTrue("Core section should contain \"logallrefupdates\"",
  552. names.contains("logallrefupdates"));
  553. Iterator<String> itr = names.iterator();
  554. assertEquals("filemode", itr.next());
  555. assertEquals("repositoryFormatVersion", itr.next());
  556. assertEquals("logAllRefUpdates", itr.next());
  557. assertFalse(itr.hasNext());
  558. }
  559. @Test
  560. public void test010_readNamesInSubSection() throws ConfigInvalidException {
  561. String configString = "[a \"sub1\"]\n"//
  562. + "x = 0\n" //
  563. + "y = false\n"//
  564. + "z = true\n"//
  565. + "[a \"sub2\"]\n"//
  566. + "a=0\n"//
  567. + "b=1\n";
  568. final Config c = parse(configString);
  569. Set<String> names = c.getNames("a", "sub1");
  570. assertEquals("Subsection size", 3, names.size());
  571. assertTrue("Subsection should contain \"x\"", names.contains("x"));
  572. assertTrue("Subsection should contain \"y\"", names.contains("y"));
  573. assertTrue("Subsection should contain \"z\"", names.contains("z"));
  574. names = c.getNames("a", "sub2");
  575. assertEquals("Subsection size", 2, names.size());
  576. assertTrue("Subsection should contain \"a\"", names.contains("a"));
  577. assertTrue("Subsection should contain \"b\"", names.contains("b"));
  578. }
  579. @Test
  580. public void readNamesInSubSectionRecursive() throws ConfigInvalidException {
  581. String baseConfigString = "[a \"sub1\"]\n"//
  582. + "x = 0\n" //
  583. + "y = false\n"//
  584. + "[a \"sub2\"]\n"//
  585. + "A=0\n";//
  586. String configString = "[a \"sub1\"]\n"//
  587. + "z = true\n"//
  588. + "[a \"sub2\"]\n"//
  589. + "B=1\n";
  590. final Config c = parse(configString, parse(baseConfigString));
  591. Set<String> names = c.getNames("a", "sub1", true);
  592. assertEquals("Subsection size", 3, names.size());
  593. assertTrue("Subsection should contain \"x\"", names.contains("x"));
  594. assertTrue("Subsection should contain \"y\"", names.contains("y"));
  595. assertTrue("Subsection should contain \"z\"", names.contains("z"));
  596. names = c.getNames("a", "sub2", true);
  597. assertEquals("Subsection size", 2, names.size());
  598. assertTrue("Subsection should contain \"A\"", names.contains("A"));
  599. assertTrue("Subsection should contain \"a\"", names.contains("a"));
  600. assertTrue("Subsection should contain \"B\"", names.contains("B"));
  601. }
  602. @Test
  603. public void testNoFinalNewline() throws ConfigInvalidException {
  604. Config c = parse("[a]\n"
  605. + "x = 0\n"
  606. + "y = 1");
  607. assertEquals("0", c.getString("a", null, "x"));
  608. assertEquals("1", c.getString("a", null, "y"));
  609. }
  610. @Test
  611. public void testExplicitlySetEmptyString() throws Exception {
  612. Config c = new Config();
  613. c.setString("a", null, "x", "0");
  614. c.setString("a", null, "y", "");
  615. assertEquals("0", c.getString("a", null, "x"));
  616. assertEquals(0, c.getInt("a", null, "x", 1));
  617. assertEquals("", c.getString("a", null, "y"));
  618. assertArrayEquals(new String[]{""}, c.getStringList("a", null, "y"));
  619. try {
  620. c.getInt("a", null, "y", 1);
  621. } catch (IllegalArgumentException e) {
  622. assertEquals("Invalid integer value: a.y=", e.getMessage());
  623. }
  624. assertNull(c.getString("a", null, "z"));
  625. assertArrayEquals(new String[]{}, c.getStringList("a", null, "z"));
  626. }
  627. @Test
  628. public void testParsedEmptyString() throws Exception {
  629. Config c = parse("[a]\n"
  630. + "x = 0\n"
  631. + "y =\n");
  632. assertEquals("0", c.getString("a", null, "x"));
  633. assertEquals(0, c.getInt("a", null, "x", 1));
  634. assertNull(c.getString("a", null, "y"));
  635. assertArrayEquals(new String[]{null}, c.getStringList("a", null, "y"));
  636. try {
  637. c.getInt("a", null, "y", 1);
  638. } catch (IllegalArgumentException e) {
  639. assertEquals("Invalid integer value: a.y=", e.getMessage());
  640. }
  641. assertNull(c.getString("a", null, "z"));
  642. assertArrayEquals(new String[]{}, c.getStringList("a", null, "z"));
  643. }
  644. @Test
  645. public void testSetStringListWithEmptyValue() throws Exception {
  646. Config c = new Config();
  647. c.setStringList("a", null, "x", Arrays.asList(""));
  648. assertArrayEquals(new String[]{""}, c.getStringList("a", null, "x"));
  649. }
  650. @Test
  651. public void testEmptyValueAtEof() throws Exception {
  652. String text = "[a]\nx =";
  653. Config c = parse(text);
  654. assertNull(c.getString("a", null, "x"));
  655. assertArrayEquals(new String[]{null},
  656. c.getStringList("a", null, "x"));
  657. c = parse(text + "\n");
  658. assertNull(c.getString("a", null, "x"));
  659. assertArrayEquals(new String[]{null},
  660. c.getStringList("a", null, "x"));
  661. }
  662. @Test
  663. public void testReadMultipleValuesForName() throws ConfigInvalidException {
  664. Config c = parse("[foo]\nbar=false\nbar=true\n");
  665. assertTrue(c.getBoolean("foo", "bar", false));
  666. }
  667. @Test
  668. public void testIncludeInvalidName() throws ConfigInvalidException {
  669. expectedEx.expect(ConfigInvalidException.class);
  670. expectedEx.expectMessage(JGitText.get().invalidLineInConfigFile);
  671. parse("[include]\nbar\n");
  672. }
  673. @Test
  674. public void testIncludeNoValue() throws ConfigInvalidException {
  675. expectedEx.expect(ConfigInvalidException.class);
  676. expectedEx.expectMessage(JGitText.get().invalidLineInConfigFile);
  677. parse("[include]\npath\n");
  678. }
  679. @Test
  680. public void testIncludeEmptyValue() throws ConfigInvalidException {
  681. expectedEx.expect(ConfigInvalidException.class);
  682. expectedEx.expectMessage(JGitText.get().invalidLineInConfigFile);
  683. parse("[include]\npath=\n");
  684. }
  685. @Test
  686. public void testIncludeValuePathNotFound() throws ConfigInvalidException {
  687. // we do not expect an exception, included path not found are ignored
  688. String notFound = "/not/found";
  689. Config parsed = parse("[include]\npath=" + notFound + "\n");
  690. assertEquals(1, parsed.getSections().size());
  691. assertEquals(notFound, parsed.getString("include", null, "path"));
  692. }
  693. @Test
  694. public void testIncludeValuePathWithTilde() throws ConfigInvalidException {
  695. // we do not expect an exception, included path not supported are
  696. // ignored
  697. String notSupported = "~/someFile";
  698. Config parsed = parse("[include]\npath=" + notSupported + "\n");
  699. assertEquals(1, parsed.getSections().size());
  700. assertEquals(notSupported, parsed.getString("include", null, "path"));
  701. }
  702. @Test
  703. public void testIncludeValuePathRelative() throws ConfigInvalidException {
  704. // we do not expect an exception, included path not supported are
  705. // ignored
  706. String notSupported = "someRelativeFile";
  707. Config parsed = parse("[include]\npath=" + notSupported + "\n");
  708. assertEquals(1, parsed.getSections().size());
  709. assertEquals(notSupported, parsed.getString("include", null, "path"));
  710. }
  711. @Test
  712. public void testIncludeTooManyRecursions() throws IOException {
  713. File config = tmp.newFile("config");
  714. String include = "[include]\npath=" + pathToString(config) + "\n";
  715. Files.write(config.toPath(), include.getBytes());
  716. FileBasedConfig fbConfig = new FileBasedConfig(null, config,
  717. FS.DETECTED);
  718. try {
  719. fbConfig.load();
  720. fail();
  721. } catch (ConfigInvalidException cie) {
  722. for (Throwable t = cie; t != null; t = t.getCause()) {
  723. if (t.getMessage()
  724. .equals(JGitText.get().tooManyIncludeRecursions)) {
  725. return;
  726. }
  727. }
  728. fail("Expected to find expected exception message: "
  729. + JGitText.get().tooManyIncludeRecursions);
  730. }
  731. }
  732. @Test
  733. public void testIncludeIsNoop() throws IOException, ConfigInvalidException {
  734. File config = tmp.newFile("config");
  735. String fooBar = "[foo]\nbar=true\n";
  736. Files.write(config.toPath(), fooBar.getBytes());
  737. Config parsed = parse("[include]\npath=" + pathToString(config) + "\n");
  738. assertFalse(parsed.getBoolean("foo", "bar", false));
  739. }
  740. @Test
  741. public void testIncludeCaseInsensitiveSection()
  742. throws IOException, ConfigInvalidException {
  743. File included = tmp.newFile("included");
  744. String content = "[foo]\nbar=true\n";
  745. Files.write(included.toPath(), content.getBytes());
  746. File config = tmp.newFile("config");
  747. content = "[Include]\npath=" + pathToString(included) + "\n";
  748. Files.write(config.toPath(), content.getBytes());
  749. FileBasedConfig fbConfig = new FileBasedConfig(null, config,
  750. FS.DETECTED);
  751. fbConfig.load();
  752. assertTrue(fbConfig.getBoolean("foo", "bar", false));
  753. }
  754. @Test
  755. public void testIncludeCaseInsensitiveKey()
  756. throws IOException, ConfigInvalidException {
  757. File included = tmp.newFile("included");
  758. String content = "[foo]\nbar=true\n";
  759. Files.write(included.toPath(), content.getBytes());
  760. File config = tmp.newFile("config");
  761. content = "[include]\nPath=" + pathToString(included) + "\n";
  762. Files.write(config.toPath(), content.getBytes());
  763. FileBasedConfig fbConfig = new FileBasedConfig(null, config,
  764. FS.DETECTED);
  765. fbConfig.load();
  766. assertTrue(fbConfig.getBoolean("foo", "bar", false));
  767. }
  768. @Test
  769. public void testIncludeExceptionContainsLine() {
  770. try {
  771. parse("[include]\npath=\n");
  772. fail("Expected ConfigInvalidException");
  773. } catch (ConfigInvalidException e) {
  774. assertTrue(
  775. "Expected to find the problem line in the exception message",
  776. e.getMessage().contains("include.path"));
  777. }
  778. }
  779. @Test
  780. public void testIncludeExceptionContainsFile() throws IOException {
  781. File included = tmp.newFile("included");
  782. String includedPath = pathToString(included);
  783. String content = "[include]\npath=\n";
  784. Files.write(included.toPath(), content.getBytes());
  785. File config = tmp.newFile("config");
  786. String include = "[include]\npath=" + includedPath + "\n";
  787. Files.write(config.toPath(), include.getBytes());
  788. FileBasedConfig fbConfig = new FileBasedConfig(null, config,
  789. FS.DETECTED);
  790. try {
  791. fbConfig.load();
  792. fail("Expected ConfigInvalidException");
  793. } catch (ConfigInvalidException e) {
  794. // Check that there is some exception in the chain that contains
  795. // includedPath
  796. for (Throwable t = e; t != null; t = t.getCause()) {
  797. if (t.getMessage().contains(includedPath)) {
  798. return;
  799. }
  800. }
  801. fail("Expected to find the path in the exception message: "
  802. + includedPath);
  803. }
  804. }
  805. private static void assertReadLong(long exp) throws ConfigInvalidException {
  806. assertReadLong(exp, String.valueOf(exp));
  807. }
  808. private static void assertReadLong(long exp, String act)
  809. throws ConfigInvalidException {
  810. final Config c = parse("[s]\na = " + act + "\n");
  811. assertEquals(exp, c.getLong("s", null, "a", 0L));
  812. }
  813. private static Config parse(String content)
  814. throws ConfigInvalidException {
  815. return parse(content, null);
  816. }
  817. private static Config parse(String content, Config baseConfig)
  818. throws ConfigInvalidException {
  819. final Config c = new Config(baseConfig);
  820. c.fromText(content);
  821. return c;
  822. }
  823. @Test
  824. public void testTimeUnit() throws ConfigInvalidException {
  825. assertEquals(0, parseTime("0", NANOSECONDS));
  826. assertEquals(2, parseTime("2ns", NANOSECONDS));
  827. assertEquals(200, parseTime("200 nanoseconds", NANOSECONDS));
  828. assertEquals(0, parseTime("0", MICROSECONDS));
  829. assertEquals(2, parseTime("2us", MICROSECONDS));
  830. assertEquals(2, parseTime("2000 nanoseconds", MICROSECONDS));
  831. assertEquals(200, parseTime("200 microseconds", MICROSECONDS));
  832. assertEquals(0, parseTime("0", MILLISECONDS));
  833. assertEquals(2, parseTime("2ms", MILLISECONDS));
  834. assertEquals(2, parseTime("2000microseconds", MILLISECONDS));
  835. assertEquals(200, parseTime("200 milliseconds", MILLISECONDS));
  836. assertEquals(0, parseTime("0s", SECONDS));
  837. assertEquals(2, parseTime("2s", SECONDS));
  838. assertEquals(231, parseTime("231sec", SECONDS));
  839. assertEquals(1, parseTime("1second", SECONDS));
  840. assertEquals(300, parseTime("300 seconds", SECONDS));
  841. assertEquals(2, parseTime("2m", MINUTES));
  842. assertEquals(2, parseTime("2min", MINUTES));
  843. assertEquals(1, parseTime("1 minute", MINUTES));
  844. assertEquals(10, parseTime("10 minutes", MINUTES));
  845. assertEquals(5, parseTime("5h", HOURS));
  846. assertEquals(5, parseTime("5hr", HOURS));
  847. assertEquals(1, parseTime("1hour", HOURS));
  848. assertEquals(48, parseTime("48hours", HOURS));
  849. assertEquals(5, parseTime("5 h", HOURS));
  850. assertEquals(5, parseTime("5 hr", HOURS));
  851. assertEquals(1, parseTime("1 hour", HOURS));
  852. assertEquals(48, parseTime("48 hours", HOURS));
  853. assertEquals(48, parseTime("48 \t \r hours", HOURS));
  854. assertEquals(4, parseTime("4d", DAYS));
  855. assertEquals(1, parseTime("1day", DAYS));
  856. assertEquals(14, parseTime("14days", DAYS));
  857. assertEquals(7, parseTime("1w", DAYS));
  858. assertEquals(7, parseTime("1week", DAYS));
  859. assertEquals(14, parseTime("2w", DAYS));
  860. assertEquals(14, parseTime("2weeks", DAYS));
  861. assertEquals(30, parseTime("1mon", DAYS));
  862. assertEquals(30, parseTime("1month", DAYS));
  863. assertEquals(60, parseTime("2mon", DAYS));
  864. assertEquals(60, parseTime("2months", DAYS));
  865. assertEquals(365, parseTime("1y", DAYS));
  866. assertEquals(365, parseTime("1year", DAYS));
  867. assertEquals(365 * 2, parseTime("2years", DAYS));
  868. }
  869. private long parseTime(String value, TimeUnit unit)
  870. throws ConfigInvalidException {
  871. Config c = parse("[a]\na=" + value + "\n");
  872. return c.getTimeUnit("a", null, "a", 0, unit);
  873. }
  874. @Test
  875. public void testTimeUnitDefaultValue() throws ConfigInvalidException {
  876. // value not present
  877. assertEquals(20, parse("[a]\na=0\n").getTimeUnit("a", null, "b", 20,
  878. MILLISECONDS));
  879. // value is empty
  880. assertEquals(20, parse("[a]\na=\" \"\n").getTimeUnit("a", null, "a", 20,
  881. MILLISECONDS));
  882. // value is not numeric
  883. assertEquals(20, parse("[a]\na=test\n").getTimeUnit("a", null, "a", 20,
  884. MILLISECONDS));
  885. }
  886. @Test
  887. public void testTimeUnitInvalid() throws ConfigInvalidException {
  888. expectedEx.expect(IllegalArgumentException.class);
  889. expectedEx
  890. .expectMessage("Invalid time unit value: a.a=1 monttthhh");
  891. parseTime("1 monttthhh", DAYS);
  892. }
  893. @Test
  894. public void testTimeUnitInvalidWithSection() throws ConfigInvalidException {
  895. Config c = parse("[a \"b\"]\na=1 monttthhh\n");
  896. expectedEx.expect(IllegalArgumentException.class);
  897. expectedEx.expectMessage("Invalid time unit value: a.b.a=1 monttthhh");
  898. c.getTimeUnit("a", "b", "a", 0, DAYS);
  899. }
  900. @Test
  901. public void testTimeUnitNegative() throws ConfigInvalidException {
  902. expectedEx.expect(IllegalArgumentException.class);
  903. parseTime("-1", MILLISECONDS);
  904. }
  905. @Test
  906. public void testEscapeSpacesOnly() throws ConfigInvalidException {
  907. // Empty string is read back as null, so this doesn't round-trip.
  908. assertEquals("", Config.escapeValue(""));
  909. assertValueRoundTrip(" ", "\" \"");
  910. assertValueRoundTrip(" ", "\" \"");
  911. }
  912. @Test
  913. public void testEscapeLeadingSpace() throws ConfigInvalidException {
  914. assertValueRoundTrip("x", "x");
  915. assertValueRoundTrip(" x", "\" x\"");
  916. assertValueRoundTrip(" x", "\" x\"");
  917. }
  918. @Test
  919. public void testEscapeTrailingSpace() throws ConfigInvalidException {
  920. assertValueRoundTrip("x", "x");
  921. assertValueRoundTrip("x ","\"x \"");
  922. assertValueRoundTrip("x ","\"x \"");
  923. }
  924. @Test
  925. public void testEscapeLeadingAndTrailingSpace()
  926. throws ConfigInvalidException {
  927. assertValueRoundTrip(" x ", "\" x \"");
  928. assertValueRoundTrip(" x ", "\" x \"");
  929. assertValueRoundTrip(" x ", "\" x \"");
  930. assertValueRoundTrip(" x ", "\" x \"");
  931. }
  932. @Test
  933. public void testNoEscapeInternalSpaces() throws ConfigInvalidException {
  934. assertValueRoundTrip("x y");
  935. assertValueRoundTrip("x y");
  936. assertValueRoundTrip("x y");
  937. assertValueRoundTrip("x y z");
  938. assertValueRoundTrip("x " + WS + " y");
  939. }
  940. @Test
  941. public void testNoEscapeSpecialCharacters() throws ConfigInvalidException {
  942. assertValueRoundTrip("x\\y", "x\\\\y");
  943. assertValueRoundTrip("x\"y", "x\\\"y");
  944. assertValueRoundTrip("x\ny", "x\\ny");
  945. assertValueRoundTrip("x\ty", "x\\ty");
  946. assertValueRoundTrip("x\by", "x\\by");
  947. }
  948. @Test
  949. public void testParseLiteralBackspace() throws ConfigInvalidException {
  950. // This is round-tripped with an escape sequence by JGit, but C git writes
  951. // it out as a literal backslash.
  952. assertEquals("x\by", parseEscapedValue("x\by"));
  953. }
  954. @Test
  955. public void testEscapeCommentCharacters() throws ConfigInvalidException {
  956. assertValueRoundTrip("x#y", "\"x#y\"");
  957. assertValueRoundTrip("x;y", "\"x;y\"");
  958. }
  959. @Test
  960. public void testEscapeValueInvalidCharacters() {
  961. assertIllegalArgumentException(() -> Config.escapeSubsection("x\0y"));
  962. }
  963. @Test
  964. public void testEscapeSubsectionInvalidCharacters() {
  965. assertIllegalArgumentException(() -> Config.escapeSubsection("x\ny"));
  966. assertIllegalArgumentException(() -> Config.escapeSubsection("x\0y"));
  967. }
  968. @Test
  969. public void testParseMultipleQuotedRegions() throws ConfigInvalidException {
  970. assertEquals("b a z; \n", parseEscapedValue("b\" a\"\" z; \\n\""));
  971. }
  972. @Test
  973. public void testParseComments() throws ConfigInvalidException {
  974. assertEquals("baz", parseEscapedValue("baz; comment"));
  975. assertEquals("baz", parseEscapedValue("baz# comment"));
  976. assertEquals("baz", parseEscapedValue("baz ; comment"));
  977. assertEquals("baz", parseEscapedValue("baz # comment"));
  978. assertEquals("baz", parseEscapedValue("baz ; comment"));
  979. assertEquals("baz", parseEscapedValue("baz # comment"));
  980. assertEquals("baz", parseEscapedValue("baz " + WS + " ; comment"));
  981. assertEquals("baz", parseEscapedValue("baz " + WS + " # comment"));
  982. assertEquals("baz ", parseEscapedValue("\"baz \"; comment"));
  983. assertEquals("baz ", parseEscapedValue("\"baz \"# comment"));
  984. assertEquals("baz ", parseEscapedValue("\"baz \" ; comment"));
  985. assertEquals("baz ", parseEscapedValue("\"baz \" # comment"));
  986. }
  987. @Test
  988. public void testEscapeSubsection() throws ConfigInvalidException {
  989. assertSubsectionRoundTrip("", "\"\"");
  990. assertSubsectionRoundTrip("x", "\"x\"");
  991. assertSubsectionRoundTrip(" x", "\" x\"");
  992. assertSubsectionRoundTrip("x ", "\"x \"");
  993. assertSubsectionRoundTrip(" x ", "\" x \"");
  994. assertSubsectionRoundTrip("x y", "\"x y\"");
  995. assertSubsectionRoundTrip("x y", "\"x y\"");
  996. assertSubsectionRoundTrip("x\\y", "\"x\\\\y\"");
  997. assertSubsectionRoundTrip("x\"y", "\"x\\\"y\"");
  998. // Unlike for values, \b and \t are not escaped.
  999. assertSubsectionRoundTrip("x\by", "\"x\by\"");
  1000. assertSubsectionRoundTrip("x\ty", "\"x\ty\"");
  1001. }
  1002. @Test
  1003. public void testParseInvalidValues() {
  1004. assertInvalidValue(JGitText.get().newlineInQuotesNotAllowed, "x\"\n\"y");
  1005. assertInvalidValue(JGitText.get().endOfFileInEscape, "x\\");
  1006. assertInvalidValue(
  1007. MessageFormat.format(JGitText.get().badEscape, 'q'), "x\\q");
  1008. }
  1009. @Test
  1010. public void testParseInvalidSubsections() {
  1011. assertInvalidSubsection(
  1012. JGitText.get().newlineInQuotesNotAllowed, "\"x\ny\"");
  1013. }
  1014. @Test
  1015. public void testDropBackslashFromInvalidEscapeSequenceInSubsectionName()
  1016. throws ConfigInvalidException {
  1017. assertEquals("x0", parseEscapedSubsection("\"x\\0\""));
  1018. assertEquals("xq", parseEscapedSubsection("\"x\\q\""));
  1019. // Unlike for values, \b, \n, and \t are not valid escape sequences.
  1020. assertEquals("xb", parseEscapedSubsection("\"x\\b\""));
  1021. assertEquals("xn", parseEscapedSubsection("\"x\\n\""));
  1022. assertEquals("xt", parseEscapedSubsection("\"x\\t\""));
  1023. }
  1024. private static void assertValueRoundTrip(String value)
  1025. throws ConfigInvalidException {
  1026. assertValueRoundTrip(value, value);
  1027. }
  1028. private static void assertValueRoundTrip(String value, String expectedEscaped)
  1029. throws ConfigInvalidException {
  1030. String escaped = Config.escapeValue(value);
  1031. assertEquals("escape failed;", expectedEscaped, escaped);
  1032. assertEquals("parse failed;", value, parseEscapedValue(escaped));
  1033. }
  1034. private static String parseEscapedValue(String escapedValue)
  1035. throws ConfigInvalidException {
  1036. String text = "[foo]\nbar=" + escapedValue;
  1037. Config c = parse(text);
  1038. return c.getString("foo", null, "bar");
  1039. }
  1040. private static void assertInvalidValue(String expectedMessage,
  1041. String escapedValue) {
  1042. try {
  1043. parseEscapedValue(escapedValue);
  1044. fail("expected ConfigInvalidException");
  1045. } catch (ConfigInvalidException e) {
  1046. assertEquals(expectedMessage, e.getMessage());
  1047. }
  1048. }
  1049. private static void assertSubsectionRoundTrip(String subsection,
  1050. String expectedEscaped) throws ConfigInvalidException {
  1051. String escaped = Config.escapeSubsection(subsection);
  1052. assertEquals("escape failed;", expectedEscaped, escaped);
  1053. assertEquals("parse failed;", subsection, parseEscapedSubsection(escaped));
  1054. }
  1055. private static String parseEscapedSubsection(String escapedSubsection)
  1056. throws ConfigInvalidException {
  1057. String text = "[foo " + escapedSubsection + "]\nbar = value";
  1058. Config c = parse(text);
  1059. Set<String> subsections = c.getSubsections("foo");
  1060. assertEquals("only one section", 1, subsections.size());
  1061. return subsections.iterator().next();
  1062. }
  1063. private static void assertIllegalArgumentException(Runnable r) {
  1064. try {
  1065. r.run();
  1066. fail("expected IllegalArgumentException");
  1067. } catch (IllegalArgumentException e) {
  1068. // Expected.
  1069. }
  1070. }
  1071. private static void assertInvalidSubsection(String expectedMessage,
  1072. String escapedSubsection) {
  1073. try {
  1074. parseEscapedSubsection(escapedSubsection);
  1075. fail("expected ConfigInvalidException");
  1076. } catch (ConfigInvalidException e) {
  1077. assertEquals(expectedMessage, e.getMessage());
  1078. }
  1079. }
  1080. }