gnodet commented on code in PR #12117:
URL: https://github.com/apache/maven/pull/12117#discussion_r3279247605


##########
impl/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java:
##########
@@ -31,6 +31,8 @@
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;

Review Comment:
   Add `assertTrue` import for the assertion change below:
   
   ```suggestion
   import static org.junit.jupiter.api.Assertions.assertInstanceOf;
   import static org.junit.jupiter.api.Assertions.assertThrows;
   import static org.junit.jupiter.api.Assertions.assertTrue;
   ```



##########
impl/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java:
##########
@@ -108,8 +110,72 @@ void testChildConfigurationElement() throws 
BeanConfigurationException {
         assertEquals(new File("test"), bean.file);
     }
 
+    @Test
+    void testSealedTypeImplementationHintCanUseSimpleName() throws 
BeanConfigurationException {
+        SealedBean bean = new SealedBean();
+
+        Xpp3Dom config = toConfig("<artifact 
implementation=\"LocalArtifact\"><name>local</name></artifact>");
+
+        DefaultBeanConfigurationRequest request = new 
DefaultBeanConfigurationRequest();
+        request.setBean(bean).setConfiguration(config);
+
+        configurator.configureBean(request);
+
+        LocalArtifact artifact = assertInstanceOf(LocalArtifact.class, 
bean.artifact);
+        assertEquals("local", artifact.name);
+    }
+
+    @Test
+    void testSealedTypeImplementationHintCanStillUseClassName() throws 
BeanConfigurationException {
+        SealedBean bean = new SealedBean();
+
+        Xpp3Dom config = toConfig("<artifact implementation=\"" + 
RemoteArtifact.class.getName()
+                + "\"><url>https://example.invalid/artifact</url></artifact>");
+
+        DefaultBeanConfigurationRequest request = new 
DefaultBeanConfigurationRequest();
+        request.setBean(bean).setConfiguration(config);
+
+        configurator.configureBean(request);
+
+        RemoteArtifact artifact = assertInstanceOf(RemoteArtifact.class, 
bean.artifact);
+        assertEquals("https://example.invalid/artifact";, artifact.url);
+    }
+
+    @Test
+    void testSealedTypeImplementationHintMustMatchPermittedSubclass() {
+        SealedBean bean = new SealedBean();
+
+        Xpp3Dom config = toConfig("<artifact 
implementation=\"MissingArtifact\"><name>missing</name></artifact>");
+
+        DefaultBeanConfigurationRequest request = new 
DefaultBeanConfigurationRequest();
+        request.setBean(bean).setConfiguration(config);
+
+        BeanConfigurationException e =
+                assertThrows(BeanConfigurationException.class, () -> 
configurator.configureBean(request));
+        assertEquals(
+                "Cannot find permitted subclass 'MissingArtifact' for sealed 
type " + SealedArtifact.class.getName(),
+                e.getMessage());
+    }
+
     static class SomeBean {
 
         File file;
     }
+
+    static class SealedBean {
+
+        SealedArtifact artifact;
+    }
+
+    public sealed interface SealedArtifact permits LocalArtifact, 
RemoteArtifact {}
+
+    public static final class LocalArtifact implements SealedArtifact {
+
+        String name;
+    }
+
+    public static final class RemoteArtifact implements SealedArtifact {
+
+        String url;
+    }
 }

Review Comment:
   Consider adding a test for the **ambiguity** code path (two permitted 
subclasses sharing the same simple name). This also requires adding the helper 
types:
   
   ```suggestion
       }
   
       @Test
       void testSealedTypeAmbiguousSimpleNameThrowsError() {
           AmbiguousBean bean = new AmbiguousBean();
   
           Xpp3Dom config = toConfig("<value implementation=\"Ambiguous\"/>");
   
           DefaultBeanConfigurationRequest request = new 
DefaultBeanConfigurationRequest();
           request.setBean(bean).setConfiguration(config);
   
           BeanConfigurationException e =
                   assertThrows(BeanConfigurationException.class, () -> 
configurator.configureBean(request));
           assertTrue(e.getMessage().contains("is ambiguous for sealed type"));
       }
   
       static class SomeBean {
   
           File file;
       }
   
       static class SealedBean {
   
           SealedArtifact artifact;
       }
   
       static class AmbiguousBean {
   
           AmbiguousSealedType value;
       }
   
       public sealed interface SealedArtifact permits LocalArtifact, 
RemoteArtifact {}
   
       public sealed interface AmbiguousSealedType permits Holder1.Ambiguous, 
Holder2.Ambiguous {}
   
       public static final class LocalArtifact implements SealedArtifact {
   
           String name;
       }
   
       public static final class RemoteArtifact implements SealedArtifact {
   
           String url;
       }
   
       public static final class Holder1 {
   
           public static final class Ambiguous implements AmbiguousSealedType {}
       }
   
       public static final class Holder2 {
   
           public static final class Ambiguous implements AmbiguousSealedType {}
       }
   }
   ```



##########
impl/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java:
##########
@@ -108,8 +110,72 @@ void testChildConfigurationElement() throws 
BeanConfigurationException {
         assertEquals(new File("test"), bean.file);
     }
 
+    @Test
+    void testSealedTypeImplementationHintCanUseSimpleName() throws 
BeanConfigurationException {
+        SealedBean bean = new SealedBean();
+
+        Xpp3Dom config = toConfig("<artifact 
implementation=\"LocalArtifact\"><name>local</name></artifact>");
+
+        DefaultBeanConfigurationRequest request = new 
DefaultBeanConfigurationRequest();
+        request.setBean(bean).setConfiguration(config);
+
+        configurator.configureBean(request);
+
+        LocalArtifact artifact = assertInstanceOf(LocalArtifact.class, 
bean.artifact);
+        assertEquals("local", artifact.name);
+    }
+
+    @Test
+    void testSealedTypeImplementationHintCanStillUseClassName() throws 
BeanConfigurationException {
+        SealedBean bean = new SealedBean();
+
+        Xpp3Dom config = toConfig("<artifact implementation=\"" + 
RemoteArtifact.class.getName()
+                + "\"><url>https://example.invalid/artifact</url></artifact>");
+
+        DefaultBeanConfigurationRequest request = new 
DefaultBeanConfigurationRequest();
+        request.setBean(bean).setConfiguration(config);
+
+        configurator.configureBean(request);
+
+        RemoteArtifact artifact = assertInstanceOf(RemoteArtifact.class, 
bean.artifact);
+        assertEquals("https://example.invalid/artifact";, artifact.url);
+    }
+
+    @Test
+    void testSealedTypeImplementationHintMustMatchPermittedSubclass() {
+        SealedBean bean = new SealedBean();
+
+        Xpp3Dom config = toConfig("<artifact 
implementation=\"MissingArtifact\"><name>missing</name></artifact>");
+
+        DefaultBeanConfigurationRequest request = new 
DefaultBeanConfigurationRequest();
+        request.setBean(bean).setConfiguration(config);
+
+        BeanConfigurationException e =
+                assertThrows(BeanConfigurationException.class, () -> 
configurator.configureBean(request));
+        assertEquals(
+                "Cannot find permitted subclass 'MissingArtifact' for sealed 
type " + SealedArtifact.class.getName(),
+                e.getMessage());

Review Comment:
   Using `assertEquals` on the full message can be brittle if 
`BeanConfigurationException` changes how it wraps the cause. A `contains` check 
is more resilient:
   
   ```suggestion
           assertTrue(
                   e.getMessage().contains("Cannot find permitted subclass 
'MissingArtifact' for sealed type "
                           + SealedArtifact.class.getName()));
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to