1   /*
2       StatCvs - CVS statistics generation 
3       Copyright (C) 2002  Lukasz Pekacki <lukasz@pekacki.de>
4       http://statcvs.sf.net/
5       
6       This library is free software; you can redistribute it and/or
7       modify it under the terms of the GNU Lesser General Public
8       License as published by the Free Software Foundation; either
9       version 2.1 of the License, or (at your option) any later version.
10  
11      This library is distributed in the hope that it will be useful,
12      but WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14      Lesser General Public License for more details.
15  
16      You should have received a copy of the GNU Lesser General Public
17      License along with this library; if not, write to the Free Software
18      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19      
20  	$RCSfile: LinesOfCodeTest.java,v $ 
21  	Created on $Date: 2004/12/14 13:38:13 $ 
22  */
23  
24  package net.sf.statsvn.input;
25  
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.Date;
29  import java.util.HashMap;
30  import java.util.Iterator;
31  import java.util.List;
32  
33  import junit.framework.TestCase;
34  import net.sf.statcvs.model.Revision;
35  import net.sf.statcvs.model.VersionedFile;
36  
37  /**
38   * Test cases for {@link Builder}, covering LOC calculations.
39   * 
40   * @todo most/all of them test only the FileBuilder -- refactor!
41   * 
42   * @author Anja Jentzsch
43   * @author Richard Cyganiak
44   * @see BuilderTest
45   * @version $Id: LinesOfCodeTest.java,v 1.18 2004/12/14 13:38:13 squig Exp $
46   */
47  public class LinesOfCodeTest extends TestCase {
48  	private Builder builder;
49  
50  	private VersionedFile file;
51  
52  	private Date date11;
53  
54  	private Date date12;
55  
56  	private Date date13;
57  
58  	private Date date14;
59  
60  	private Date date15;
61  
62  	private Revision rev0;
63  
64  	private Revision rev1;
65  
66  	private Revision rev2;
67  
68  	private Revision rev3;
69  
70  	private Revision rev4;
71  
72  	private DummyRepositoryFileManager fileman;
73  
74  	/**
75  	 * Constructor
76  	 * @param arg0 input
77  	 */
78  	public LinesOfCodeTest(final String arg0) {
79  		super(arg0);
80  	}
81  
82  	/**
83  	 * @see TestCase#setUp()
84  	 */
85  	protected void setUp() throws Exception {
86  		super.setUp();
87  		fileman = new DummyRepositoryFileManager();
88  		builder = new Builder(fileman, null, null, null);
89  		builder.buildFile("file", false, false, new HashMap(), new HashMap());
90  		file = null;
91  		date11 = new Date(1100000000);
92  		date12 = new Date(1200000000);
93  		date13 = new Date(1300000000);
94  		date14 = new Date(1400000000);
95  		date15 = new Date(1500000000);
96  		rev0 = null;
97  		rev1 = null;
98  		rev2 = null;
99  		rev3 = null;
100 		rev4 = null;
101 	}
102 
103 	/**
104 	 * Method testLinesOfCodeWithoutRepository1.
105 	 */
106 	public void testLinesOfCodeWithoutRepository1() throws Exception {
107 		buildRevision("2", date12, 5, 0);
108 		buildRevisionInitial("1", date11);
109 		finishBuilder();
110 		assertEquals(5, file.getCurrentLinesOfCode());
111 		assertRevisionLines(rev0, 5, 5, 5);
112 		assertRevisionLines(rev1, 0, 0, 0);
113 	}
114 
115 	/**
116 	 * Method testLinesOfCodeWithoutRepository2.
117 	 */
118 	public void testLinesOfCodeWithoutRepository2() throws Exception {
119 		buildRevision("2", date12, 0, 5);
120 		buildRevisionInitial("1", date11);
121 		finishBuilder();
122 		assertEquals(0, file.getCurrentLinesOfCode());
123 		assertRevisionLines(rev0, 0, -5, 0);
124 		assertRevisionLines(rev1, 5, 5, 5);
125 	}
126 
127 	/**
128 	 * Method testLinesOfCodeWithoutRepository3.
129 	 */
130 	public void testLinesOfCodeWithoutRepository3() throws Exception {
131 		buildRevision("5", date15, 10, 15);
132 		buildRevision("4", date14, 10, 0);
133 		buildRevision("3", date13, 25, 15);
134 		buildRevision("2", date12, 10, 0);
135 		buildRevisionInitial("1", date11);
136 		finishBuilder();
137 		assertEquals(30, file.getCurrentLinesOfCode());
138 		assertRevisionLines(rev0, 30, -5, 10);
139 		assertRevisionLines(rev1, 35, 10, 10);
140 		assertRevisionLines(rev2, 25, 10, 25);
141 		assertRevisionLines(rev3, 15, 10, 10);
142 		assertRevisionLines(rev4, 5, 5, 5);
143 	}
144 
145 	//  not relevant for SVN
146 	//	/**
147 	//	 * Test a file whose initial revision is dead (this means it was
148 	//	 * added on another branch). The builder should filter this file,
149 	//	 * so the Repository should be empty.
150 	//	 */
151 	//	public void testLinesOfCodeDeadInitial() throws Exception {
152 	// not relevant for SVN
153 	//		buildRevisionDead("1.1", date11);
154 	//		try {
155 	//			finishBuilder();
156 	//			fail("should have thrown EmptyRepositoryException");
157 	//		} catch (EmptyRepositoryException expected) {
158 	//			// is expected
159 	//		}
160 	//	}
161 
162 	//  not relevant for SVN
163 	//	/**
164 	//	 * Test a file whose initial revision is dead (this means it was
165 	//	 * added on another branch), but that was later merged into the
166 	//	 * trunk.
167 	//	 */
168 	//	public void testLinesOfCodeDeadInitialMerged() throws Exception {
169 	//		buildRevision("1.2", date12, 10, 0);
170 	//		buildRevisionDead("1.1", date11);
171 	//		fileman.setLinesOfCode("file", 10);
172 	//		finishBuilder();
173 	//		assertTrue(rev0.isInitialRevision());
174 	//		assertRevisionLines(rev0, 10, 10, 10);
175 	//		assertEquals(1, file.getRevisions().size());
176 	//	}
177 
178 	/**
179 	 * Simple test to make sure that the Builder pulls the LOC number
180 	 * from the RepositoryFileManager
181 	 */
182 	public void testLinesOfCodeInitial() throws Exception {
183 		fileman.setLinesOfCode("file", 100);
184 		buildRevisionInitial("1", date11);
185 		finishBuilder();
186 		assertEquals(100, file.getCurrentLinesOfCode());
187 		assertRevisionLines(rev0, 100, 100, 100);
188 	}
189 
190 	/**
191 	 * Test to make sure that LOC count for binary files is 0
192 	 */
193 	public void testLinesOfCodeBinary() throws Exception {
194 		fileman.setLinesOfCode("binaryfile", 100);
195 		builder.buildFile("binaryfile", true, false, new HashMap(), new HashMap());
196 		buildRevisionInitial("1", date11);
197 		finishBuilder();
198 
199 		// get "binaryfile"
200 		file = (VersionedFile) builder.createRepository().getFiles().first();
201 		assertEquals(0, file.getCurrentLinesOfCode());
202 		rev0 = (Revision) file.getRevisions().first();
203 		assertRevisionLines(rev0, 0, 0, 0);
204 	}
205 
206 	/**
207 	 * Test the behaviour of a deleted file, for which no HEAD LOC count
208 	 * is available.
209 	 */
210 	public void testLinesOfCodeWithDeletion() throws Exception {
211 		buildRevisionDead("3", date13);
212 		buildRevision("2", date12, 100, 0);
213 		buildRevisionInitial("1", date11);
214 		finishBuilder();
215 		assertTrue(file.isDead());
216 		assertEquals(0, file.getCurrentLinesOfCode());
217 		//TODO: WTF should LOC for a deleted file be 100? Counter-intuitive.
218 		assertRevisionLines(rev0, 0, -100, 0);
219 		assertRevisionLines(rev1, 100, 100, 100);
220 		assertRevisionLines(rev2, 0, 0, 0);
221 	}
222 
223 	/**
224 	 * Tests the behaviour for deleted and re-added files.
225 	 */
226 	public void testLinesOfCodeWithRestore() throws Exception {
227 		fileman.setLinesOfCode("file", 100);
228 		buildRevision("3", date13, 0, 0);
229 		buildRevisionDead("2", date12);
230 		buildRevisionInitial("1", date11);
231 		finishBuilder();
232 		assertTrue(!file.isDead());
233 		assertEquals(100, file.getCurrentLinesOfCode());
234 		assertTrue(rev0.isInitialRevision());
235 		assertRevisionLines(rev0, 100, 100, 100);
236 		assertTrue(rev1.isDead());
237 		assertRevisionLines(rev1, 0, -100, 0);
238 		assertTrue(rev2.isInitialRevision());
239 		assertRevisionLines(rev2, 100, 100, 100);
240 	}
241 
242 	/**
243 	 * Tests if "cvs log -d" logs work correctly when the file
244 	 * has no revisions in the -d timespan, but it did exist
245 	 */
246 	public void testPartialLogZeroRevisions() throws Exception {
247 		fileman.setLinesOfCode("file", 100);
248 		addAnotherFile();
249 		finishBuilder();
250 		assertNotNull(file);
251 		assertEquals(1, file.getRevisions().size());
252 		assertTrue(rev0.isBeginOfLog());
253 		assertNull(rev0.getAuthor());
254 		assertEquals(100, rev0.getLines());
255 		assertEquals(0, rev0.getReplacedLines());
256 		assertEquals(0, rev0.getLinesDelta());
257 	}
258 
259 	/**
260 	 * Tests if "cvs log -d" logs work correctly when the file
261 	 * did not exist during the -d timespan (that is, it was
262 	 * added at a later date, or removed before the start date)
263 	 */
264 	public void testPartialLogZeroRevisionsNoFile() throws Exception {
265 		addAnotherFile();
266 		finishBuilder();
267 		assertNull(file);
268 	}
269 
270 	public void testPartialLogOneRevision() throws Exception {
271 		fileman.setLinesOfCode("file", 100);
272 		buildRevision("5", date15, 80, 30);
273 		finishBuilder();
274 		assertEquals(3, file.getRevisions().size());
275 		assertEquals("5", rev0.getRevisionNumber());
276 		assertEquals("5", rev1.getRevisionNumber());
277 		assertEquals("0.0", rev2.getRevisionNumber());
278 		assertTrue(rev2.isBeginOfLog());
279 		assertRevisionLines(rev0, 100, 50, 80);
280 		assertRevisionLines(rev1, 0, 0, 0);
281 		assertRevisionLines(rev2, 50, 0, 0);
282 	}
283 
284 	private void buildRevision(final String revision, final Date date, final int linesAdded, final int linesRemoved) {
285 		final RevisionData data = new RevisionData();
286 		data.setStateExp(true);
287 		data.setRevisionNumber(revision);
288 		data.setLoginName("author1");
289 		data.setDate(date);
290 		data.setLines(linesAdded, linesRemoved);
291 		data.setComment("comment");
292 		builder.buildRevision(data);
293 	}
294 
295 	private void buildRevisionInitial(final String revision, final Date date) {
296 		final RevisionData data = new RevisionData();
297 		data.setStateExp(true);
298 		data.setStateAdded(true);
299 		data.setRevisionNumber(revision);
300 		data.setLoginName("author1");
301 		data.setDate(date);
302 		data.setComment("comment");
303 		builder.buildRevision(data);
304 	}
305 
306 	private void buildRevisionDead(final String revision, final Date date) {
307 		final RevisionData data = new RevisionData();
308 		data.setStateDead(true);
309 		data.setRevisionNumber(revision);
310 		data.setLoginName("author1");
311 		data.setDate(date);
312 		data.setComment("comment");
313 		builder.buildRevision(data);
314 	}
315 
316 	private void addAnotherFile() {
317 		builder.buildFile("file2", false, false, new HashMap(), new HashMap());
318 		buildRevisionInitial("1", date11);
319 	}
320 
321 	private void finishBuilder() {
322 		final Iterator it = builder.createRepository().getFiles().iterator();
323 		while (it.hasNext()) {
324 			final VersionedFile f = (VersionedFile) it.next();
325 			if (f.getFilename().equals("file")) {
326 				file = f;
327 			}
328 		}
329 		if (file == null) {
330 			return;
331 		}
332 		final List revisions = new ArrayList(file.getRevisions());
333 		Collections.reverse(revisions);
334 		try {
335 			rev0 = (Revision) revisions.get(0);
336 			rev1 = (Revision) revisions.get(1);
337 			rev2 = (Revision) revisions.get(2);
338 			rev3 = (Revision) revisions.get(3);
339 			rev4 = (Revision) revisions.get(4);
340 		} catch (final IndexOutOfBoundsException mightHappen) {
341 			// do nothing
342 		}
343 	}
344 
345 	private void assertRevisionLines(final Revision revision, final int effectiveLinesOfCode, final int locChange, final int lineValue) {
346 		assertEquals("effective lines of code", effectiveLinesOfCode, revision.getLines());
347 		assertEquals("lines of code change", locChange, revision.getLinesDelta());
348 		assertEquals("line value", lineValue, revision.getNewLines());
349 	}
350 }