1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package io.earcam.instrumental.module.auto;
20
21 import static io.earcam.instrumental.module.auto.Reader.reader;
22 import static java.nio.charset.StandardCharsets.UTF_8;
23 import static org.hamcrest.MatcherAssert.assertThat;
24 import static org.hamcrest.Matchers.*;
25 import static org.ops4j.pax.tinybundles.core.TinyBundles.bundle;
26
27 import java.io.ByteArrayInputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.UncheckedIOException;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Comparator;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Objects;
39 import java.util.Set;
40 import java.util.function.BiConsumer;
41 import java.util.jar.Manifest;
42
43 import org.hamcrest.Matchers;
44 import org.hamcrest.core.IsAnything;
45 import org.junit.jupiter.api.Nested;
46 import org.junit.jupiter.api.Test;
47 import org.objectweb.asm.Label;
48 import org.objectweb.asm.signature.SignatureReader;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import io.earcam.acme.AcmeAnnotation;
53 import io.earcam.acme.Annotated;
54 import io.earcam.acme.ImportsSlf4jApi;
55 import io.earcam.instrumental.module.auto.Reader;
56 import io.earcam.instrumental.reflect.Resources;
57 import io.earcam.utilitarian.charstar.CharSequences;
58
59 @SuppressWarnings("squid:S2187")
60 public class ReaderTest {
61
62
63 private static String cn(Class<?> type)
64 {
65 return type.getCanonicalName();
66 }
67
68
69 private static String pkg(Class<?> type)
70 {
71 return type.getPackage().getName();
72 }
73
74
75 @Nested
76 class Annotations {
77
78 @Test
79 void readsAnnotationsAndTheirValuesByDefault()
80 {
81
82
83 Map<String, Set<String>> imports = new HashMap<>();
84
85 reader()
86 .addImportListener(imports::put)
87 .processClass(Resources.classAsBytes(Annotated.class));
88
89 assertThat(imports, is(aMapWithSize(1)));
90
91 assertThat(imports, hasEntry(equalTo(cn(Annotated.class)),
92 containsInAnyOrder(
93 cn(Object.class),
94 cn(Comparable.class),
95 cn(Class.class),
96 cn(Throwable.class),
97 cn(OutOfMemoryError.class),
98 cn(Integer.class),
99
100 cn(AcmeAnnotation.class),
101
102 cn(CharSequences.class),
103 cn(Test.class),
104 cn(Label.class),
105 cn(SignatureReader.class),
106 cn(IllegalStateException.class),
107 cn(Matchers.class),
108 cn(IsAnything.class),
109 cn(Comparator.class),
110 cn(Objects.class),
111 cn(UncheckedIOException.class))));
112
113
114 }
115
116
117 @Test
118 void readingAnnotationsAndTheirValuesCanBeDisabled()
119 {
120 Map<String, Set<String>> imports = new HashMap<>();
121
122
123 reader()
124 .ignoreAnnotations()
125 .addImportListener(imports::put)
126 .processClass(Resources.classAsBytes(Annotated.class));
127
128 assertThat(imports, is(aMapWithSize(1)));
129
130 assertThat(imports, hasEntry(equalTo(cn(Annotated.class)), containsInAnyOrder(
131 cn(Object.class),
132 cn(Comparable.class),
133 cn(Class.class),
134 cn(Throwable.class),
135 cn(OutOfMemoryError.class),
136 cn(Integer.class))));
137
138 }
139 }
140
141 @Nested
142 class FromClass {
143
144 @Nested
145 class Simple {
146
147 @Test
148 void importListenerOnly() throws IOException
149 {
150
151 Map<String, Set<String>> imports = new HashMap<>();
152
153 reader()
154 .addImportListener(imports::put)
155 .processClass(Resources.classAsBytes(ImportsSlf4jApi.class));
156
157 assertThat(imports, is(aMapWithSize(1)));
158
159 assertThat(imports, hasEntry(equalTo(cn(ImportsSlf4jApi.class)), containsInAnyOrder(
160 cn(Arrays.class),
161 cn(Logger.class),
162 cn(LoggerFactory.class),
163 cn(Object.class),
164 cn(Class.class),
165 cn(StringBuilder.class),
166 cn(String.class))));
167
168 }
169
170 }
171 }
172
173 @Nested
174 class FromJar {
175
176 @Nested
177 class Simple {
178
179 @Test
180 void importListenerOnly() throws IOException
181 {
182 Map<String, Set<String>> imports = new HashMap<>();
183
184 InputStream jar = bundle()
185 .add(ImportsSlf4jApi.class)
186 .add("irrelevant/file.txt", new ByteArrayInputStream("hello".getBytes(UTF_8)))
187 .build();
188
189 reader()
190 .addImportListener(imports::put)
191 .processJar(jar);
192
193 assertThat(imports, is(aMapWithSize(1)));
194
195 assertThat(imports, hasEntry(equalTo(cn(ImportsSlf4jApi.class)), containsInAnyOrder(
196 cn(Arrays.class),
197 cn(Logger.class),
198 cn(LoggerFactory.class),
199 cn(Object.class),
200 cn(Class.class),
201 cn(StringBuilder.class),
202 cn(String.class))));
203 }
204
205
206 @Test
207 void manifestListenerOnly() throws IOException
208 {
209 InputStream jar = bundle()
210 .add(ImportsSlf4jApi.class)
211 .add("irrelevant/file.txt", new ByteArrayInputStream("hello".getBytes(UTF_8)))
212 .build();
213
214 List<Manifest> manifests = new ArrayList<>();
215
216 reader()
217 .addManifestListener(manifests::add)
218 .processJar(jar);
219
220 assertThat(manifests, hasSize(1));
221 }
222
223
224 @Test
225 void additionalBytecodeListener() throws IOException
226 {
227 InputStream jar = bundle()
228 .add(ImportsSlf4jApi.class)
229 .add("irrelevant/file.txt", new ByteArrayInputStream("hello".getBytes(UTF_8)))
230 .build();
231
232 Map<String, Set<String>> imports = new HashMap<>();
233 List<byte[]> listener = new ArrayList<>();
234
235 reader()
236 .addImportListener(imports::put)
237 .addByteCodeListener(listener::add)
238 .processJar(jar);
239
240 assertThat(listener, hasSize(1));
241 }
242
243
244 @Test
245 void listenerAndTypeReducers() throws IOException
246 {
247
248 Map<String, Set<String>> imports = new HashMap<>();
249
250 InputStream jar = bundle()
251 .add(ImportsSlf4jApi.class)
252 .add("irrelevant/file.txt", new ByteArrayInputStream("hello".getBytes(UTF_8)))
253 .build();
254
255 BiConsumer<String, Set<String>> listener = imports::put;
256
257 reader()
258 .addImportListener(listener)
259 .setImportedTypeReducer(Reader::typeToPackageReducer)
260 .setImportingTypeReducer(Reader::typeToPackageReducer)
261 .processJar(jar);
262
263 assertThat(imports, is(aMapWithSize(1)));
264
265 Set<String> expected = new HashSet<>(Arrays.asList(
266 pkg(Arrays.class),
267 pkg(Logger.class),
268 pkg(LoggerFactory.class),
269 pkg(Object.class),
270 pkg(Class.class),
271 pkg(StringBuilder.class),
272 pkg(String.class)));
273
274 assertThat(imports, hasEntry(equalTo(pkg(ImportsSlf4jApi.class)), equalTo(expected)));
275
276 }
277 }
278 }
279 }