View Javadoc
1   /*
2    * Copyright (C) 2009-2010, Google Inc.
3    * Copyright (C) 2009, Robin Rosenberg
4    * Copyright (C) 2009, Robin Rosenberg <robin.rosenberg@dewire.com>
5    * and other copyright owners as documented in the project's IP log.
6    *
7    * This program and the accompanying materials are made available
8    * under the terms of the Eclipse Distribution License v1.0 which
9    * accompanies this distribution, is reproduced below, and is
10   * available at http://www.eclipse.org/org/documents/edl-v10.php
11   *
12   * All rights reserved.
13   *
14   * Redistribution and use in source and binary forms, with or
15   * without modification, are permitted provided that the following
16   * conditions are met:
17   *
18   * - Redistributions of source code must retain the above copyright
19   *   notice, this list of conditions and the following disclaimer.
20   *
21   * - Redistributions in binary form must reproduce the above
22   *   copyright notice, this list of conditions and the following
23   *   disclaimer in the documentation and/or other materials provided
24   *   with the distribution.
25   *
26   * - Neither the name of the Eclipse Foundation, Inc. nor the
27   *   names of its contributors may be used to endorse or promote
28   *   products derived from this software without specific prior
29   *   written permission.
30   *
31   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
32   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
33   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
36   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
38   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
40   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
43   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44   */
45  
46  package org.eclipse.jgit.lib;
47  
48  import static org.eclipse.jgit.junit.Assert.assertEquals;
49  import static org.junit.Assert.assertEquals;
50  import static org.junit.Assert.assertFalse;
51  import static org.junit.Assert.assertNotNull;
52  import static org.junit.Assert.assertNull;
53  import static org.junit.Assert.assertSame;
54  import static org.junit.Assert.assertTrue;
55  import static org.junit.Assert.fail;
56  
57  import java.io.File;
58  import java.io.FileOutputStream;
59  import java.io.IOException;
60  import java.util.Map;
61  import java.util.TreeSet;
62  
63  import org.eclipse.jgit.lib.Ref.Storage;
64  import org.eclipse.jgit.lib.RefUpdate.Result;
65  import org.eclipse.jgit.storage.file.FileBasedConfig;
66  import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
67  import org.junit.Test;
68  
69  /**
70   * Misc tests for refs. A lot of things are tested elsewhere so not having a
71   * test for a ref related method, does not mean it is untested.
72   */
73  public class RefTest extends SampleDataRepositoryTestCase {
74  
75  	private void writeSymref(String src, String dst) throws IOException {
76  		RefUpdate u = db.updateRef(src);
77  		switch (u.link(dst)) {
78  		case NEW:
79  		case FORCED:
80  		case NO_CHANGE:
81  			break;
82  		default:
83  			fail("link " + src + " to " + dst);
84  		}
85  	}
86  
87  	@Test
88  	public void testRemoteNames() throws Exception {
89  		FileBasedConfig config = db.getConfig();
90  		config.setBoolean(ConfigConstants.CONFIG_REMOTE_SECTION,
91  				"origin", "dummy", true);
92  		config.setBoolean(ConfigConstants.CONFIG_REMOTE_SECTION,
93  				"ab/c", "dummy", true);
94  		config.save();
95  		assertEquals("[ab/c, origin]",
96  				new TreeSet<String>(db.getRemoteNames()).toString());
97  
98  		// one-level deep remote branch
99  		assertEquals("master",
100 				db.shortenRemoteBranchName("refs/remotes/origin/master"));
101 		assertEquals("origin", db.getRemoteName("refs/remotes/origin/master"));
102 
103 		// two-level deep remote branch
104 		assertEquals("masta/r",
105 				db.shortenRemoteBranchName("refs/remotes/origin/masta/r"));
106 		assertEquals("origin", db.getRemoteName("refs/remotes/origin/masta/r"));
107 
108 		// Remote with slash and one-level deep branch name
109 		assertEquals("xmaster",
110 				db.shortenRemoteBranchName("refs/remotes/ab/c/xmaster"));
111 		assertEquals("ab/c", db.getRemoteName("refs/remotes/ab/c/xmaster"));
112 
113 		// Remote with slash and two-level deep branch name
114 		assertEquals("xmasta/r",
115 				db.shortenRemoteBranchName("refs/remotes/ab/c/xmasta/r"));
116 		assertEquals("ab/c", db.getRemoteName("refs/remotes/ab/c/xmasta/r"));
117 
118 		// no such remote
119 		assertNull(db.getRemoteName("refs/remotes/nosuchremote/x"));
120 		assertNull(db.shortenRemoteBranchName("refs/remotes/nosuchremote/x"));
121 
122 		// no such remote too, no branch name either
123 		assertNull(db.getRemoteName("refs/remotes/abranch"));
124 		assertNull(db.shortenRemoteBranchName("refs/remotes/abranch"));
125 
126 		// // local branch
127 		assertNull(db.getRemoteName("refs/heads/abranch"));
128 		assertNull(db.shortenRemoteBranchName("refs/heads/abranch"));
129 	}
130 
131 	@Test
132 	public void testReadAllIncludingSymrefs() throws Exception {
133 		ObjectId masterId = db.resolve("refs/heads/master");
134 		RefUpdate updateRef = db.updateRef("refs/remotes/origin/master");
135 		updateRef.setNewObjectId(masterId);
136 		updateRef.setForceUpdate(true);
137 		updateRef.update();
138 		writeSymref("refs/remotes/origin/HEAD",
139 					"refs/remotes/origin/master");
140 
141 		ObjectId r = db.resolve("refs/remotes/origin/HEAD");
142 		assertEquals(masterId, r);
143 
144 		Map<String, Ref> allRefs = db.getAllRefs();
145 		Ref refHEAD = allRefs.get("refs/remotes/origin/HEAD");
146 		assertNotNull(refHEAD);
147 		assertEquals(masterId, refHEAD.getObjectId());
148 		assertFalse(refHEAD.isPeeled());
149 		assertNull(refHEAD.getPeeledObjectId());
150 
151 		Ref refmaster = allRefs.get("refs/remotes/origin/master");
152 		assertEquals(masterId, refmaster.getObjectId());
153 		assertFalse(refmaster.isPeeled());
154 		assertNull(refmaster.getPeeledObjectId());
155 	}
156 
157 	@Test
158 	public void testReadSymRefToPacked() throws IOException {
159 		writeSymref("HEAD", "refs/heads/b");
160 		Ref ref = db.getRef("HEAD");
161 		assertEquals(Ref.Storage.LOOSE, ref.getStorage());
162 		assertTrue("is symref", ref.isSymbolic());
163 		ref = ref.getTarget();
164 		assertEquals("refs/heads/b", ref.getName());
165 		assertEquals(Ref.Storage.PACKED, ref.getStorage());
166 	}
167 
168 	@Test
169 	public void testReadSymRefToLoosePacked() throws IOException {
170 		ObjectId pid = db.resolve("refs/heads/master^");
171 		RefUpdate updateRef = db.updateRef("refs/heads/master");
172 		updateRef.setNewObjectId(pid);
173 		updateRef.setForceUpdate(true);
174 		Result update = updateRef.update();
175 		assertEquals(Result.FORCED, update); // internal
176 
177 		writeSymref("HEAD", "refs/heads/master");
178 		Ref ref = db.getRef("HEAD");
179 		assertEquals(Ref.Storage.LOOSE, ref.getStorage());
180 		ref = ref.getTarget();
181 		assertEquals("refs/heads/master", ref.getName());
182 		assertEquals(Ref.Storage.LOOSE, ref.getStorage());
183 	}
184 
185 	@Test
186 	public void testReadLooseRef() throws IOException {
187 		RefUpdate updateRef = db.updateRef("ref/heads/new");
188 		updateRef.setNewObjectId(db.resolve("refs/heads/master"));
189 		Result update = updateRef.update();
190 		assertEquals(Result.NEW, update);
191 		Ref ref = db.getRef("ref/heads/new");
192 		assertEquals(Storage.LOOSE, ref.getStorage());
193 	}
194 
195 	/**
196 	 * Let an "outsider" create a loose ref with the same name as a packed one
197 	 *
198 	 * @throws IOException
199 	 * @throws InterruptedException
200 	 */
201 	@Test
202 	public void testReadLoosePackedRef() throws IOException,
203 			InterruptedException {
204 		Ref ref = db.getRef("refs/heads/master");
205 		assertEquals(Storage.PACKED, ref.getStorage());
206 		FileOutputStream os = new FileOutputStream(new File(db.getDirectory(),
207 				"refs/heads/master"));
208 		os.write(ref.getObjectId().name().getBytes());
209 		os.write('\n');
210 		os.close();
211 
212 		ref = db.getRef("refs/heads/master");
213 		assertEquals(Storage.LOOSE, ref.getStorage());
214 	}
215 
216 	/**
217 	 * Modify a packed ref using the API. This creates a loose ref too, ie.
218 	 * LOOSE_PACKED
219 	 *
220 	 * @throws IOException
221 	 */
222 	@Test
223 	public void testReadSimplePackedRefSameRepo() throws IOException {
224 		Ref ref = db.getRef("refs/heads/master");
225 		ObjectId pid = db.resolve("refs/heads/master^");
226 		assertEquals(Storage.PACKED, ref.getStorage());
227 		RefUpdate updateRef = db.updateRef("refs/heads/master");
228 		updateRef.setNewObjectId(pid);
229 		updateRef.setForceUpdate(true);
230 		Result update = updateRef.update();
231 		assertEquals(Result.FORCED, update);
232 
233 		ref = db.getRef("refs/heads/master");
234 		assertEquals(Storage.LOOSE, ref.getStorage());
235 	}
236 
237 	@Test
238 	public void testResolvedNamesBranch() throws IOException {
239 		Ref ref = db.getRef("a");
240 		assertEquals("refs/heads/a", ref.getName());
241 	}
242 
243 	@Test
244 	public void testResolvedSymRef() throws IOException {
245 		Ref ref = db.getRef(Constants.HEAD);
246 		assertEquals(Constants.HEAD, ref.getName());
247 		assertTrue("is symbolic ref", ref.isSymbolic());
248 		assertSame(Ref.Storage.LOOSE, ref.getStorage());
249 
250 		Ref dst = ref.getTarget();
251 		assertNotNull("has target", dst);
252 		assertEquals("refs/heads/master", dst.getName());
253 
254 		assertSame(dst.getObjectId(), ref.getObjectId());
255 		assertSame(dst.getPeeledObjectId(), ref.getPeeledObjectId());
256 		assertEquals(dst.isPeeled(), ref.isPeeled());
257 	}
258 }