View Javadoc
1   /*
2    * Copyright (C) 2009, Google Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.lib;
45  
46  import static org.eclipse.jgit.junit.Assert.assertEquals;
47  
48  import org.eclipse.jgit.junit.MockSystemReader;
49  import org.eclipse.jgit.util.SystemReader;
50  import org.junit.Test;
51  
52  public class ValidRefNameTest {
53  	private static void assertValid(final boolean exp, final String name) {
54  		SystemReader instance = SystemReader.getInstance();
55  		try {
56  			setUnixSystemReader();
57  			assertEquals("\"" + name + "\"", exp,
58  					Repository.isValidRefName(name));
59  			setWindowsSystemReader();
60  			assertEquals("\"" + name + "\"", exp,
61  					Repository.isValidRefName(name));
62  		} finally {
63  			SystemReader.setInstance(instance);
64  		}
65  	}
66  
67  	private static void setWindowsSystemReader() {
68  		SystemReader.setInstance(new MockSystemReader() {
69  			{
70  				setWindows();
71  			}
72  		});
73  	}
74  
75  	private static void setUnixSystemReader() {
76  		SystemReader.setInstance(new MockSystemReader() {
77  			{
78  				setUnix();
79  			}
80  		});
81  	}
82  
83  	private static void assertInvalidOnWindows(final String name) {
84  		SystemReader instance = SystemReader.getInstance();
85  		try {
86  			setUnixSystemReader();
87  			assertEquals("\"" + name + "\"", true,
88  					Repository.isValidRefName(name));
89  			setWindowsSystemReader();
90  			assertEquals("\"" + name + "\"", false,
91  					Repository.isValidRefName(name));
92  		} finally {
93  			SystemReader.setInstance(instance);
94  		}
95  	}
96  
97  	@Test
98  	public void testEmptyString() {
99  		assertValid(false, "");
100 		assertValid(false, "/");
101 	}
102 
103 	@Test
104 	public void testMustHaveTwoComponents() {
105 		assertValid(false, "master");
106 		assertValid(true, "heads/master");
107 	}
108 
109 	@Test
110 	public void testValidHead() {
111 		assertValid(true, "refs/heads/master");
112 		assertValid(true, "refs/heads/pu");
113 		assertValid(true, "refs/heads/z");
114 		assertValid(true, "refs/heads/FoO");
115 	}
116 
117 	@Test
118 	public void testValidTag() {
119 		assertValid(true, "refs/tags/v1.0");
120 	}
121 
122 	@Test
123 	public void testNoLockSuffix() {
124 		assertValid(false, "refs/heads/master.lock");
125 	}
126 
127 	@Test
128 	public void testNoDirectorySuffix() {
129 		assertValid(false, "refs/heads/master/");
130 	}
131 
132 	@Test
133 	public void testNoSpace() {
134 		assertValid(false, "refs/heads/i haz space");
135 	}
136 
137 	@Test
138 	public void testNoAsciiControlCharacters() {
139 		for (char c = '\0'; c < ' '; c++)
140 			assertValid(false, "refs/heads/mast" + c + "er");
141 	}
142 
143 	@Test
144 	public void testNoBareDot() {
145 		assertValid(false, "refs/heads/.");
146 		assertValid(false, "refs/heads/..");
147 		assertValid(false, "refs/heads/./master");
148 		assertValid(false, "refs/heads/../master");
149 	}
150 
151 	@Test
152 	public void testNoLeadingOrTrailingDot() {
153 		assertValid(false, ".");
154 		assertValid(false, "refs/heads/.bar");
155 		assertValid(false, "refs/heads/..bar");
156 		assertValid(false, "refs/heads/bar.");
157 	}
158 
159 	@Test
160 	public void testContainsDot() {
161 		assertValid(true, "refs/heads/m.a.s.t.e.r");
162 		assertValid(false, "refs/heads/master..pu");
163 	}
164 
165 	@Test
166 	public void testNoMagicRefCharacters() {
167 		assertValid(false, "refs/heads/master^");
168 		assertValid(false, "refs/heads/^master");
169 		assertValid(false, "^refs/heads/master");
170 
171 		assertValid(false, "refs/heads/master~");
172 		assertValid(false, "refs/heads/~master");
173 		assertValid(false, "~refs/heads/master");
174 
175 		assertValid(false, "refs/heads/master:");
176 		assertValid(false, "refs/heads/:master");
177 		assertValid(false, ":refs/heads/master");
178 	}
179 
180 	@Test
181 	public void testShellGlob() {
182 		assertValid(false, "refs/heads/master?");
183 		assertValid(false, "refs/heads/?master");
184 		assertValid(false, "?refs/heads/master");
185 
186 		assertValid(false, "refs/heads/master[");
187 		assertValid(false, "refs/heads/[master");
188 		assertValid(false, "[refs/heads/master");
189 
190 		assertValid(false, "refs/heads/master*");
191 		assertValid(false, "refs/heads/*master");
192 		assertValid(false, "*refs/heads/master");
193 	}
194 
195 	@Test
196 	public void testValidSpecialCharacterUnixs() {
197 		assertValid(true, "refs/heads/!");
198 		assertValid(true, "refs/heads/#");
199 		assertValid(true, "refs/heads/$");
200 		assertValid(true, "refs/heads/%");
201 		assertValid(true, "refs/heads/&");
202 		assertValid(true, "refs/heads/'");
203 		assertValid(true, "refs/heads/(");
204 		assertValid(true, "refs/heads/)");
205 		assertValid(true, "refs/heads/+");
206 		assertValid(true, "refs/heads/,");
207 		assertValid(true, "refs/heads/-");
208 		assertValid(true, "refs/heads/;");
209 		assertValid(true, "refs/heads/=");
210 		assertValid(true, "refs/heads/@");
211 		assertValid(true, "refs/heads/]");
212 		assertValid(true, "refs/heads/_");
213 		assertValid(true, "refs/heads/`");
214 		assertValid(true, "refs/heads/{");
215 		assertValid(true, "refs/heads/}");
216 
217 		// This is valid on UNIX, but not on Windows
218 		// hence we make in invalid due to non-portability
219 		//
220 		assertValid(false, "refs/heads/\\");
221 
222 		// More invalid characters on Windows, but we allow them
223 		assertInvalidOnWindows("refs/heads/\"");
224 		assertInvalidOnWindows("refs/heads/<");
225 		assertInvalidOnWindows("refs/heads/>");
226 		assertInvalidOnWindows("refs/heads/|");
227 	}
228 
229 	@Test
230 	public void testUnicodeNames() {
231 		assertValid(true, "refs/heads/\u00e5ngstr\u00f6m");
232 	}
233 
234 	@Test
235 	public void testRefLogQueryIsValidRef() {
236 		assertValid(false, "refs/heads/master@{1}");
237 		assertValid(false, "refs/heads/master@{1.hour.ago}");
238 	}
239 
240 	@Test
241 	public void testWindowsReservedNames() {
242 		// re-using code from DirCacheCheckoutTest, hence
243 		// only testing for one of the special names.
244 		assertInvalidOnWindows("refs/heads/con");
245 		assertInvalidOnWindows("refs/con/x");
246 		assertInvalidOnWindows("con/heads/x");
247 		assertValid(true, "refs/heads/conx");
248 		assertValid(true, "refs/heads/xcon");
249 	}
250 }