1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.shade;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.OutputStream;
29 import java.lang.reflect.Field;
30 import java.net.URL;
31 import java.net.URLClassLoader;
32 import java.nio.charset.StandardCharsets;
33 import java.nio.file.Files;
34 import java.nio.file.Paths;
35 import java.nio.file.attribute.FileTime;
36 import java.time.temporal.ChronoUnit;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collections;
40 import java.util.Enumeration;
41 import java.util.LinkedHashSet;
42 import java.util.List;
43 import java.util.Set;
44 import java.util.jar.JarEntry;
45 import java.util.jar.JarFile;
46 import java.util.jar.JarInputStream;
47 import java.util.jar.JarOutputStream;
48 import java.util.stream.Collectors;
49 import java.util.zip.CRC32;
50 import java.util.zip.ZipEntry;
51
52 import org.apache.maven.plugin.MojoExecutionException;
53 import org.apache.maven.plugins.shade.filter.Filter;
54 import org.apache.maven.plugins.shade.relocation.Relocator;
55 import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
56 import org.apache.maven.plugins.shade.resource.AppendingTransformer;
57 import org.apache.maven.plugins.shade.resource.ComponentsXmlResourceTransformer;
58 import org.apache.maven.plugins.shade.resource.ResourceTransformer;
59 import org.apache.maven.plugins.shade.resource.ServicesResourceTransformer;
60 import org.codehaus.plexus.util.IOUtil;
61 import org.codehaus.plexus.util.Os;
62 import org.junit.Assert;
63 import org.junit.ClassRule;
64 import org.junit.Test;
65 import org.junit.rules.TemporaryFolder;
66 import org.mockito.ArgumentCaptor;
67 import org.objectweb.asm.ClassReader;
68 import org.objectweb.asm.ClassVisitor;
69 import org.objectweb.asm.Opcodes;
70 import org.slf4j.Logger;
71
72 import static java.util.Arrays.asList;
73 import static java.util.Collections.singleton;
74 import static java.util.Objects.requireNonNull;
75 import static org.codehaus.plexus.util.FileUtils.forceMkdir;
76 import static org.hamcrest.CoreMatchers.containsString;
77 import static org.hamcrest.CoreMatchers.hasItem;
78 import static org.hamcrest.CoreMatchers.hasItems;
79 import static org.hamcrest.CoreMatchers.is;
80 import static org.hamcrest.MatcherAssert.assertThat;
81 import static org.junit.Assert.assertEquals;
82 import static org.junit.Assert.assertFalse;
83 import static org.junit.Assert.assertTrue;
84 import static org.mockito.Mockito.doNothing;
85 import static org.mockito.Mockito.mock;
86 import static org.mockito.Mockito.when;
87
88
89
90
91
92 public class DefaultShaderTest {
93 private static final String[] EXCLUDES =
94 new String[] {"org/codehaus/plexus/util/xml/Xpp3Dom", "org/codehaus/plexus/util/xml/pull.*"};
95
96 @ClassRule
97 public static final TemporaryFolder TEMPORARY_FOLDER = new TemporaryFolder();
98
99 private static final String NEWLINE = "\n";
100
101 @Test
102 public void testNoopWhenNotRelocated() throws IOException, MojoExecutionException {
103 File plexusJar = new File("src/test/jars/plexus-utils-1.4.1.jar");
104 File shadedOutput = new File("target/foo-custom_testNoopWhenNotRelocated.jar");
105
106 Set<File> jars = new LinkedHashSet<>();
107 jars.add(new File("src/test/jars/test-project-1.0-SNAPSHOT.jar"));
108 jars.add(plexusJar);
109
110 Relocator relocator = new SimpleRelocator(
111 "org/codehaus/plexus/util/cli",
112 "relocated/plexus/util/cli",
113 Collections.emptyList(),
114 Collections.emptyList());
115
116 ShadeRequest shadeRequest = new ShadeRequest();
117 shadeRequest.setJars(jars);
118 shadeRequest.setRelocators(Collections.singletonList(relocator));
119 shadeRequest.setResourceTransformers(Collections.emptyList());
120 shadeRequest.setFilters(Collections.emptyList());
121 shadeRequest.setUberJar(shadedOutput);
122
123 DefaultShader shader = newShader();
124 shader.shade(shadeRequest);
125
126 try (JarFile originalJar = new JarFile(plexusJar);
127 JarFile shadedJar = new JarFile(shadedOutput)) {
128
129
130
131
132
133 assertTrue(areEqual(originalJar, shadedJar, "org/codehaus/plexus/util/Expand.class"));
134
135
136
137
138 assertFalse(areEqual(
139 originalJar,
140 shadedJar,
141 "org/codehaus/plexus/util/cli/Arg.class",
142 "relocated/plexus/util/cli/Arg.class"));
143 }
144 int result = 0;
145 for (String msg : debugMessages.getAllValues()) {
146 if ("Rewrote class bytecode: org/codehaus/plexus/util/cli/Arg.class".equals(msg)) {
147 result |= 1;
148 } else if ("Keeping original class bytecode: org/codehaus/plexus/util/Expand.class".equals(msg)) {
149 result |= 2;
150 }
151 }
152 assertEquals(3 , result);
153 }
154
155 @Test
156 public void testOverlappingResourcesAreLogged() throws IOException, MojoExecutionException {
157 DefaultShader shader = newShader();
158
159
160
161 Set<File> set = new LinkedHashSet<>();
162 set.add(new File("src/test/jars/test-project-1.0-SNAPSHOT.jar"));
163 set.add(new File("src/test/jars/plexus-utils-1.4.1.jar"));
164
165 ShadeRequest shadeRequest = new ShadeRequest();
166 shadeRequest.setJars(set);
167 shadeRequest.setRelocators(Collections.<Relocator>emptyList());
168 shadeRequest.setResourceTransformers(Collections.<ResourceTransformer>emptyList());
169 shadeRequest.setFilters(Collections.<Filter>emptyList());
170 shadeRequest.setUberJar(new File("target/foo-custom_testOverlappingResourcesAreLogged.jar"));
171 shader.shade(shadeRequest);
172
173 assertThat(
174 warnMessages.getAllValues(),
175 hasItem(containsString(
176 "plexus-utils-1.4.1.jar, test-project-1.0-SNAPSHOT.jar define 1 overlapping resource:")));
177 assertThat(warnMessages.getAllValues(), hasItem(containsString("- META-INF/MANIFEST.MF")));
178 if (Os.isFamily(Os.FAMILY_WINDOWS)) {
179 assertThat(
180 debugMessages.getAllValues(),
181 hasItem(containsString(
182 "We have a duplicate META-INF/MANIFEST.MF in src\\test\\jars\\plexus-utils-1.4.1.jar")));
183 } else {
184 assertThat(
185 debugMessages.getAllValues(),
186 hasItem(containsString(
187 "We have a duplicate META-INF/MANIFEST.MF in src/test/jars/plexus-utils-1.4.1.jar")));
188 }
189 }
190
191 @Test
192 public void testOverlappingResourcesAreLoggedExceptATransformerHandlesIt() throws Exception {
193 TemporaryFolder temporaryFolder = new TemporaryFolder();
194 try {
195 Set<File> set = new LinkedHashSet<>();
196 temporaryFolder.create();
197 File j1 = temporaryFolder.newFile("j1.jar");
198 try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(j1))) {
199 jos.putNextEntry(new JarEntry("foo.txt"));
200 jos.write("c1".getBytes(StandardCharsets.UTF_8));
201 jos.closeEntry();
202 }
203 File j2 = temporaryFolder.newFile("j2.jar");
204 try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(j2))) {
205 jos.putNextEntry(new JarEntry("foo.txt"));
206 jos.write("c2".getBytes(StandardCharsets.UTF_8));
207 jos.closeEntry();
208 }
209 set.add(j1);
210 set.add(j2);
211
212 AppendingTransformer transformer = new AppendingTransformer();
213 Field resource = AppendingTransformer.class.getDeclaredField("resource");
214 resource.setAccessible(true);
215 resource.set(transformer, "foo.txt");
216
217 ShadeRequest shadeRequest = new ShadeRequest();
218 shadeRequest.setJars(set);
219 shadeRequest.setRelocators(Collections.emptyList());
220 shadeRequest.setResourceTransformers(Collections.singletonList(transformer));
221 shadeRequest.setFilters(Collections.emptyList());
222 shadeRequest.setUberJar(new File("target/foo-custom_testOverlappingResourcesAreLogged.jar"));
223
224 DefaultShader shaderWithTransformer = newShader();
225 shaderWithTransformer.shade(shadeRequest);
226
227 assertThat(warnMessages.getAllValues().size(), is(0));
228
229 DefaultShader shaderWithoutTransformer = newShader();
230 shadeRequest.setResourceTransformers(Collections.emptyList());
231 shaderWithoutTransformer.shade(shadeRequest);
232
233 assertThat(
234 warnMessages.getAllValues(),
235 hasItems(containsString("j1.jar, j2.jar define 1 overlapping resource:")));
236 assertThat(warnMessages.getAllValues(), hasItems(containsString("- foo.txt")));
237 } finally {
238 temporaryFolder.delete();
239 }
240 }
241
242 @Test
243 public void testShaderWithDefaultShadedPattern() throws Exception {
244 shaderWithPattern(null, new File("target/foo-default.jar"), EXCLUDES);
245 }
246
247 @Test
248 public void testShaderWithStaticInitializedClass() throws Exception {
249 Shader s = newShader();
250
251 Set<File> set = new LinkedHashSet<>();
252
253 set.add(new File("src/test/jars/test-artifact-1.0-SNAPSHOT.jar"));
254
255 List<Relocator> relocators = new ArrayList<>();
256
257 relocators.add(new SimpleRelocator("org.apache.maven.plugins.shade", null, null, null));
258
259 List<ResourceTransformer> resourceTransformers = new ArrayList<>();
260
261 List<Filter> filters = new ArrayList<>();
262
263 File file = new File("target/testShaderWithStaticInitializedClass.jar");
264
265 ShadeRequest shadeRequest = new ShadeRequest();
266 shadeRequest.setJars(set);
267 shadeRequest.setUberJar(file);
268 shadeRequest.setFilters(filters);
269 shadeRequest.setRelocators(relocators);
270 shadeRequest.setResourceTransformers(resourceTransformers);
271
272 s.shade(shadeRequest);
273
274 try (URLClassLoader cl = new URLClassLoader(new URL[] {file.toURI().toURL()})) {
275 Class<?> c = cl.loadClass("hidden.org.apache.maven.plugins.shade.Lib");
276 Object o = c.newInstance();
277 assertEquals("foo.bar/baz", c.getDeclaredField("CONSTANT").get(o));
278 }
279 }
280
281 @Test
282 public void testShaderWithCustomShadedPattern() throws Exception {
283 shaderWithPattern("org/shaded/plexus/util", new File("target/foo-custom.jar"), EXCLUDES);
284 }
285
286 @Test
287 public void testShaderWithoutExcludesShouldRemoveReferencesOfOriginalPattern() throws Exception {
288
289
290 shaderWithPattern(
291 "org/shaded/plexus/util", new File("target/foo-custom-without-excludes.jar"), new String[] {});
292 }
293
294 @Test
295 public void testHandleDirectory() throws Exception {
296 final File dir = TEMPORARY_FOLDER.getRoot();
297
298 try (JarInputStream in =
299 new JarInputStream(Files.newInputStream(Paths.get("src/test/jars/test-artifact-1.0-SNAPSHOT.jar")))) {
300 JarEntry nextJarEntry;
301 while ((nextJarEntry = in.getNextJarEntry()) != null) {
302 if (nextJarEntry.isDirectory()) {
303 continue;
304 }
305 File out = new File(dir, nextJarEntry.getName());
306 forceMkdir(out.getParentFile());
307 try (OutputStream outputStream = Files.newOutputStream(out.toPath())) {
308 IOUtil.copy(in, outputStream, (int) Math.max(nextJarEntry.getSize(), 512));
309 }
310 }
311 }
312
313
314 File shade = new File("target/testHandleDirectory.jar");
315 shaderWithPattern("org/shaded/plexus/util", shade, new String[0], singleton(dir));
316
317
318 try (JarFile jar = new JarFile(shade)) {
319 List<String> entries = new ArrayList<>();
320 Enumeration<JarEntry> jarEntryEnumeration = jar.entries();
321 while (jarEntryEnumeration.hasMoreElements()) {
322 JarEntry jarEntry = jarEntryEnumeration.nextElement();
323 if (jarEntry.isDirectory()) {
324 continue;
325 }
326 entries.add(jarEntry.getName());
327 }
328 Collections.sort(entries);
329 assertEquals(
330 asList(
331 "META-INF/maven/org.apache.maven.plugins.shade/test-artifact/pom.properties",
332 "META-INF/maven/org.apache.maven.plugins.shade/test-artifact/pom.xml",
333 "org/apache/maven/plugins/shade/Lib.class"),
334 entries);
335 }
336 }
337
338 @Test
339 public void testShaderWithRelocatedClassname() throws Exception {
340 DefaultShader s = newShader();
341
342 Set<File> set = new LinkedHashSet<>();
343
344 set.add(new File("src/test/jars/test-project-1.0-SNAPSHOT.jar"));
345
346 set.add(new File("src/test/jars/plexus-utils-1.4.1.jar"));
347
348 List<Relocator> relocators = new ArrayList<>();
349
350 relocators.add(
351 new SimpleRelocator("org/codehaus/plexus/util/", "_plexus/util/__", null, Collections.emptyList()));
352
353 List<ResourceTransformer> resourceTransformers = new ArrayList<>();
354
355 resourceTransformers.add(new ComponentsXmlResourceTransformer());
356
357 List<Filter> filters = new ArrayList<>();
358
359 File file = new File("target/foo-relocate-class.jar");
360
361 ShadeRequest shadeRequest = new ShadeRequest();
362 shadeRequest.setJars(set);
363 shadeRequest.setUberJar(file);
364 shadeRequest.setFilters(filters);
365 shadeRequest.setRelocators(relocators);
366 shadeRequest.setResourceTransformers(resourceTransformers);
367
368 s.shade(shadeRequest);
369
370 try (URLClassLoader cl = new URLClassLoader(new URL[] {file.toURI().toURL()})) {
371 Class<?> c = cl.loadClass("_plexus.util.__StringUtils");
372
373 Object o = c.newInstance();
374 assertEquals("", c.getMethod("clean", String.class).invoke(o, (String) null));
375
376
377 String[] source = {null};
378 ClassReader classReader = new ClassReader(cl.getResourceAsStream("_plexus/util/__StringUtils.class"));
379 classReader.accept(
380 new ClassVisitor(Opcodes.ASM4) {
381 @Override
382 public void visitSource(String arg0, String arg1) {
383 super.visitSource(arg0, arg1);
384 source[0] = arg0;
385 }
386 },
387 ClassReader.SKIP_CODE);
388 assertEquals("__StringUtils.java", source[0]);
389 }
390 }
391
392 @Test
393 public void testShaderWithNestedJar() throws Exception {
394 TemporaryFolder temporaryFolder = new TemporaryFolder();
395
396 final String innerJarFileName = "inner.jar";
397
398 temporaryFolder.create();
399 File innerJar = temporaryFolder.newFile(innerJarFileName);
400 try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(innerJar.toPath()))) {
401 jos.putNextEntry(new JarEntry("foo.txt"));
402 jos.write("c1".getBytes(StandardCharsets.UTF_8));
403 jos.closeEntry();
404 }
405
406 ShadeRequest shadeRequest = new ShadeRequest();
407 shadeRequest.setJars(new LinkedHashSet<>(Collections.singleton(innerJar)));
408 shadeRequest.setFilters(Collections.emptyList());
409 shadeRequest.setRelocators(Collections.emptyList());
410 shadeRequest.setResourceTransformers(Collections.emptyList());
411 File shadedFile = temporaryFolder.newFile("shaded.jar");
412 shadeRequest.setUberJar(shadedFile);
413
414 DefaultShader shader = newShader();
415 shader.shade(shadeRequest);
416
417 FileTime lastModified = FileTime.from(
418 Files.getLastModifiedTime(shadedFile.toPath()).toInstant().minus(5, ChronoUnit.SECONDS));
419
420 Files.setLastModifiedTime(shadedFile.toPath(), lastModified);
421
422 shader.shade(shadeRequest);
423 assertEquals(lastModified, Files.getLastModifiedTime(shadedFile.toPath()));
424
425 temporaryFolder.delete();
426 }
427
428 @Test
429 public void testShaderNoOverwrite() throws Exception {
430 TemporaryFolder temporaryFolder = new TemporaryFolder();
431
432 final String innerJarFileName = "inner.jar";
433
434 temporaryFolder.create();
435 File innerJar = temporaryFolder.newFile(innerJarFileName);
436 try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(innerJar))) {
437 jos.putNextEntry(new JarEntry("foo.txt"));
438 jos.write("c1".getBytes(StandardCharsets.UTF_8));
439 jos.closeEntry();
440 }
441
442 File outerJar = temporaryFolder.newFile("outer.jar");
443 try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(outerJar))) {
444 FileInputStream innerStream = new FileInputStream(innerJar);
445 byte[] bytes = IOUtil.toByteArray(innerStream, 32 * 1024);
446 innerStream.close();
447 writeEntryWithoutCompression(innerJarFileName, bytes, jos);
448 }
449
450 ShadeRequest shadeRequest = new ShadeRequest();
451 shadeRequest.setJars(new LinkedHashSet<>(Collections.singleton(outerJar)));
452 shadeRequest.setFilters(new ArrayList<>());
453 shadeRequest.setRelocators(new ArrayList<>());
454 shadeRequest.setResourceTransformers(new ArrayList<>());
455 File shadedFile = temporaryFolder.newFile("shaded.jar");
456 shadeRequest.setUberJar(shadedFile);
457
458 DefaultShader shader = newShader();
459 shader.shade(shadeRequest);
460
461 JarFile shadedJarFile = new JarFile(shadedFile);
462 JarEntry entry = shadedJarFile.getJarEntry(innerJarFileName);
463
464
465 Assert.assertEquals(entry.getMethod(), ZipEntry.STORED);
466
467 temporaryFolder.delete();
468 }
469
470 @Test
471 public void testShaderWithDuplicateService() throws Exception {
472 TemporaryFolder temporaryFolder = new TemporaryFolder();
473 temporaryFolder.create();
474
475 String serviceEntryName = "META-INF/services/my.foo.Service";
476 String serviceEntryValue = "my.foo.impl.Service1";
477
478 File innerJar1 = temporaryFolder.newFile("inner1.jar");
479 try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(innerJar1.toPath()))) {
480 jos.putNextEntry(new JarEntry(serviceEntryName));
481 jos.write((serviceEntryValue + NEWLINE).getBytes(StandardCharsets.UTF_8));
482 jos.closeEntry();
483 }
484
485 File innerJar2 = temporaryFolder.newFile("inner2.jar");
486 try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(innerJar2.toPath()))) {
487 jos.putNextEntry(new JarEntry(serviceEntryName));
488 jos.write((serviceEntryValue + NEWLINE).getBytes(StandardCharsets.UTF_8));
489 jos.closeEntry();
490 }
491
492 ShadeRequest shadeRequest = new ShadeRequest();
493 shadeRequest.setJars(new LinkedHashSet<>(Arrays.asList(innerJar1, innerJar2)));
494 shadeRequest.setFilters(Collections.emptyList());
495 shadeRequest.setRelocators(Collections.emptyList());
496 shadeRequest.setResourceTransformers(Collections.singletonList(new ServicesResourceTransformer()));
497 File shadedFile = temporaryFolder.newFile("shaded.jar");
498 shadeRequest.setUberJar(shadedFile);
499
500 DefaultShader shader = newShader();
501 shader.shade(shadeRequest);
502
503 JarFile shadedJarFile = new JarFile(shadedFile);
504 JarEntry entry = shadedJarFile.getJarEntry(serviceEntryName);
505
506 List<String> lines = new BufferedReader(
507 new InputStreamReader(shadedJarFile.getInputStream(entry), StandardCharsets.UTF_8))
508 .lines()
509 .collect(Collectors.toList());
510
511
512 Assert.assertEquals(Collections.singletonList(serviceEntryValue), lines);
513
514 temporaryFolder.delete();
515 }
516
517 @Test
518 public void testShaderWithSmallEntries() throws Exception {
519 TemporaryFolder temporaryFolder = new TemporaryFolder();
520
521 final String innerJarFileName = "inner.jar";
522 int len;
523
524 temporaryFolder.create();
525 File innerJar = temporaryFolder.newFile(innerJarFileName);
526 try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(innerJar.toPath()))) {
527 jos.putNextEntry(new JarEntry("foo.txt"));
528 byte[] bytes = "c1".getBytes(StandardCharsets.UTF_8);
529 len = bytes.length;
530 jos.write(bytes);
531 jos.closeEntry();
532 }
533
534 ShadeRequest shadeRequest = new ShadeRequest();
535 shadeRequest.setJars(new LinkedHashSet<>(Collections.singleton(innerJar)));
536 shadeRequest.setFilters(new ArrayList<>());
537 shadeRequest.setRelocators(new ArrayList<>());
538 shadeRequest.setResourceTransformers(new ArrayList<>());
539 File shadedFile = temporaryFolder.newFile("shaded.jar");
540 shadeRequest.setUberJar(shadedFile);
541
542 DefaultShader shader = newShader();
543 shader.shade(shadeRequest);
544
545 JarFile shadedJarFile = new JarFile(shadedFile);
546 JarEntry entry = shadedJarFile.getJarEntry("foo.txt");
547
548
549 Assert.assertEquals(entry.getSize(), len);
550
551 temporaryFolder.delete();
552 }
553
554 private void writeEntryWithoutCompression(String entryName, byte[] entryBytes, JarOutputStream jos)
555 throws IOException {
556 final JarEntry entry = new JarEntry(entryName);
557 final int size = entryBytes.length;
558 final CRC32 crc = new CRC32();
559 crc.update(entryBytes, 0, size);
560 entry.setSize(size);
561 entry.setCompressedSize(size);
562 entry.setMethod(ZipEntry.STORED);
563 entry.setCrc(crc.getValue());
564 jos.putNextEntry(entry);
565 jos.write(entryBytes);
566 jos.closeEntry();
567 }
568
569 private void shaderWithPattern(String shadedPattern, File jar, String[] excludes) throws Exception {
570 Set<File> set = new LinkedHashSet<>();
571 set.add(new File("src/test/jars/test-project-1.0-SNAPSHOT.jar"));
572 set.add(new File("src/test/jars/plexus-utils-1.4.1.jar"));
573 shaderWithPattern(shadedPattern, jar, excludes, set);
574 }
575
576 private void shaderWithPattern(String shadedPattern, File jar, String[] excludes, Set<File> set) throws Exception {
577 DefaultShader s = newShader();
578
579 List<Relocator> relocators = new ArrayList<>();
580
581 relocators.add(new SimpleRelocator("org/codehaus/plexus/util", shadedPattern, null, Arrays.asList(excludes)));
582
583 List<ResourceTransformer> resourceTransformers = new ArrayList<>();
584
585 resourceTransformers.add(new ComponentsXmlResourceTransformer());
586
587 List<Filter> filters = new ArrayList<>();
588
589 ShadeRequest shadeRequest = new ShadeRequest();
590 shadeRequest.setJars(set);
591 shadeRequest.setUberJar(jar);
592 shadeRequest.setFilters(filters);
593 shadeRequest.setRelocators(relocators);
594 shadeRequest.setResourceTransformers(resourceTransformers);
595
596 s.shade(shadeRequest);
597 }
598
599 private DefaultShader newShader() {
600 return new DefaultShader(mockLogger());
601 }
602
603 private ArgumentCaptor<String> debugMessages;
604
605 private ArgumentCaptor<String> warnMessages;
606
607 private Logger mockLogger() {
608 debugMessages = ArgumentCaptor.forClass(String.class);
609 warnMessages = ArgumentCaptor.forClass(String.class);
610 Logger logger = mock(Logger.class);
611 when(logger.isDebugEnabled()).thenReturn(true);
612 when(logger.isWarnEnabled()).thenReturn(true);
613 doNothing().when(logger).debug(debugMessages.capture());
614 doNothing().when(logger).warn(warnMessages.capture());
615 return logger;
616 }
617
618 private boolean areEqual(final JarFile jar1, final JarFile jar2, final String entry) throws IOException {
619 return areEqual(jar1, jar2, entry, entry);
620 }
621
622 private boolean areEqual(final JarFile jar1, final JarFile jar2, final String entry1, String entry2)
623 throws IOException {
624 try (InputStream s1 = jar1.getInputStream(
625 requireNonNull(jar1.getJarEntry(entry1), entry1 + " in " + jar1.getName()));
626 InputStream s2 = jar2.getInputStream(
627 requireNonNull(jar2.getJarEntry(entry2), entry2 + " in " + jar2.getName()))) {
628 return Arrays.equals(IOUtil.toByteArray(s1), IOUtil.toByteArray(s2));
629 }
630 }
631 }