Skip to content

Commit f051912

Browse files
authored
Add ModuleLocation tests (#302)
1 parent b07c6ca commit f051912

File tree

2 files changed

+307
-3
lines changed

2 files changed

+307
-3
lines changed

java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/helpers/Fixtures.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package io.github.ascopes.jct.tests.helpers;
1717

1818
import static io.github.ascopes.jct.tests.helpers.GenericMock.mockRaw;
19+
import static java.util.stream.Collectors.joining;
1920
import static org.mockito.ArgumentMatchers.any;
2021
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
2122
import static org.mockito.Mockito.mock;
@@ -38,13 +39,16 @@
3839
import java.nio.file.Files;
3940
import java.nio.file.Path;
4041
import java.time.Instant;
42+
import java.util.ArrayList;
4143
import java.util.Arrays;
4244
import java.util.Collection;
4345
import java.util.List;
4446
import java.util.Locale;
47+
import java.util.Objects;
4548
import java.util.Random;
4649
import java.util.UUID;
4750
import java.util.stream.Collectors;
51+
import java.util.stream.IntStream;
4852
import java.util.stream.Stream;
4953
import javax.annotation.processing.Processor;
5054
import javax.tools.Diagnostic;
@@ -141,7 +145,7 @@ public static String someLinesOfText() {
141145
.generate(UUID::randomUUID)
142146
.map(UUID::toString)
143147
.limit(someInt(5, 15))
144-
.collect(Collectors.joining("\n"));
148+
.collect(joining("\n"));
145149
}
146150

147151
/**
@@ -281,7 +285,7 @@ public static Throwable someUncheckedException() {
281285
.generate(UUID::randomUUID)
282286
.map(UUID::toString)
283287
.limit(someInt(1, 4))
284-
.collect(Collectors.joining(" blah blah "));
288+
.collect(joining(" blah blah "));
285289
return new RuntimeException(message)
286290
.fillInStackTrace();
287291
}
@@ -296,7 +300,7 @@ public static Throwable someIoException() {
296300
.generate(UUID::randomUUID)
297301
.map(UUID::toString)
298302
.limit(someInt(1, 4))
299-
.collect(Collectors.joining(" blah blah "));
303+
.collect(joining(" blah blah "));
300304
return new IOException(message)
301305
.fillInStackTrace();
302306
}
@@ -348,6 +352,22 @@ public static String someRelease() {
348352
return Integer.toString(RANDOM.nextInt(11) + 11);
349353
}
350354

355+
/**
356+
* Get a valid random module name.
357+
*
358+
* @return the valid module name.
359+
*/
360+
public static String someModuleName() {
361+
return Stream
362+
.generate(() -> Stream
363+
.generate(() -> (char) someInt('a', 'z'))
364+
.map(Objects::toString)
365+
.limit(someInt(1, 10))
366+
.collect(joining()))
367+
.limit(someInt(1, 5))
368+
.collect(joining("."));
369+
}
370+
351371
/**
352372
* Get some mock Java file object with a dummy name and some assigned {@link Kind}.
353373
*
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
/*
2+
* Copyright (C) 2022 - 2023, the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.github.ascopes.jct.tests.unit.filemanagers;
17+
18+
import static io.github.ascopes.jct.tests.helpers.Fixtures.someModuleName;
19+
import static java.util.function.Predicate.not;
20+
import static java.util.stream.Collectors.collectingAndThen;
21+
import static java.util.stream.Collectors.toList;
22+
import static org.assertj.core.api.Assertions.assertThat;
23+
import static org.assertj.core.api.Assertions.assertThatCode;
24+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
25+
26+
import io.github.ascopes.jct.filemanagers.ModuleLocation;
27+
import io.github.ascopes.jct.tests.helpers.Fixtures;
28+
import java.util.Objects;
29+
import java.util.stream.Stream;
30+
import javax.tools.StandardLocation;
31+
import org.junit.jupiter.api.DisplayName;
32+
import org.junit.jupiter.api.Test;
33+
import org.junit.jupiter.params.ParameterizedTest;
34+
import org.junit.jupiter.params.provider.MethodSource;
35+
36+
/**
37+
* {@link ModuleLocation} tests.
38+
*
39+
* @author Ashley Scopes
40+
*/
41+
@DisplayName("ModuleLocation tests")
42+
class ModuleLocationTest {
43+
44+
@DisplayName("Passing a null parent to the constructor raises an exception")
45+
@SuppressWarnings("DataFlowIssue")
46+
@Test
47+
void passingNullParentToConstructorRaisesException() {
48+
// Then
49+
assertThatThrownBy(() -> new ModuleLocation(null, "something"))
50+
.isInstanceOf(NullPointerException.class)
51+
.hasMessage("parent");
52+
}
53+
54+
@DisplayName("Passing a null module name to the constructor raises an exception")
55+
@SuppressWarnings("DataFlowIssue")
56+
@Test
57+
void passingNullNameToConstructorRaisesException() {
58+
// Then
59+
assertThatThrownBy(() -> new ModuleLocation(StandardLocation.MODULE_SOURCE_PATH, null))
60+
.isInstanceOf(NullPointerException.class)
61+
.hasMessage("moduleName");
62+
}
63+
64+
@DisplayName("Passing an input package-oriented location to the constructor raises an exception")
65+
@MethodSource("packageOrientedInputLocations")
66+
@ParameterizedTest(name = "for StandardLocation.{0}")
67+
void passingInputPackageOrientedLocationToConstructorRaisesException(StandardLocation location) {
68+
// Then
69+
assertThatThrownBy(() -> new ModuleLocation(location, "foo.bar"))
70+
.isInstanceOf(IllegalArgumentException.class)
71+
.hasMessage(
72+
"The parent of a module location must be either an output location or be "
73+
+ "module-oriented, but got %s",
74+
location.getName()
75+
);
76+
}
77+
78+
@DisplayName(
79+
"Passing a module-oriented or output location to the constructor does not raise an exception"
80+
)
81+
@MethodSource({"moduleOrientedLocations", "outputLocations"})
82+
@ParameterizedTest(name = "for StandardLocation.{0}")
83+
void passingModuleOrientedOrOutputLocationsToConstructorSucceeds(StandardLocation location) {
84+
// Then
85+
assertThatCode(() -> new ModuleLocation(location, "foo.bar"))
86+
.doesNotThrowAnyException();
87+
}
88+
89+
@DisplayName(".getParent() returns the parent location")
90+
@Test
91+
void getParentReturnsTheParentLocation() {
92+
// Given
93+
var parent = someValidParentLocation();
94+
var moduleName = someModuleName();
95+
var moduleLocation = new ModuleLocation(parent, moduleName);
96+
97+
// Then
98+
assertThat(moduleLocation.getParent())
99+
.isSameAs(parent);
100+
}
101+
102+
@DisplayName(".getModuleName() returns the module name")
103+
@Test
104+
void getModuleNameReturnsTheModuleName() {
105+
// Given
106+
var parent = someValidParentLocation();
107+
var moduleName = someModuleName();
108+
var moduleLocation = new ModuleLocation(parent, moduleName);
109+
110+
// Then
111+
assertThat(moduleLocation.getModuleName())
112+
.isEqualTo(moduleName);
113+
}
114+
115+
@DisplayName(".getName() returns the friendly name identifier")
116+
@Test
117+
void getNameReturnsTheFriendlyNameIdentifier() {
118+
// Given
119+
var parent = someValidParentLocation();
120+
var moduleName = someModuleName();
121+
var moduleLocation = new ModuleLocation(parent, moduleName);
122+
123+
// Then
124+
assertThat(moduleLocation.getName())
125+
.isEqualTo("%s[%s]", parent.getName(), moduleName);
126+
}
127+
128+
@DisplayName(".isOutputLocation() returns the expected value")
129+
@MethodSource({"moduleOrientedLocations", "outputLocations"})
130+
@ParameterizedTest(name = "for StandardLocation.{0}")
131+
void isOutputLocationReturnsTheExpectedValue(StandardLocation parent) {
132+
// Given
133+
var moduleName = someModuleName();
134+
var moduleLocation = new ModuleLocation(parent, moduleName);
135+
136+
// Then
137+
assertThat(moduleLocation.isOutputLocation())
138+
.isEqualTo(parent.isOutputLocation());
139+
}
140+
141+
@DisplayName(".isModuleOrientedLocation() always returns false")
142+
@MethodSource({"moduleOrientedLocations", "outputLocations"})
143+
@ParameterizedTest(name = "for StandardLocation.{0}")
144+
void isModuleOrientedLocationAlwaysReturnsFalse(StandardLocation parent) {
145+
// Given
146+
var moduleName = someModuleName();
147+
var moduleLocation = new ModuleLocation(parent, moduleName);
148+
149+
// Then
150+
assertThat(moduleLocation.isModuleOrientedLocation())
151+
.isFalse();
152+
}
153+
154+
@DisplayName(".equals(...) returns true for the same object")
155+
@Test
156+
void equalsReturnsTrueForSameObject() {
157+
// Given
158+
var moduleLocation = new ModuleLocation(someValidParentLocation(), someModuleName());
159+
160+
// Then
161+
assertThat(moduleLocation).isEqualTo(moduleLocation);
162+
}
163+
164+
@DisplayName(".equals(...) returns true for equal objects that are not the same instance")
165+
@Test
166+
void equalsReturnsTrueForEqualButNonSameObjects() {
167+
// Given
168+
var parent = someValidParentLocation();
169+
var moduleName = someModuleName();
170+
171+
var moduleLocation1 = new ModuleLocation(parent, moduleName);
172+
var moduleLocation2 = new ModuleLocation(parent, moduleName);
173+
174+
// Then
175+
assertThat(moduleLocation1).isEqualTo(moduleLocation2);
176+
assertThat(moduleLocation2).isEqualTo(moduleLocation1);
177+
}
178+
179+
@DisplayName(".equals(...) returns false for null values")
180+
@Test
181+
void equalsReturnsFalseForNullValues() {
182+
// Then
183+
assertThat(new ModuleLocation(someValidParentLocation(), someModuleName()))
184+
.isNotEqualTo(null);
185+
}
186+
187+
@DisplayName(".equals(...) returns false for non-module location objects")
188+
@SuppressWarnings("AssertBetweenInconvertibleTypes")
189+
@Test
190+
void equalsReturnsFalseForNonModuleLocationObjects() {
191+
// Given
192+
var parent = someValidParentLocation();
193+
var moduleName = someModuleName();
194+
195+
// Then
196+
assertThat(new ModuleLocation(parent, moduleName))
197+
.isNotEqualTo(parent)
198+
.isNotEqualTo(moduleName)
199+
.isNotEqualTo("potato")
200+
.isNotEqualTo(new ArrayIndexOutOfBoundsException());
201+
}
202+
203+
@DisplayName(".equals(...) returns false for different parents with the same module name")
204+
@Test
205+
void equalsReturnsFalseForDifferentParentsWithTheSameModuleName() {
206+
// Given
207+
var parent1 = someValidParentLocation();
208+
var parent2 = someValidParentLocation(parent1);
209+
var moduleName = someModuleName();
210+
211+
var moduleLocation1 = new ModuleLocation(parent1, moduleName);
212+
var moduleLocation2 = new ModuleLocation(parent2, moduleName);
213+
214+
// Then
215+
assertThat(moduleLocation1)
216+
.isNotEqualTo(moduleLocation2);
217+
}
218+
219+
@DisplayName(".equals(...) returns false for shared parents with differing module names")
220+
@Test
221+
void equalsReturnsFalseForSharedParentsWithDifferentModuleNames() {
222+
// Given
223+
var parent = someValidParentLocation();
224+
var moduleName1 = "foo.bar";
225+
var moduleName2 = "baz.bork";
226+
227+
var moduleLocation1 = new ModuleLocation(parent, moduleName1);
228+
var moduleLocation2 = new ModuleLocation(parent, moduleName2);
229+
230+
// Then
231+
assertThat(moduleLocation1)
232+
.isNotEqualTo(moduleLocation2);
233+
}
234+
235+
@DisplayName(".hashCode() returns the expected value")
236+
@Test
237+
void hashCodeReturnsTheExpectedValue() {
238+
// Given
239+
var parent = someValidParentLocation();
240+
var moduleName = someModuleName();
241+
var moduleLocation = new ModuleLocation(parent, moduleName);
242+
243+
// Then
244+
assertThat(moduleLocation.hashCode())
245+
.isEqualTo(Objects.hash(parent, moduleName));
246+
}
247+
248+
@DisplayName(".toString() returns the expected value")
249+
@Test
250+
void toStringReturnsTheExpectedValue() {
251+
// Given
252+
var parent = someValidParentLocation();
253+
var moduleName = someModuleName();
254+
var moduleLocation = new ModuleLocation(parent, moduleName);
255+
256+
// Then
257+
assertThat(moduleLocation.toString())
258+
.isEqualTo("ModuleLocation{parent=%s, moduleName=\"%s\"}", parent, moduleName);
259+
}
260+
261+
static Stream<StandardLocation> packageOrientedInputLocations() {
262+
return Stream.of(StandardLocation.values())
263+
.filter(not(StandardLocation::isOutputLocation))
264+
.filter(not(StandardLocation::isModuleOrientedLocation));
265+
}
266+
267+
static Stream<StandardLocation> moduleOrientedLocations() {
268+
return Stream.of(StandardLocation.values())
269+
.filter(not(StandardLocation::isOutputLocation))
270+
.filter(StandardLocation::isModuleOrientedLocation);
271+
}
272+
273+
static Stream<StandardLocation> outputLocations() {
274+
return Stream.of(StandardLocation.values())
275+
.filter(StandardLocation::isOutputLocation);
276+
}
277+
278+
static StandardLocation someValidParentLocation(StandardLocation... exclude) {
279+
return Stream
280+
.concat(moduleOrientedLocations(), outputLocations())
281+
.filter(location -> Stream.of(exclude).noneMatch(location::equals))
282+
.collect(collectingAndThen(toList(), Fixtures::oneOf));
283+
}
284+
}

0 commit comments

Comments
 (0)