1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.statsvn.input;
21
22 import java.io.ByteArrayInputStream;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.Reader;
26 import java.util.Calendar;
27 import java.util.Date;
28 import java.util.NoSuchElementException;
29 import java.util.TimeZone;
30
31 import junit.framework.TestCase;
32 import net.sf.statcvs.input.LogSyntaxException;
33 import net.sf.statcvs.util.LookaheadReader;
34
35 /**
36 * Tests for {@link SvnLogfileParser} and {@link FileBlockParser}. Most
37 * tests run the parser class on a logfile loaded from the file system and
38 * use a {@link MockBuilder} to verify the results.
39 *
40 * @author Richard Cyganiak <richard@cyganiak.de>
41 * @version $Id: ParserTest.java,v 1.5 2004/10/10 11:29:07 cyganiak Exp $
42 */
43 public class ParserTest extends TestCase {
44 private final static Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
45
46 private MockLogBuilder mock;
47
48 private RevisionData rev1;
49
50 public ParserTest(final String arg0) {
51 super(arg0);
52 }
53
54
55
56
57 protected void setUp() throws Exception {
58 super.setUp();
59 mock = new MockLogBuilder();
60 rev1 = new RevisionData();
61 }
62
63 /**
64 * Tests simple.log
65 * @throws Exception on error
66 */
67 public void testSimpleLog() throws Exception {
68 mock.expectBuildModule("statcvs");
69 mock.expectBuildFile("LICENSE", false, false);
70 rev1.setRevisionNumber("1.1");
71 rev1.setDate(createDate(2003, 06, 04, 19, 32, 58));
72 rev1.setLoginName("cyganiak");
73 rev1.setStateExp(true);
74 rev1.setComment("renamed license.txt to LICENSE");
75 mock.expectBuildRevision(rev1);
76 parseLog("simple.log");
77 mock.verify();
78 }
79
80 /**
81 * Tests a logfile which was created when uncommited files were present in
82 * the working copy ("? filename" lines at the beginning). They must be
83 * ignored.
84 * @throws Exception on error
85 */
86 public void testUncommittedFiles() throws Exception {
87 mock.expectBuildModule("statcvs");
88 mock.expectBuildFile("LICENSE", false, false);
89 mock.expectCurrentRevisionNumber("1.1");
90 parseLog("uncommitted-files.log");
91 mock.verify();
92 }
93
94 /**
95 * Tests two-files.log
96 * @throws Exception
97 */
98 public void testTwoFiles() throws Exception {
99 mock.expectBuildModule("statcvs");
100 mock.expectBuildFile("LICENSE", false, false);
101 mock.expectCurrentRevisionNumber("1.2");
102 mock.expectNextRevision();
103 mock.expectCurrentRevisionNumber("1.1");
104 mock.expectBuildFile("README", false, false);
105 mock.expectCurrentRevisionNumber("1.1");
106 parseLog("two-files.log");
107 mock.verify();
108 }
109
110 /**
111 * Tests parsing a log with a file that has no selected revisions.
112 * Necessary when specifying ranges of dates or tags. The log still
113 * contains all files but some may have no selected revisions.
114 * @throws Exception
115 */
116 public void testNoRevisionsSelected() throws Exception {
117 mock.expectBuildModule("statcvs");
118 mock.expectBuildFile("LICENSE", false, false);
119 mock.expectBuildFile("README", false, false);
120 mock.expectCurrentRevisionNumber("1.1");
121 parseLog("no-revs-selected.log");
122 mock.verify();
123 }
124
125 /**
126 * Same as {@link #testNoRevisionsSelected}, but now the file has a description.
127 * The description must be ignored by the parser.
128 * @throws Exception
129 */
130 public void testNoRevisionsSelectedWithDescription() throws Exception {
131 mock.expectBuildModule("statcvs");
132 mock.expectBuildFile("LICENSE", false, false);
133 mock.expectBuildFile("README", false, false);
134 mock.expectCurrentRevisionNumber("1.1");
135 parseLog("no-revs-selected-w-description.log");
136 mock.verify();
137 }
138
139 /**
140 * Not sure why that was put in, but apparently we want the parser to
141 * deal gracefully with newlines at the end of the file.
142 * @throws Exception on error
143 */
144 public void testEmptyLinesAfterEnd() throws Exception {
145 mock.expectBuildModule("statcvs");
146 mock.expectBuildFile("LICENSE", false, false);
147 mock.expectNextRevision();
148 parseLog("newlines-after-end.log");
149 mock.verify();
150 }
151
152 /**
153 * Tests if the parser can handle a revision delimiter in the comment.
154 * @throws Exception
155 */
156 public void testRevisionDelimiterInComment() throws Exception {
157 mock.expectBuildModule("statcvs");
158 mock.expectBuildFile("LICENSE", false, false);
159 mock.expectCurrentRevisionNumber("1.1");
160 mock.expectCurrentComment("comment\n----------------------------\ncomment");
161 mock.expectBuildFile("README", false, false);
162 mock.expectCurrentRevisionNumber("1.1");
163 parseLog("delimiter-in-comment.log");
164 mock.verify();
165 }
166
167 /**
168 * Tests for exception on empty logfile
169 * @throws Exception
170 */
171 public void testEmptyLog() throws Exception {
172 final ByteArrayInputStream stream = new ByteArrayInputStream("".getBytes());
173
174 final SvnLogfileParser parser = new SvnLogfileParser(null, stream, mock);
175 try {
176 parser.parse();
177 fail("should have thrown LogSyntaxException");
178 } catch (final LogSyntaxException expected) {
179
180 }
181 }
182
183 /**
184 * Tests for exception on bogus logfile
185 * @throws Exception
186 */
187 public void testBogusLog() throws Exception {
188 final ByteArrayInputStream stream = new ByteArrayInputStream("foo\nbar".getBytes());
189
190 final SvnLogfileParser parser = new SvnLogfileParser(null, stream, mock);
191 try {
192 parser.parse();
193 fail("should have thrown LogSyntaxException");
194 } catch (final LogSyntaxException expected) {
195
196 }
197 }
198
199 /**
200 * Tests the FileBlockParser for a first file
201 * @throws Exception
202 */
203 public void testFirstFile() throws Exception {
204 mock.expectBuildModule("statcvs");
205 mock.expectBuildFile("LICENSE", false, false);
206 mock.expectCurrentRevisionNumber("1.1");
207 final Reader reader = new InputStreamReader(getClass().getResourceAsStream("simple.log2"));
208 final LookaheadReader lookahead = new LookaheadReader(reader);
209 lookahead.nextLine();
210
211 mock.verify();
212 reader.close();
213 }
214
215 /**
216 * Tests the FileBlockParser for a non-first file
217 * @throws Exception
218 */
219 public void testNonFirstFile() throws Exception {
220 mock.expectBuildFile("LICENSE", false, false);
221 mock.expectCurrentRevisionNumber("1.1");
222 parseOneFile("simple.log2");
223 mock.verify();
224 }
225
226 /**
227 * Tests the FileBlockParser for a file with description
228 * @throws Exception
229 */
230 public void testDescription() throws Exception {
231 mock.expectBuildFile("LICENSE", false, false);
232 mock.expectCurrentRevisionNumber("1.1");
233 parseOneFile("description.log2");
234 mock.verify();
235 }
236
237 /**
238 * Tests parsing a log with a lock ("cyganiak: 1.1")
239 * @throws Exception on error
240 */
241 public void testLocks() throws Exception {
242 mock.expectBuildFile("LICENSE", false, false);
243 mock.expectCurrentRevisionNumber("1.1");
244 parseOneFile("locks.log2");
245 mock.verify();
246 }
247
248 /**
249 * Tests the FileBlockParser for a file with access list
250 * @throws Exception on error
251 */
252 public void testAccessList() throws Exception {
253 mock.expectBuildFile("LICENSE", false, false);
254 mock.expectCurrentRevisionNumber("1.1");
255 parseOneFile("access-list.log2");
256 mock.verify();
257 }
258
259 /**
260 * Test log with missing "symbolic names:" section. Such
261 * logs are created by the -N switch of the cvs log command.
262 * @throws Exception on error
263 */
264 public void testNoSymbolicNames() throws Exception {
265 mock.expectBuildFile("LICENSE", false, false);
266 mock.expectCurrentRevisionNumber("1.1");
267 parseOneFile("no-symbolic-names.log2");
268 mock.verify();
269 }
270
271 /**
272 * Tests if attic files are correctly identified.
273 * @throws Exception on error
274 * @see net.sf.statsvn.util.SvnLogUtilsTest.testIsInAttic
275 */
276 public void testIsInAttic() throws Exception {
277 mock.expectBuildFile("LICENSE", false, true);
278 mock.expectCurrentRevisionNumber("1.1");
279 parseOneFile("in-attic.log2");
280 mock.verify();
281 }
282
283 public void testTwoRevisions() throws Exception {
284 mock.expectBuildFile("LICENSE", false, false);
285 mock.expectCurrentRevisionNumber("1.2");
286 mock.expectCurrentAuthor("jentzsch");
287 mock.expectCurrentDate(createDate(2003, 6, 5, 19, 32, 58));
288 mock.expectCurrentComment("comment2");
289 mock.expectCurrentStateExp();
290 mock.expectCurrentLines(10, 0);
291 mock.expectNextRevision();
292 mock.expectCurrentRevisionNumber("1.1");
293 mock.expectCurrentAuthor("cyganiak");
294 mock.expectCurrentDate(createDate(2003, 6, 4, 19, 32, 58));
295 mock.expectCurrentComment("comment1");
296 mock.expectCurrentNoLines();
297 parseOneFile("two-revisions.log2");
298 mock.verify();
299 }
300
301 /**
302 * Tests the FileBlockParser for a binary file
303 * @throws Exception
304 */
305 public void testBinary() throws Exception {
306 mock.expectBuildFile("LICENSE", true, false);
307 mock.expectCurrentRevisionNumber("1.1");
308 parseOneFile("binary.log2");
309 mock.verify();
310 }
311
312 /**
313 * Recent CVS versions have a different date format
314 */
315 public void testNewCVSDates() throws Exception {
316 this.mock.expectBuildFile("LICENSE", false, false);
317 this.mock.expectCurrentRevisionNumber("1.1");
318 this.mock.expectCurrentDate(createDate(2004, 07, 18, 17, 42, 25));
319 parseOneFile("newdate.log2");
320 this.mock.verify();
321 }
322
323 public void testPrematurelyEndingLog() throws Exception {
324 this.mock.expectBuildFile("LICENSE", false, false);
325 try {
326 parseOneFile("premature-end.log2");
327 fail();
328 } catch (final NoSuchElementException ex) {
329
330 }
331 }
332
333 private void parseLog(final String name) throws Exception {
334 final InputStream stream = getClass().getResourceAsStream(name);
335
336 new SvnLogfileParser(null, stream, mock).parse();
337 }
338
339 private void parseOneFile(final String name) throws Exception {
340 final Reader reader = new InputStreamReader(getClass().getResourceAsStream(name));
341 final LookaheadReader lookahead = new LookaheadReader(reader);
342 lookahead.nextLine();
343
344 reader.close();
345 }
346
347 private Date createDate(final int year, final int month, final int day, final int hour, final int minute, final int second) {
348 calendar.set(year, month - 1, day, hour, minute, second);
349 return calendar.getTime();
350 }
351 }