|
1 /* |
|
2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 */ |
|
23 |
|
24 import java.lang.reflect.Constructor; |
|
25 import java.lang.reflect.Field; |
|
26 import java.lang.reflect.Method; |
|
27 import java.util.Arrays; |
|
28 import java.util.concurrent.Callable; |
|
29 import java.util.function.Consumer; |
|
30 |
|
31 import sun.security.util.ManifestDigester; |
|
32 |
|
33 import org.testng.annotations.Test; |
|
34 import org.testng.annotations.BeforeClass; |
|
35 import org.testng.annotations.BeforeMethod; |
|
36 import org.testng.annotations.DataProvider; |
|
37 import org.testng.annotations.Factory; |
|
38 |
|
39 import static java.nio.charset.StandardCharsets.UTF_8; |
|
40 import static org.testng.Assert.*; |
|
41 |
|
42 /** |
|
43 * @test |
|
44 * @bug 8217375 |
|
45 * @modules java.base/sun.security.util:+open |
|
46 * @compile ../../tools/jarsigner/Utils.java |
|
47 * @run testng/othervm FindSection |
|
48 * @summary Check {@link ManifestDigester#findSection}. |
|
49 */ |
|
50 public class FindSection { |
|
51 |
|
52 /* |
|
53 * TODO: |
|
54 * FIXED_8217375 is not intended to keep. it is intended to show what |
|
55 * exactly has changed with respect to the previous version for which no |
|
56 * such test existed. |
|
57 */ |
|
58 static final boolean FIXED_8217375 = true; |
|
59 |
|
60 /** |
|
61 * {@link ManifestDigester.Entry#digestWorkaround} should not feed the |
|
62 * trailing blank line into the digester. Before resolution of 8217375 it |
|
63 * fed the trailing blank line into the digest if the second line break |
|
64 * was at the end of the file due to <pre> |
|
65 * if (allBlank || (i == len-1)) { |
|
66 * if (i == len-1) |
|
67 * pos.endOfSection = i; |
|
68 * else |
|
69 * pos.endOfSection = last; |
|
70 * </pre> in {@link ManifestDigester#findSection}. In that case at the end |
|
71 * of the manifest file, {@link ManifestDigester.Entry#digestWorkaround} |
|
72 * would have produced the same digest as |
|
73 * {@link ManifestDigester.Entry#digest} which was wrong and without effect |
|
74 * at best. |
|
75 * <p> |
|
76 * Once this fix is accepted, this flag can be removed along with |
|
77 * {@link #actualEndOfSection8217375}. |
|
78 */ |
|
79 static final boolean FIXED_8217375_EOF_ENDOFSECTION = FIXED_8217375; |
|
80 |
|
81 /** |
|
82 * {@link ManifestDigester.Position.endOfSection} usually points to the |
|
83 * start position of the blank line trailing a section minus one. |
|
84 * If a {@link ManifestDigester.Position} returned by |
|
85 * {@link ManifestDigester#findSection} is based on a portion that starts |
|
86 * with a blank line, above statement is (or was) not true, because of the |
|
87 * initialization of {@code last} in {@link ManifestDigester#findSection} |
|
88 * <pre> |
|
89 * int last = offset; |
|
90 * </pre> |
|
91 * which would point after incrementing it in {@code pos.endOfSection + 1} |
|
92 * on line 128 (line number before this change) or {@code int sectionLen = |
|
93 * pos.endOfSection-start+1;} on line 133 (line number before this change) |
|
94 * at one byte after the first line break character of usually two and |
|
95 * possibly (assuming "{@code \r\n}" default line break normally) in between |
|
96 * the two characters of a line break. After subtracting again the index of |
|
97 * the section start position on former line 133, the last byte would be |
|
98 * missed to be digested by {@link ManifestDigester.Entry#digestWorkaround}. |
|
99 * <p> |
|
100 * All this, however could possibly matter (or have mattered) only when |
|
101 * {@link ManifestDigester#findSection} was invoked with an offset position |
|
102 * pointing straight to a line break which happens if a manifest starts |
|
103 * with an empty line or if there are superfluous blank lines between |
|
104 * sections in both cases no useful manifest portion is identified. |
|
105 * Superfluous blank lines are not identified as sections (because they |
|
106 * don't have a name and specifically don't meet {@code if (len > 6) {} on |
|
107 * former line 136. Manifests starting with a line break are not any more |
|
108 * useful either. |
|
109 * <p> |
|
110 * Once this fix is accepted, this flag can be removed along with |
|
111 * {@link #actualEndOfSection8217375}. |
|
112 */ |
|
113 static final boolean FIXED_8217375_STARTWITHBLANKLINE_ENDOFSECTION = |
|
114 FIXED_8217375; |
|
115 |
|
116 static Constructor<?> PositionConstructor; |
|
117 static Method findSection; |
|
118 static Field rawBytes; |
|
119 static Field endOfFirstLine; |
|
120 static Field endOfSection; |
|
121 static Field startOfNext; |
|
122 |
|
123 @BeforeClass |
|
124 public static void setFindSectionAccessible() throws Exception { |
|
125 Class<?> Position = Arrays.stream(ManifestDigester.class. |
|
126 getDeclaredClasses()).filter(c -> c.getSimpleName(). |
|
127 equals("Position")).findFirst().get(); |
|
128 PositionConstructor = Position.getDeclaredConstructor(); |
|
129 PositionConstructor.setAccessible(true); |
|
130 findSection = ManifestDigester.class.getDeclaredMethod("findSection", |
|
131 int.class, Position); |
|
132 findSection.setAccessible(true); |
|
133 rawBytes = ManifestDigester.class.getDeclaredField("rawBytes"); |
|
134 rawBytes.setAccessible(true); |
|
135 endOfFirstLine = Position.getDeclaredField("endOfFirstLine"); |
|
136 endOfFirstLine.setAccessible(true); |
|
137 endOfSection = Position.getDeclaredField("endOfSection"); |
|
138 endOfSection.setAccessible(true); |
|
139 startOfNext = Position.getDeclaredField("startOfNext"); |
|
140 startOfNext.setAccessible(true); |
|
141 } |
|
142 |
|
143 static class Position { |
|
144 final int endOfFirstLine; // not including newline character |
|
145 |
|
146 final int endOfSection; // end of section, not including the blank line |
|
147 // between sections |
|
148 final int startOfNext; // the start of the next section |
|
149 |
|
150 Position(Object pos) throws ReflectiveOperationException { |
|
151 endOfFirstLine = FindSection.endOfFirstLine.getInt(pos); |
|
152 endOfSection = FindSection.endOfSection.getInt(pos); |
|
153 startOfNext = FindSection.startOfNext.getInt(pos); |
|
154 } |
|
155 } |
|
156 |
|
157 Position findSection(byte[] manifestBytes) |
|
158 throws ReflectiveOperationException { |
|
159 ManifestDigester manDig = new ManifestDigester("\n\n".getBytes(UTF_8)); |
|
160 FindSection.rawBytes.set(manDig, manifestBytes); |
|
161 Object pos = PositionConstructor.newInstance(); |
|
162 Object result = findSection.invoke(manDig, offset, pos); |
|
163 if (Boolean.FALSE.equals(result)) { |
|
164 return null; // indicates findSection having returned false |
|
165 } else { |
|
166 return new Position(pos); |
|
167 } |
|
168 } |
|
169 |
|
170 @DataProvider(name = "parameters") |
|
171 public static Object[][] parameters() { |
|
172 return new Object[][] { { 0 }, { 42 } }; |
|
173 } |
|
174 |
|
175 @Factory(dataProvider = "parameters") |
|
176 public static Object[] createTests(int offset) { |
|
177 return new Object[]{ new FindSection(offset) }; |
|
178 } |
|
179 |
|
180 final int offset; |
|
181 |
|
182 FindSection(int offset) { |
|
183 this.offset = offset; |
|
184 } |
|
185 |
|
186 @BeforeMethod |
|
187 public void verbose() { |
|
188 System.out.println("offset = " + offset); |
|
189 } |
|
190 |
|
191 Position findSection(String manifestString) |
|
192 throws ReflectiveOperationException { |
|
193 byte[] manifestBytes = manifestString.getBytes(UTF_8); |
|
194 byte[] manifestWithOffset = new byte[manifestBytes.length + offset]; |
|
195 System.arraycopy(manifestBytes, 0, manifestWithOffset, offset, |
|
196 manifestBytes.length); |
|
197 return findSection(manifestWithOffset); |
|
198 } |
|
199 |
|
200 /** |
|
201 * Surprising, but the offset actually makes a difference in |
|
202 * {@link ManifestDigester#findSection} return value. |
|
203 */ |
|
204 @SuppressWarnings("unused") |
|
205 int actualEndOfFirstLine8217375(int correctPosition) { |
|
206 // if the parsed portion of the manifest starts with a blank line, |
|
207 // and offset is 0, "pos.endOfFirstLine = -1;" probably denoting a |
|
208 // yet uninitialized value coincides with the assignment by |
|
209 // "pos.endOfFirstLine = i-1;" if i == 0 and |
|
210 // "if (pos.endOfFirstLine == -1)" after "case '\n':" happens to |
|
211 // become true even though already assigned. |
|
212 if (offset == 0 && correctPosition == -1 && !FIXED_8217375) return 0; |
|
213 return correctPosition; |
|
214 } |
|
215 |
|
216 @SuppressWarnings("unused") |
|
217 int actualEndOfSection8217375(int correctPosition, boolean eof, int lbl) { |
|
218 // if the parsed portion of the manifest ends with a blank line and |
|
219 // just before eof, the blank line is included in Position.endOfSection/ |
|
220 // Section.length (the one usually without blank line as well as in |
|
221 // Position.startOfNext/Section.lengthWithBlankLine) which is used |
|
222 // in digestWorkaround (independent of the digest without workaround) |
|
223 if (eof && !FIXED_8217375_EOF_ENDOFSECTION) { |
|
224 return correctPosition + lbl; |
|
225 } else if (correctPosition == -1 |
|
226 && !FIXED_8217375_STARTWITHBLANKLINE_ENDOFSECTION) { |
|
227 return 0; |
|
228 } else { |
|
229 return correctPosition; |
|
230 } |
|
231 } |
|
232 |
|
233 AssertionError collectErrors(AssertionError a, Runnable run) { |
|
234 try { |
|
235 run.run(); |
|
236 } catch (AssertionError e) { |
|
237 if (a == null) a = new AssertionError(); |
|
238 a.addSuppressed(e); |
|
239 } |
|
240 return a; |
|
241 } |
|
242 |
|
243 void assertPosition(Position pos, |
|
244 int endOfFirstLine, int endOfSection, int startOfNext) { |
|
245 AssertionError a = null; |
|
246 a = collectErrors(a, () -> assertEquals( |
|
247 pos.endOfFirstLine, endOfFirstLine + offset, "endOfFirstLine")); |
|
248 a = collectErrors(a, () -> assertEquals( |
|
249 pos.endOfSection, endOfSection + offset, "endOfSection")); |
|
250 a = collectErrors(a, () -> assertEquals( |
|
251 pos.startOfNext, startOfNext + offset, "startOfNext")); |
|
252 if (a != null) throw a; |
|
253 } |
|
254 |
|
255 void catchCrCausesIndexOutOfBoundsException( |
|
256 Callable<Position> test, Consumer<Position> asserts) { |
|
257 try { |
|
258 Position x = test.call(); |
|
259 if (!FIXED_8217375) fail(); |
|
260 asserts.accept(x); |
|
261 } catch (Exception e) { |
|
262 if (e instanceof IndexOutOfBoundsException || |
|
263 e.getCause() instanceof IndexOutOfBoundsException) { |
|
264 if (FIXED_8217375) throw new AssertionError(e); |
|
265 } else { |
|
266 throw new AssertionError(e); |
|
267 } |
|
268 } |
|
269 } |
|
270 |
|
271 @Test |
|
272 public void testEmpty() throws Exception { |
|
273 assertNull(findSection("")); |
|
274 } |
|
275 |
|
276 @Test |
|
277 public void testOneLineBreakCr() throws Exception { |
|
278 catchCrCausesIndexOutOfBoundsException( |
|
279 () -> findSection("\r"), |
|
280 p -> assertPosition(p, |
|
281 -1, actualEndOfSection8217375(-1, false, 1), 1) |
|
282 ); |
|
283 } |
|
284 |
|
285 @Test |
|
286 public void testOneLineBreakLf() throws Exception { |
|
287 assertPosition(findSection("\n"), |
|
288 -1, actualEndOfSection8217375(-1, false, 1), 1); |
|
289 } |
|
290 |
|
291 @Test |
|
292 public void testOneLineBreakCrLf() throws Exception { |
|
293 assertPosition(findSection("\r\n"), |
|
294 actualEndOfFirstLine8217375(-1), |
|
295 actualEndOfSection8217375(-1, true, 2), |
|
296 2); |
|
297 } |
|
298 |
|
299 @Test |
|
300 public void testSpaceAndLineBreakCr() throws Exception { |
|
301 catchCrCausesIndexOutOfBoundsException( |
|
302 () -> findSection(" \r"), |
|
303 p -> assertPosition(p, 2, 3, 4) |
|
304 ); |
|
305 } |
|
306 |
|
307 @Test |
|
308 public void testSpaceAndOneLineBreakLf() throws Exception { |
|
309 assertPosition(findSection(" \n"), 2, 3, 4); |
|
310 } |
|
311 |
|
312 @Test |
|
313 public void testSpaceAndOneLineBreakCrLf() throws Exception { |
|
314 assertPosition(findSection(" \r\n"), 2, 4, 5); |
|
315 } |
|
316 |
|
317 @Test |
|
318 public void testOneLineBreakCrAndSpace() throws Exception { |
|
319 assertPosition(findSection("\r "), |
|
320 -1, actualEndOfSection8217375(-1, false, 1), 1); |
|
321 } |
|
322 |
|
323 @Test |
|
324 public void testOneLineBreakLfAndSpace() throws Exception { |
|
325 assertPosition(findSection("\n "), |
|
326 -1, actualEndOfSection8217375(-1, false, 1), 1); |
|
327 } |
|
328 |
|
329 @Test |
|
330 public void testOneLineBreakCrLfAndSpace() throws Exception { |
|
331 assertPosition(findSection("\r\n "), |
|
332 actualEndOfFirstLine8217375(-1), |
|
333 actualEndOfSection8217375(-1, false, 1), |
|
334 2); |
|
335 } |
|
336 |
|
337 @Test |
|
338 public void testCrEof() throws Exception { |
|
339 catchCrCausesIndexOutOfBoundsException( |
|
340 () -> findSection("abc\r"), |
|
341 p -> assertPosition(p, 2, 3, 4) |
|
342 ); |
|
343 } |
|
344 |
|
345 @Test |
|
346 public void testLfEof() throws Exception { |
|
347 assertPosition(findSection("abc\n"), 2, 3, 4); |
|
348 } |
|
349 |
|
350 @Test |
|
351 public void testCrLfEof() throws Exception { |
|
352 assertPosition(findSection("abc\r\n"), 2, 4, 5); |
|
353 } |
|
354 |
|
355 @Test |
|
356 public void testCrContinued() throws Exception { |
|
357 assertPosition(findSection("abc\rxyz\r\n\r\n "), 2, 8, 11); |
|
358 } |
|
359 |
|
360 @Test |
|
361 public void testLfContinued() throws Exception { |
|
362 assertPosition(findSection("abc\nxyz\r\n\r\n "), 2, 8, 11); |
|
363 } |
|
364 |
|
365 @Test |
|
366 public void testCrLfContinued() throws Exception { |
|
367 assertPosition(findSection("abc\r\nxyz\r\n\r\n "), 2, 9, 12); |
|
368 } |
|
369 |
|
370 @Test |
|
371 public void testCrCrEof() throws Exception { |
|
372 catchCrCausesIndexOutOfBoundsException( |
|
373 () -> findSection("abc\r\nxyz\r\r"), |
|
374 p -> assertPosition(p, |
|
375 2, actualEndOfSection8217375(8, true, 1), 10) |
|
376 ); |
|
377 } |
|
378 |
|
379 @Test |
|
380 public void testCrCrContinued() throws Exception { |
|
381 assertPosition(findSection("abc\r\nxyz\r\r "), 2, 8, 10); |
|
382 } |
|
383 |
|
384 @Test |
|
385 public void testLfLfEof() throws Exception { |
|
386 assertPosition(findSection("abc\r\nxyz\n\n"), |
|
387 2, actualEndOfSection8217375(8, true, 1), 10); |
|
388 } |
|
389 |
|
390 @Test |
|
391 public void testLfLfContinued() throws Exception { |
|
392 assertPosition(findSection("abc\r\nxyz\n\n "), 2, 8, 10); |
|
393 } |
|
394 |
|
395 @Test |
|
396 public void testCrLfEof2() throws Exception { |
|
397 assertPosition(findSection("abc\r\nxyz\r\n"), 2, 9, 10); |
|
398 } |
|
399 |
|
400 @Test |
|
401 public void testMainSectionNotTerminatedWithLineBreak() throws Exception { |
|
402 assertNull(findSection("abc\r\nxyz\r\n ")); |
|
403 } |
|
404 |
|
405 @Test |
|
406 public void testLfCrEof() throws Exception { |
|
407 catchCrCausesIndexOutOfBoundsException( |
|
408 () -> findSection("abc\r\nxyz\n\r"), |
|
409 p -> assertPosition(p, |
|
410 2, actualEndOfSection8217375(8, true, 1), 10) |
|
411 ); |
|
412 } |
|
413 |
|
414 @Test |
|
415 public void testLfCrContinued() throws Exception { |
|
416 assertPosition(findSection("abc\r\nxyz\n\r "), 2, 8, 10); |
|
417 } |
|
418 |
|
419 @Test |
|
420 public void testCrLfCrEof() throws Exception { |
|
421 catchCrCausesIndexOutOfBoundsException( |
|
422 () -> findSection("abc\r\nxyz\r\n\r"), |
|
423 p -> assertPosition(p, |
|
424 2, actualEndOfSection8217375(9, true, 2), 11) |
|
425 ); |
|
426 } |
|
427 |
|
428 @Test |
|
429 public void testCrLfCrContinued() throws Exception { |
|
430 assertPosition(findSection("abc\r\nxyz\r\n\r "), 2, 9, 11); |
|
431 } |
|
432 |
|
433 @Test |
|
434 public void testCrLfLfEof() throws Exception { |
|
435 assertPosition(findSection("abc\r\nxyz\r\n\n"), |
|
436 2, actualEndOfSection8217375(9, true, 1), 11); |
|
437 } |
|
438 |
|
439 @Test |
|
440 public void testCrLfLfContinued() throws Exception { |
|
441 assertPosition(findSection("abc\r\nxyz\r\n\n "), 2, 9, 11); |
|
442 } |
|
443 |
|
444 @Test |
|
445 public void testCrLfCrLfEof() throws Exception { |
|
446 assertPosition(findSection("abc\r\nxyz\r\n\r\n"), |
|
447 2, actualEndOfSection8217375(9, true, 2), 12); |
|
448 } |
|
449 |
|
450 @Test |
|
451 public void testCrLfCfLfContinued() throws Exception { |
|
452 assertPosition(findSection("abc\r\nxyz\r\n\r\n "), 2, 9, 12); |
|
453 } |
|
454 |
|
455 @Test |
|
456 public void testCrLfCrCrEof() throws Exception { |
|
457 assertPosition(findSection("abc\r\nxyz\r\n\r\r"), 2, 9, 11); |
|
458 } |
|
459 |
|
460 @Test |
|
461 public void testCrLfCrCrContinued() throws Exception { |
|
462 assertPosition(findSection("abc\r\nxyz\r\n\r\r "), 2, 9, 11); |
|
463 } |
|
464 |
|
465 @Test |
|
466 public void testCrLfLfCrEof() throws Exception { |
|
467 assertPosition(findSection("abc\r\nxyz\r\n\n\r"), 2, 9, 11); |
|
468 } |
|
469 |
|
470 @Test |
|
471 public void testCrLfLfCrContinued() throws Exception { |
|
472 assertPosition(findSection("abc\r\nxyz\r\n\n\r "), 2, 9, 11); |
|
473 } |
|
474 |
|
475 @Test |
|
476 public void testCrLfCrLfCrEof() throws Exception { |
|
477 assertPosition(findSection("abc\r\nxyz\r\n\r\n\r"), 2, 9, 12); |
|
478 } |
|
479 |
|
480 @Test |
|
481 public void testCrLfCfLfCrContinued() throws Exception { |
|
482 assertPosition(findSection("abc\r\nxyz\r\n\r\n\r "), 2, 9, 12); |
|
483 } |
|
484 |
|
485 @Test |
|
486 public void testCrLfCrLfContinued() throws Exception { |
|
487 assertPosition(findSection("abc\r\nxyz\r\n\r\n "), 2, 9, 12); |
|
488 } |
|
489 |
|
490 @Test |
|
491 public void testCrLfLfLfEof() throws Exception { |
|
492 assertPosition(findSection("abc\r\nxyz\r\n\n\n"), 2, 9, 11); |
|
493 } |
|
494 |
|
495 @Test |
|
496 public void testCrLfLfLfContinued() throws Exception { |
|
497 assertPosition(findSection("abc\r\nxyz\r\n\n\n "), 2, 9, 11); |
|
498 } |
|
499 |
|
500 @Test |
|
501 public void testCrLfCrLfLfContinued() throws Exception { |
|
502 assertPosition(findSection("abc\r\nxyz\r\n\r\n\n "), 2, 9, 12); |
|
503 } |
|
504 |
|
505 @Test |
|
506 public void testCrLfCrCrLfEof() throws Exception { |
|
507 assertPosition(findSection("abc\r\nxyz\r\n\r\r\n"), 2, 9, 11); |
|
508 } |
|
509 |
|
510 @Test |
|
511 public void testCrLfCrCrLfContinued() throws Exception { |
|
512 assertPosition(findSection("abc\r\nxyz\r\n\r\r\n "), 2, 9, 11); |
|
513 } |
|
514 |
|
515 @Test |
|
516 public void testCrLfLfCrLfEof() throws Exception { |
|
517 assertPosition(findSection("abc\r\nxyz\r\n\n\r\n"), 2, 9, 11); |
|
518 } |
|
519 |
|
520 @Test |
|
521 public void testCrLfLfCrLfContinued() throws Exception { |
|
522 assertPosition(findSection("abc\r\nxyz\r\n\n\r\n "), 2, 9, 11); |
|
523 } |
|
524 |
|
525 @Test |
|
526 public void testCrLfCrLfCrLfEof() throws Exception { |
|
527 assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\n"), 2, 9, 12); |
|
528 } |
|
529 |
|
530 @Test |
|
531 public void testCrLfCfLfCrLfContinued() throws Exception { |
|
532 assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\n "), 2, 9, 12); |
|
533 } |
|
534 |
|
535 @Test |
|
536 public void testCrLfLfCrCrEof() throws Exception { |
|
537 assertPosition(findSection("abc\r\nxyz\r\n\n\r\r"), 2, 9, 11); |
|
538 } |
|
539 |
|
540 @Test |
|
541 public void testCrLfCrLfCrCrEof() throws Exception { |
|
542 assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\r"), 2, 9, 12); |
|
543 } |
|
544 |
|
545 @Test |
|
546 public void testCrLfCrLfCrContinued() throws Exception { |
|
547 assertPosition(findSection("abc\r\nxyz\r\n\r\n\r "), 2, 9, 12); |
|
548 } |
|
549 |
|
550 @Test |
|
551 public void testCrLfLfLfCrEof() throws Exception { |
|
552 assertPosition(findSection("abc\r\nxyz\r\n\n\n\r"), 2, 9, 11); |
|
553 } |
|
554 |
|
555 @Test |
|
556 public void testCrLfLfCrLfCrEof() throws Exception { |
|
557 assertPosition(findSection("abc\r\nxyz\r\n\n\r\n\r"), 2, 9, 11); |
|
558 } |
|
559 |
|
560 @Test |
|
561 public void testCrLfLfLfLfEof() throws Exception { |
|
562 assertPosition(findSection("abc\r\nxyz\r\n\n\n\n"), 2, 9, 11); |
|
563 } |
|
564 |
|
565 @Test |
|
566 public void testCrLfLfCrLfLfEof() throws Exception { |
|
567 assertPosition(findSection("abc\r\nxyz\r\n\n\r\n\n"), 2, 9, 11); |
|
568 } |
|
569 |
|
570 @Test |
|
571 public void testCrLfLfCrCrLfEof() throws Exception { |
|
572 assertPosition(findSection("abc\r\nxyz\r\n\n\r\r\n"), 2, 9, 11); |
|
573 } |
|
574 |
|
575 @Test |
|
576 public void testCrLfCrLfCrCrLfEof() throws Exception { |
|
577 assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\r\n"), 2, 9, 12); |
|
578 } |
|
579 |
|
580 @Test |
|
581 public void testCrLfCrLfCrLfContinued() throws Exception { |
|
582 assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\n "), 2, 9, 12); |
|
583 } |
|
584 |
|
585 @Test |
|
586 public void testCrLfLfLfCrLfEof() throws Exception { |
|
587 assertPosition(findSection("abc\r\nxyz\r\n\n\n\r\n"), 2, 9, 11); |
|
588 } |
|
589 |
|
590 @Test |
|
591 public void testCrLfLfCrLfCrLfEof() throws Exception { |
|
592 assertPosition(findSection("abc\r\nxyz\r\n\n\r\n\r\n"), 2, 9, 11); |
|
593 } |
|
594 |
|
595 @Test |
|
596 public void testCrLfCrCrLfCrCrEof() throws Exception { |
|
597 assertPosition(findSection("abc\r\nxyz\r\n\r\r\n\r"), 2, 9, 11); |
|
598 } |
|
599 |
|
600 @Test |
|
601 public void testCrLfCrCrCrCrEof() throws Exception { |
|
602 assertPosition(findSection("abc\r\nxyz\r\n\r\r\r"), 2, 9, 11); |
|
603 } |
|
604 |
|
605 @Test |
|
606 public void testCrLfCrCrLfLfEof() throws Exception { |
|
607 assertPosition(findSection("abc\r\nxyz\r\n\r\r\n\n"), 2, 9, 11); |
|
608 } |
|
609 |
|
610 @Test |
|
611 public void testCrLfCrCrLfCrLfEof() throws Exception { |
|
612 assertPosition(findSection("abc\r\nxyz\r\n\r\r\n\r\n"), 2, 9, 11); |
|
613 } |
|
614 |
|
615 @Test |
|
616 public void testCrLfCrCrCrLfEof() throws Exception { |
|
617 assertPosition(findSection("abc\r\nxyz\r\n\r\r\r\n"), 2, 9, 11); |
|
618 } |
|
619 |
|
620 /* |
|
621 * endOfFirstLine is the same regardless of the line break delimiter |
|
622 */ |
|
623 @Test |
|
624 public void testEndOfFirstLineVsLineBreak() throws Exception { |
|
625 for (String lb : new String[] { "\r", "\n", "\r\n" }) { |
|
626 Position p = findSection("abc" + lb + "xyz" + lb + lb + " "); |
|
627 |
|
628 // main assertion showing endOfFirstLine independent of line break |
|
629 assertEquals(p.endOfFirstLine, 2 + offset); |
|
630 |
|
631 // assert remaining positions as well just for completeness |
|
632 assertPosition(p, 2, 5 + 2 * lb.length(), 6 + 3 * lb.length()); |
|
633 } |
|
634 } |
|
635 |
|
636 /* |
|
637 * '\r' at the end of the bytes causes index out of bounds exception |
|
638 */ |
|
639 @Test |
|
640 public void testCrLastCausesIndexOutOfBounds() throws Exception { |
|
641 catchCrCausesIndexOutOfBoundsException( |
|
642 () -> findSection("\r"), |
|
643 p -> assertPosition(p, |
|
644 -1, actualEndOfSection8217375(-1, true, 1), 1) |
|
645 ); |
|
646 } |
|
647 |
|
648 /* |
|
649 * endOfSection includes second line break if at end of bytes only |
|
650 */ |
|
651 @Test |
|
652 public void testEndOfSectionWithLineBreakVsEof() throws Exception { |
|
653 AssertionError errors = new AssertionError("offset = " + offset); |
|
654 for (String lb : new String[] { "\r", "\n", "\r\n" }) { |
|
655 for (boolean eof : new boolean[] { false, true }) { |
|
656 Position p; |
|
657 try { |
|
658 p = findSection("abc" + lb + lb + (eof ? "" : "xyz")); |
|
659 } catch (RuntimeException | ReflectiveOperationException e) { |
|
660 if ((e instanceof IndexOutOfBoundsException || |
|
661 e.getCause() instanceof IndexOutOfBoundsException) |
|
662 && eof && "\r".equals(lb) && !FIXED_8217375) continue; |
|
663 throw e; |
|
664 } |
|
665 |
|
666 AssertionError a = new AssertionError("offset = " + offset |
|
667 + ", lb = " + Utils.escapeStringWithNumbers(lb) + ", " |
|
668 + "eof = " + eof); |
|
669 |
|
670 // main assertion showing endOfSection including second line |
|
671 // break when at end of file |
|
672 a = collectErrors(a, () -> assertEquals( |
|
673 p.endOfSection, |
|
674 actualEndOfSection8217375( |
|
675 2 + lb.length() + offset, eof, lb.length()) )); |
|
676 |
|
677 // assert remaining positions as well just for completeness |
|
678 a = collectErrors(a, () -> assertPosition(p, |
|
679 2, |
|
680 actualEndOfSection8217375( |
|
681 2 + lb.length(), eof, lb.length()), |
|
682 3 + lb.length() * 2)); |
|
683 |
|
684 if (a.getSuppressed().length > 0) errors.addSuppressed(a); |
|
685 } |
|
686 } |
|
687 if (errors.getSuppressed().length > 0) throw errors; |
|
688 } |
|
689 |
|
690 /* |
|
691 * returns position even if only one line break before end of bytes. |
|
692 * because no name will be found the result will be skipped and no entry |
|
693 * will be created. |
|
694 */ |
|
695 @Test |
|
696 public void testReturnPosVsEof() throws Exception { |
|
697 for (String lb : new String[] { "\r", "\n", "\r\n" }) { |
|
698 for (boolean eof : new boolean[] { false, true }) { |
|
699 try { |
|
700 Position p = findSection("abc" + lb + (eof ? "" : "xyz")); |
|
701 assertTrue(p != null == eof); |
|
702 } catch (RuntimeException | ReflectiveOperationException e) { |
|
703 if ((e instanceof IndexOutOfBoundsException || |
|
704 e.getCause() instanceof IndexOutOfBoundsException) |
|
705 && eof && "\r".equals(lb) && !FIXED_8217375) continue; |
|
706 throw e; |
|
707 } |
|
708 } |
|
709 } |
|
710 } |
|
711 |
|
712 /* |
|
713 * it could be normally be expected that startOfNext would point to the |
|
714 * start of the next section after a blank line but that is not the case |
|
715 * if a section ends with only one line break and no blank line immediately |
|
716 * before eof of the manifest. |
|
717 * such an entry will be digested without the trailing blank line which is |
|
718 * only fine until another section should be added afterwards. |
|
719 */ |
|
720 @Test |
|
721 public void testStartOfNextPointsToEofWithNoBlankLine() throws Exception { |
|
722 for (String lb : new String[] { "\r", "\n", "\r\n" }) { |
|
723 for (boolean blank : new boolean[] { false, true }) { |
|
724 String manifest = "abc" + lb + "xyz" + lb + (blank ? lb : ""); |
|
725 try { |
|
726 Position p = findSection(manifest); |
|
727 |
|
728 // assert that startOfNext points to eof in all cases |
|
729 // whether with or without a blank line before eof |
|
730 assertEquals(p.startOfNext, manifest.length() + offset); |
|
731 |
|
732 // assert remaining positions as well just for completeness |
|
733 assertPosition(p, |
|
734 2, |
|
735 actualEndOfSection8217375( |
|
736 5 + lb.length() * 2, |
|
737 true, |
|
738 blank ? lb.length() : 0), |
|
739 manifest.length()); |
|
740 } catch (RuntimeException | ReflectiveOperationException e) { |
|
741 if ((e instanceof IndexOutOfBoundsException || |
|
742 e.getCause() instanceof IndexOutOfBoundsException) |
|
743 && "\r".equals(lb) && !FIXED_8217375) continue; |
|
744 throw e; |
|
745 } |
|
746 } |
|
747 } |
|
748 } |
|
749 |
|
750 } |