View Javadoc
1   /*
2    * Copyright (C) 2010, Google Inc. 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  
11  package org.eclipse.jgit.internal.storage.pack;
12  
13  import static org.junit.Assert.assertArrayEquals;
14  import static org.junit.Assert.assertEquals;
15  import static org.junit.Assert.assertFalse;
16  import static org.junit.Assert.assertTrue;
17  
18  import java.io.ByteArrayOutputStream;
19  import java.io.IOException;
20  
21  import org.eclipse.jgit.junit.JGitTestUtil;
22  import org.eclipse.jgit.junit.TestRng;
23  import org.eclipse.jgit.lib.Constants;
24  import org.junit.Before;
25  import org.junit.Test;
26  
27  public class DeltaIndexTest {
28  	private TestRng rng;
29  
30  	private ByteArrayOutputStream actDeltaBuf;
31  
32  	private ByteArrayOutputStream expDeltaBuf;
33  
34  	private DeltaEncoder expDeltaEnc;
35  
36  	private byte[] src;
37  
38  	private byte[] dst;
39  
40  	private ByteArrayOutputStream dstBuf;
41  
42  	private TestRng getRng() {
43  		if (rng == null)
44  			rng = new TestRng(JGitTestUtil.getName());
45  		return rng;
46  	}
47  
48  	@Before
49  	public void setUp() throws Exception {
50  		actDeltaBuf = new ByteArrayOutputStream();
51  		expDeltaBuf = new ByteArrayOutputStream();
52  		expDeltaEnc = new DeltaEncoder(expDeltaBuf, 0, 0);
53  		dstBuf = new ByteArrayOutputStream();
54  	}
55  
56  	@Test
57  	public void testInsertWholeObject_Length12() throws IOException {
58  		src = getRng().nextBytes(12);
59  		insert(src);
60  		doTest();
61  	}
62  
63  	@Test
64  	public void testCopyWholeObject_Length128() throws IOException {
65  		src = getRng().nextBytes(128);
66  		copy(0, 128);
67  		doTest();
68  	}
69  
70  	@Test
71  	public void testCopyWholeObject_Length123() throws IOException {
72  		src = getRng().nextBytes(123);
73  		copy(0, 123);
74  		doTest();
75  	}
76  
77  	@Test
78  	public void testCopyZeros_Length128() throws IOException {
79  		src = new byte[2048];
80  		copy(0, src.length);
81  		doTest();
82  
83  		// The index should be smaller than expected due to the chain
84  		// being truncated. Without truncation we would expect to have
85  		// more than 3584 bytes used.
86  		//
87  		assertEquals(2636, new DeltaIndex(src).getIndexSize());
88  	}
89  
90  	@Test
91  	public void testShuffleSegments() throws IOException {
92  		src = getRng().nextBytes(128);
93  		copy(64, 64);
94  		copy(0, 64);
95  		doTest();
96  	}
97  
98  	@Test
99  	public void testInsertHeadMiddle() throws IOException {
100 		src = getRng().nextBytes(1024);
101 		insert("foo");
102 		copy(0, 512);
103 		insert("yet more fooery");
104 		copy(0, 512);
105 		doTest();
106 	}
107 
108 	@Test
109 	public void testInsertTail() throws IOException {
110 		src = getRng().nextBytes(1024);
111 		copy(0, 512);
112 		insert("bar");
113 		doTest();
114 	}
115 
116 	@Test
117 	public void testIndexSize() {
118 		src = getRng().nextBytes(1024);
119 		DeltaIndex di = new DeltaIndex(src);
120 		assertEquals(1860, di.getIndexSize());
121 		assertEquals("DeltaIndex[2 KiB]", di.toString());
122 	}
123 
124 	@Test
125 	public void testLimitObjectSize_Length12InsertFails() throws IOException {
126 		src = getRng().nextBytes(12);
127 		dst = src;
128 
129 		DeltaIndex di = new DeltaIndex(src);
130 		assertFalse(di.encode(actDeltaBuf, dst, src.length));
131 	}
132 
133 	@Test
134 	public void testLimitObjectSize_Length130InsertFails() throws IOException {
135 		src = getRng().nextBytes(130);
136 		dst = getRng().nextBytes(130);
137 
138 		DeltaIndex di = new DeltaIndex(src);
139 		assertFalse(di.encode(actDeltaBuf, dst, src.length));
140 	}
141 
142 	@Test
143 	public void testLimitObjectSize_Length130CopyOk() throws IOException {
144 		src = getRng().nextBytes(130);
145 		copy(0, 130);
146 		dst = dstBuf.toByteArray();
147 
148 		DeltaIndex di = new DeltaIndex(src);
149 		assertTrue(di.encode(actDeltaBuf, dst, dst.length));
150 
151 		byte[] actDelta = actDeltaBuf.toByteArray();
152 		byte[] expDelta = expDeltaBuf.toByteArray();
153 
154 		assertEquals(BinaryDelta.format(expDelta, false), //
155 				BinaryDelta.format(actDelta, false));
156 	}
157 
158 	@Test
159 	public void testLimitObjectSize_Length130CopyFails() throws IOException {
160 		src = getRng().nextBytes(130);
161 		copy(0, 130);
162 		dst = dstBuf.toByteArray();
163 
164 		// The header requires 4 bytes for these objects, so a target length
165 		// of 5 is bigger than the copy instruction and should cause an abort.
166 		//
167 		DeltaIndex di = new DeltaIndex(src);
168 		assertFalse(di.encode(actDeltaBuf, dst, 5));
169 		assertEquals(4, actDeltaBuf.size());
170 	}
171 
172 	@Test
173 	public void testLimitObjectSize_InsertFrontFails() throws IOException {
174 		src = getRng().nextBytes(130);
175 		insert("eight");
176 		copy(0, 130);
177 		dst = dstBuf.toByteArray();
178 
179 		// The header requires 4 bytes for these objects, so a target length
180 		// of 5 is bigger than the copy instruction and should cause an abort.
181 		//
182 		DeltaIndex di = new DeltaIndex(src);
183 		assertFalse(di.encode(actDeltaBuf, dst, 5));
184 		assertEquals(4, actDeltaBuf.size());
185 	}
186 
187 	private void copy(int offset, int len) throws IOException {
188 		dstBuf.write(src, offset, len);
189 		expDeltaEnc.copy(offset, len);
190 	}
191 
192 	private void insert(String text) throws IOException {
193 		insert(Constants.encode(text));
194 	}
195 
196 	private void insert(byte[] text) throws IOException {
197 		dstBuf.write(text);
198 		expDeltaEnc.insert(text);
199 	}
200 
201 	private void doTest() throws IOException {
202 		dst = dstBuf.toByteArray();
203 
204 		DeltaIndex di = new DeltaIndex(src);
205 		di.encode(actDeltaBuf, dst);
206 
207 		byte[] actDelta = actDeltaBuf.toByteArray();
208 		byte[] expDelta = expDeltaBuf.toByteArray();
209 
210 		assertEquals(BinaryDelta.format(expDelta, false), //
211 				BinaryDelta.format(actDelta, false));
212 
213 		assertTrue("delta is not empty", actDelta.length > 0);
214 		assertEquals(src.length, BinaryDelta.getBaseSize(actDelta));
215 		assertEquals(dst.length, BinaryDelta.getResultSize(actDelta));
216 		assertArrayEquals(dst, BinaryDelta.apply(src, actDelta));
217 	}
218 }