View Javadoc
1   /*
2    * Copyright (C) 2012, Marc Strapetz and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.storage.file;
11  
12  import static java.nio.charset.StandardCharsets.UTF_8;
13  import static org.eclipse.jgit.util.FileUtils.pathToString;
14  import static org.junit.Assert.assertArrayEquals;
15  import static org.junit.Assert.assertEquals;
16  import static org.junit.Assert.assertNotNull;
17  
18  import java.io.ByteArrayOutputStream;
19  import java.io.IOException;
20  import java.io.OutputStream;
21  import java.nio.file.Files;
22  import java.nio.file.Path;
23  import java.nio.file.StandardOpenOption;
24  import java.util.StringTokenizer;
25  
26  import org.eclipse.jgit.errors.ConfigInvalidException;
27  import org.eclipse.jgit.junit.MockSystemReader;
28  import org.eclipse.jgit.util.FS;
29  import org.eclipse.jgit.util.FileUtils;
30  import org.eclipse.jgit.util.IO;
31  import org.eclipse.jgit.util.SystemReader;
32  import org.junit.After;
33  import org.junit.Before;
34  import org.junit.Test;
35  
36  public class FileBasedConfigTest {
37  
38  	private static final String USER = "user";
39  
40  	private static final String NAME = "name";
41  
42  	private static final String EMAIL = "email";
43  
44  	private static final String ALICE = "Alice";
45  
46  	private static final String BOB = "Bob";
47  
48  	private static final String ALICE_EMAIL = "alice@home";
49  
50  	private static final String CONTENT1 = "[" + USER + "]\n\t" + NAME + " = "
51  			+ ALICE + "\n";
52  
53  	private static final String CONTENT2 = "[" + USER + "]\n\t" + NAME + " = "
54  			+ BOB + "\n";
55  
56  	private static final String CONTENT3 = "[" + USER + "]\n\t" + NAME + " = "
57  			+ ALICE + "\n" + "[" + USER + "]\n\t" + EMAIL + " = " + ALICE_EMAIL;
58  
59  	private Path trash;
60  
61  	@Before
62  	public void setUp() throws Exception {
63  		SystemReader.setInstance(new MockSystemReader());
64  		trash = Files.createTempDirectory("tmp_");
65  		FS.getFileStoreAttributes(trash.getParent());
66  	}
67  
68  	@After
69  	public void tearDown() throws Exception {
70  		FileUtils.delete(trash.toFile(),
71  				FileUtils.RECURSIVE | FileUtils.SKIP_MISSING | FileUtils.RETRY);
72  	}
73  
74  	@Test
75  	public void testSystemEncoding() throws IOException, ConfigInvalidException {
76  		final Path file = createFile(CONTENT1.getBytes(UTF_8));
77  		final FileBasedConfig config = new FileBasedConfig(file.toFile(),
78  				FS.DETECTED);
79  		config.load();
80  		assertEquals(ALICE, config.getString(USER, null, NAME));
81  
82  		config.setString(USER, null, NAME, BOB);
83  		config.save();
84  		assertArrayEquals(CONTENT2.getBytes(UTF_8), IO.readFully(file.toFile()));
85  	}
86  
87  	@Test
88  	public void testUTF8withoutBOM() throws IOException, ConfigInvalidException {
89  		final Path file = createFile(CONTENT1.getBytes(UTF_8));
90  		final FileBasedConfig config = new FileBasedConfig(file.toFile(),
91  				FS.DETECTED);
92  		config.load();
93  		assertEquals(ALICE, config.getString(USER, null, NAME));
94  
95  		config.setString(USER, null, NAME, BOB);
96  		config.save();
97  		assertArrayEquals(CONTENT2.getBytes(UTF_8), IO.readFully(file.toFile()));
98  	}
99  
100 	@Test
101 	public void testUTF8withBOM() throws IOException, ConfigInvalidException {
102 		final ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
103 		bos1.write(0xEF);
104 		bos1.write(0xBB);
105 		bos1.write(0xBF);
106 		bos1.write(CONTENT1.getBytes(UTF_8));
107 
108 		final Path file = createFile(bos1.toByteArray());
109 		final FileBasedConfig config = new FileBasedConfig(file.toFile(),
110 				FS.DETECTED);
111 		config.load();
112 		assertEquals(ALICE, config.getString(USER, null, NAME));
113 
114 		config.setString(USER, null, NAME, BOB);
115 		config.save();
116 
117 		final ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
118 		bos2.write(0xEF);
119 		bos2.write(0xBB);
120 		bos2.write(0xBF);
121 		bos2.write(CONTENT2.getBytes(UTF_8));
122 		assertArrayEquals(bos2.toByteArray(), IO.readFully(file.toFile()));
123 	}
124 
125 	@Test
126 	public void testLeadingWhitespaces() throws IOException, ConfigInvalidException {
127 		final ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
128 		bos1.write(" \n\t".getBytes(UTF_8));
129 		bos1.write(CONTENT1.getBytes(UTF_8));
130 
131 		final Path file = createFile(bos1.toByteArray());
132 		final FileBasedConfig config = new FileBasedConfig(file.toFile(),
133 				FS.DETECTED);
134 		config.load();
135 		assertEquals(ALICE, config.getString(USER, null, NAME));
136 
137 		config.setString(USER, null, NAME, BOB);
138 		config.save();
139 
140 		final ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
141 		bos2.write(" \n\t".getBytes(UTF_8));
142 		bos2.write(CONTENT2.getBytes(UTF_8));
143 		assertArrayEquals(bos2.toByteArray(), IO.readFully(file.toFile()));
144 	}
145 
146 	@Test
147 	public void testIncludeAbsolute()
148 			throws IOException, ConfigInvalidException {
149 		final Path includedFile = createFile(CONTENT1.getBytes(UTF_8));
150 		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
151 		bos.write("[include]\npath=".getBytes(UTF_8));
152 		bos.write(pathToString(includedFile.toFile()).getBytes(UTF_8));
153 
154 		final Path file = createFile(bos.toByteArray());
155 		final FileBasedConfig config = new FileBasedConfig(file.toFile(),
156 				FS.DETECTED);
157 		config.load();
158 		assertEquals(ALICE, config.getString(USER, null, NAME));
159 	}
160 
161 	@Test
162 	public void testIncludeRelativeDot()
163 			throws IOException, ConfigInvalidException {
164 		final Path includedFile = createFile(CONTENT1.getBytes(UTF_8), "dir1");
165 		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
166 		bos.write("[include]\npath=".getBytes(UTF_8));
167 		bos.write(("./" + includedFile.getFileName()).getBytes(UTF_8));
168 
169 		final Path file = createFile(bos.toByteArray(), "dir1");
170 		final FileBasedConfig config = new FileBasedConfig(file.toFile(),
171 				FS.DETECTED);
172 		config.load();
173 		assertEquals(ALICE, config.getString(USER, null, NAME));
174 	}
175 
176 	@Test
177 	public void testIncludeRelativeDotDot()
178 			throws IOException, ConfigInvalidException {
179 		final Path includedFile = createFile(CONTENT1.getBytes(UTF_8), "dir1");
180 		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
181 		bos.write("[include]\npath=".getBytes(UTF_8));
182 		bos.write(("../" + parent(includedFile).getFileName() + "/"
183 				+ includedFile.getFileName()).getBytes(UTF_8));
184 
185 		final Path file = createFile(bos.toByteArray(), "dir2");
186 		final FileBasedConfig config = new FileBasedConfig(file.toFile(),
187 				FS.DETECTED);
188 		config.load();
189 		assertEquals(ALICE, config.getString(USER, null, NAME));
190 	}
191 
192 	@Test
193 	public void testIncludeRelativeDotDotNotFound()
194 			throws IOException, ConfigInvalidException {
195 		final Path includedFile = createFile(CONTENT1.getBytes(UTF_8));
196 		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
197 		bos.write("[include]\npath=".getBytes(UTF_8));
198 		bos.write(("../" + includedFile.getFileName()).getBytes(UTF_8));
199 
200 		final Path file = createFile(bos.toByteArray());
201 		final FileBasedConfig config = new FileBasedConfig(file.toFile(),
202 				FS.DETECTED);
203 		config.load();
204 		assertEquals(null, config.getString(USER, null, NAME));
205 	}
206 
207 	@Test
208 	public void testIncludeWithTilde()
209 			throws IOException, ConfigInvalidException {
210 		final Path includedFile = createFile(CONTENT1.getBytes(UTF_8), "home");
211 		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
212 		bos.write("[include]\npath=".getBytes(UTF_8));
213 		bos.write(("~/" + includedFile.getFileName()).getBytes(UTF_8));
214 
215 		final Path file = createFile(bos.toByteArray(), "repo");
216 		final FS fs = FS.DETECTED.newInstance();
217 		fs.setUserHome(parent(includedFile).toFile());
218 
219 		final FileBasedConfig config = new FileBasedConfig(file.toFile(), fs);
220 		config.load();
221 		assertEquals(ALICE, config.getString(USER, null, NAME));
222 	}
223 
224 	@Test
225 	public void testIncludeDontInlineIncludedLinesOnSave()
226 			throws IOException, ConfigInvalidException {
227 		// use a content with multiple sections and multiple key/value pairs
228 		// because code for first line works different than for subsequent lines
229 		final Path includedFile = createFile(CONTENT3.getBytes(UTF_8), "dir1");
230 
231 		final Path file = createFile(new byte[0], "dir2");
232 		FileBasedConfig config = new FileBasedConfig(file.toFile(),
233 				FS.DETECTED);
234 		config.setString("include", null, "path",
235 				("../" + parent(includedFile).getFileName() + "/"
236 						+ includedFile.getFileName()));
237 
238 		// just by setting the include.path, it won't be included
239 		assertEquals(null, config.getString(USER, null, NAME));
240 		assertEquals(null, config.getString(USER, null, EMAIL));
241 		config.save();
242 
243 		// and it won't be included after saving
244 		assertEquals(null, config.getString(USER, null, NAME));
245 		assertEquals(null, config.getString(USER, null, EMAIL));
246 
247 		final String expectedText = config.toText();
248 		assertEquals(2,
249 				new StringTokenizer(expectedText, "\n", false).countTokens());
250 
251 		config = new FileBasedConfig(file.toFile(), FS.DETECTED);
252 		config.load();
253 
254 		String actualText = config.toText();
255 		assertEquals(expectedText, actualText);
256 		// but it will be included after (re)loading
257 		assertEquals(ALICE, config.getString(USER, null, NAME));
258 		assertEquals(ALICE_EMAIL, config.getString(USER, null, EMAIL));
259 
260 		config.save();
261 
262 		actualText = config.toText();
263 		assertEquals(expectedText, actualText);
264 		// and of course preserved after saving
265 		assertEquals(ALICE, config.getString(USER, null, NAME));
266 		assertEquals(ALICE_EMAIL, config.getString(USER, null, EMAIL));
267 	}
268 
269 	private Path createFile(byte[] content) throws IOException {
270 		return createFile(content, null);
271 	}
272 
273 	private Path createFile(byte[] content, String subdir) throws IOException {
274 		Path dir = subdir != null ? trash.resolve(subdir) : trash;
275 		Files.createDirectories(dir);
276 
277 		Path f = Files.createTempFile(dir, getClass().getName(), null);
278 		try (OutputStream os = Files.newOutputStream(f,
279 				StandardOpenOption.APPEND)) {
280 			os.write(content);
281 		}
282 		return f;
283 	}
284 
285 	private Path parent(Path file) {
286 		Path parent = file.getParent();
287 		assertNotNull(parent);
288 		return parent;
289 	}
290 }