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