Skip to content

Commit 32cba95

Browse files
hasterclaude
andcommitted
Make name lookup null-safe and add typed lookup overload
- TestcontainerRegistry.lookup(String): flip the equals direction so callers passing null get a null result instead of an NPE on a populated registry. The compared `containerDesc.name` is sourced from Testcontainer.name(), which by annotation rules cannot be null. - TestcontainerRegistry.lookup(String, Class<T>): typed overload that casts the looked-up container to the requested type, throwing IllegalArgumentException if the registered container is not assignable to the requested type. Returns null if no container with the given name is registered. Tests cover the null-name path on a populated registry, the typed-lookup happy path including a missing-name null return, and the type-mismatch throw path. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 725095f commit 32cba95

2 files changed

Lines changed: 54 additions & 1 deletion

File tree

src/main/java/org/arquillian/testcontainers/TestcontainerRegistry.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,35 @@ GenericContainer<?> lookupOrCreate(final Class<GenericContainer<?>> type, final
6969
*/
7070
GenericContainer<?> lookup(final String name) {
7171
for (TestcontainerDescription containerDesc : this.containers) {
72-
if (name.equals(containerDesc.name)) {
72+
if (containerDesc.name.equals(name)) {
7373
return containerDesc.instance;
7474
}
7575
}
7676
return null;
7777
}
7878

79+
/**
80+
* Typed lookup by name. Throws {@link IllegalArgumentException} if a container with the given name is registered
81+
* but its runtime type is not assignable to {@code type}.
82+
*
83+
* @param name the container name
84+
* @param type the expected container type
85+
*
86+
* @return the container cast to {@code type}, or {@code null} if no container with the given name is registered
87+
*/
88+
<T extends GenericContainer<?>> T lookup(final String name, final Class<T> type) {
89+
final GenericContainer<?> container = lookup(name);
90+
if (container == null) {
91+
return null;
92+
}
93+
if (!type.isInstance(container)) {
94+
throw new IllegalArgumentException(
95+
String.format("Container with name '%s' is of type %s, which is not assignable to %s",
96+
name, container.getClass().getName(), type.getName()));
97+
}
98+
return type.cast(container);
99+
}
100+
79101
/**
80102
* Lookup the container in the test container instances. If more than one container is found for the type or
81103
* qualifier, an {@link IllegalArgumentException} is thrown.

src/test/java/org/arquillian/testcontainers/TestcontainerRegistryTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,37 @@ public void emptyNameLookupDoesNotMatchNamedContainers() throws Exception {
5151
"Empty-string lookup should not return any registered container");
5252
}
5353

54+
@Test
55+
public void lookupTreatsNullNameAsAbsent() throws Exception {
56+
TestcontainerRegistry registry = new TestcontainerRegistry();
57+
registry.lookupOrCreate(simpleType(), annotation("alphaFixture"), List.of());
58+
59+
Assertions.assertNull(registry.lookup((String) null));
60+
}
61+
62+
@Test
63+
public void typedLookupReturnsTypedContainer() throws Exception {
64+
TestcontainerRegistry registry = new TestcontainerRegistry();
65+
GenericContainer<?> alpha = registry.lookupOrCreate(simpleType(), annotation("alphaFixture"), List.of());
66+
67+
SimpleTestContainer typed = registry.lookup("alpha", SimpleTestContainer.class);
68+
Assertions.assertSame(alpha, typed);
69+
Assertions.assertNull(registry.lookup("missing", SimpleTestContainer.class));
70+
}
71+
72+
@Test
73+
public void typedLookupThrowsOnTypeMismatch() throws Exception {
74+
TestcontainerRegistry registry = new TestcontainerRegistry();
75+
registry.lookupOrCreate(simpleType(), annotation("alphaFixture"), List.of());
76+
77+
Assertions.assertThrows(IllegalArgumentException.class,
78+
() -> registry.lookup("alpha", IncompatibleContainer.class));
79+
}
80+
81+
/** Distinct {@link GenericContainer} subtype used to exercise the type-mismatch path on typed lookup. */
82+
private static class IncompatibleContainer extends GenericContainer<IncompatibleContainer> {
83+
}
84+
5485
@SuppressWarnings("unchecked")
5586
private static Class<GenericContainer<?>> simpleType() {
5687
return (Class<GenericContainer<?>>) (Class<?>) SimpleTestContainer.class;

0 commit comments

Comments
 (0)