This is an automated email from the ASF dual-hosted git repository.

veithen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-axiom.git


The following commit(s) were added to refs/heads/master by this push:
     new 450eeff81 Make MatrixTestNode return Stream<DynamicNode> and 
MatrixTestContainer generic
450eeff81 is described below

commit 450eeff81e84eae4ecfdd7edbf960076bf0849b2
Author: Andreas Veithen-Knowles <[email protected]>
AuthorDate: Mon Feb 23 08:31:01 2026 +0000

    Make MatrixTestNode return Stream<DynamicNode> and MatrixTestContainer 
generic
    
    - MatrixTestNode.toDynamicNodes() now returns Stream<DynamicNode> instead
      of a single DynamicNode.
    - MatrixTestContainer<D extends Dimension> is now generic and holds a
      List<D>, producing one DynamicContainer per dimension instance.
    - MatrixTestCase.toDynamicNodes() returns Stream.of(...) or
      Stream.empty() instead of a node or null.
    - Consumer no longer needs .children() to unwrap a root container.
---
 docs/design/test-suite-pattern.md | 129 +++++++++++++++++++++-----------------
 1 file changed, 71 insertions(+), 58 deletions(-)

diff --git a/docs/design/test-suite-pattern.md 
b/docs/design/test-suite-pattern.md
index 39052df13..5578d00f7 100644
--- a/docs/design/test-suite-pattern.md
+++ b/docs/design/test-suite-pattern.md
@@ -232,7 +232,7 @@ parameters needed for exclusion filtering.
  * that can be filtered before conversion to JUnit 5's dynamic test API.
  */
 abstract class MatrixTestNode {
-    abstract DynamicNode toDynamicNode(Dictionary<String, String> 
inheritedParameters,
+    abstract Stream<DynamicNode> toDynamicNodes(Dictionary<String, String> 
inheritedParameters,
             List<Filter> excludes);
 }
 ```
@@ -242,23 +242,27 @@ abstract class MatrixTestNode {
  * Mirrors {@link DynamicContainer}. Represents a parameterized grouping level
  * in the test tree (e.g. a SOAP version, a serialization strategy).
  *
- * <p>Each {@code MatrixTestContainer} corresponds to a single {@link 
Dimension}
- * value (e.g. one particular {@code SerializationStrategy}). The {@code 
Dimension}
- * is stored as-is; its test parameters are extracted lazily when
- * {@link #toDynamicNode(Dictionary, List)} is called. Because a {@code 
Dimension}
- * may contribute multiple test parameters (for example, {@code 
SerializeToWriter}
- * adds both {@code serializationStrategy=Writer} and {@code cache=true}), 
these
- * parameters also determine the display name and are merged into the inherited
- * parameter dictionary. The full parameter dictionary for any leaf
- * {@code MatrixTestCase} is the accumulation of parameters from its ancestor
- * {@code MatrixTestContainer} chain.
+ * <p>A {@code MatrixTestContainer} holds a list of {@link Dimension} instances
+ * of a given type (e.g. all {@code SOAPSpec} values, or all
+ * {@code SerializationStrategy} values). When {@link #toDynamicNodes} is 
called,
+ * it produces one {@link DynamicContainer} per dimension instance. Each
+ * dimension's test parameters are extracted at that point to determine the
+ * display name and to merge into the inherited parameter dictionary. Because a
+ * {@code Dimension} may contribute multiple test parameters (for example,
+ * {@code SerializeToWriter} adds both {@code serializationStrategy=Writer} and
+ * {@code cache=true}), these parameters also determine the display name. The
+ * full parameter dictionary for any leaf {@code MatrixTestCase} is the
+ * accumulation of parameters from its ancestor {@code MatrixTestContainer}
+ * chain.
+ *
+ * @param <D> the dimension type
  */
-class MatrixTestContainer extends MatrixTestNode {
-    private final Dimension dimension;
+class MatrixTestContainer<D extends Dimension> extends MatrixTestNode {
+    private final List<D> dimensions;
     private final List<MatrixTestNode> children = new ArrayList<>();
 
-    MatrixTestContainer(Dimension dimension) {
-        this.dimension = dimension;
+    MatrixTestContainer(List<D> dimensions) {
+        this.dimensions = dimensions;
     }
 
     void addChild(MatrixTestNode child) {
@@ -266,39 +270,40 @@ class MatrixTestContainer extends MatrixTestNode {
     }
 
     @Override
-    DynamicNode toDynamicNode(Dictionary<String, String> inheritedParameters,
+    Stream<DynamicNode> toDynamicNodes(Dictionary<String, String> 
inheritedParameters,
             List<Filter> excludes) {
-        Map<String, String> parameters = new LinkedHashMap<>();
-        dimension.addTestParameters(new TestParameterTarget() {
-            @Override
-            public void addTestParameter(String name, String value) {
-                parameters.put(name, value);
-            }
-
-            @Override
-            public void addTestParameter(String name, boolean value) {
-                addTestParameter(name, String.valueOf(value));
-            }
-
-            @Override
-            public void addTestParameter(String name, int value) {
-                addTestParameter(name, String.valueOf(value));
+        return dimensions.stream().map(dimension -> {
+            Map<String, String> parameters = new LinkedHashMap<>();
+            dimension.addTestParameters(new TestParameterTarget() {
+                @Override
+                public void addTestParameter(String name, String value) {
+                    parameters.put(name, value);
+                }
+
+                @Override
+                public void addTestParameter(String name, boolean value) {
+                    addTestParameter(name, String.valueOf(value));
+                }
+
+                @Override
+                public void addTestParameter(String name, int value) {
+                    addTestParameter(name, String.valueOf(value));
+                }
+            });
+            Hashtable<String, String> params = new Hashtable<>();
+            // Copy inherited parameters from ancestor containers
+            for (Enumeration<String> e = inheritedParameters.keys(); 
e.hasMoreElements(); ) {
+                String key = e.nextElement();
+                params.put(key, inheritedParameters.get(key));
             }
+            parameters.forEach(params::put);
+            String displayName = parameters.entrySet().stream()
+                    .map(e -> e.getKey() + "=" + e.getValue())
+                    .collect(Collectors.joining(", "));
+            return DynamicContainer.dynamicContainer(displayName,
+                    children.stream()
+                            .flatMap(child -> child.toDynamicNodes(params, 
excludes)));
         });
-        Hashtable<String, String> params = new Hashtable<>();
-        // Copy inherited parameters from ancestor containers
-        for (Enumeration<String> e = inheritedParameters.keys(); 
e.hasMoreElements(); ) {
-            String key = e.nextElement();
-            params.put(key, inheritedParameters.get(key));
-        }
-        parameters.forEach(params::put);
-        String displayName = parameters.entrySet().stream()
-                .map(e -> e.getKey() + "=" + e.getValue())
-                .collect(Collectors.joining(", "));
-        return DynamicContainer.dynamicContainer(displayName,
-                children.stream()
-                        .map(child -> child.toDynamicNode(params, excludes))
-                        .filter(Objects::nonNull));
     }
 }
 ```
@@ -319,29 +324,38 @@ class MatrixTestCase extends MatrixTestNode {
     }
 
     @Override
-    DynamicNode toDynamicNode(Dictionary<String, String> inheritedParameters,
+    Stream<DynamicNode> toDynamicNodes(Dictionary<String, String> 
inheritedParameters,
             List<Filter> excludes) {
         for (Filter exclude : excludes) {
             if (exclude.matches(testClass, inheritedParameters)) {
-                return null; // Excluded
+                return Stream.empty(); // Excluded
             }
         }
-        return DynamicTest.dynamicTest(testClass.getSimpleName(), executable);
+        return Stream.of(DynamicTest.dynamicTest(testClass.getSimpleName(), 
executable));
     }
 }
 ```
 
 #### How filtering works
 
-Each `MatrixTestContainer` level represents one `Dimension` value and carries 
one or
-more parameters contributed by that dimension. As the tree is converted to 
`DynamicNode`
-instances via `toDynamicNode()`, parameters accumulate from the root down:
+Each `MatrixTestContainer` level holds a list of `Dimension` instances (e.g. 
all
+`SOAPSpec` values or all `SerializationStrategy` values). When 
`toDynamicNodes()` is
+called, each container produces one `DynamicContainer` per dimension instance, 
and
+parameters accumulate from the root down:
 
 ```
-MatrixTestContainer(SOAPSpec.SOAP11)                 → params: {spec=soap11}
-  MatrixTestContainer(SerializeToWriter(cache=true)) → params: {spec=soap11, 
serializationStrategy=Writer, cache=true}
-    MatrixTestCase(SerializeElement.class, ...)        → filtered against 
{spec=soap11, serializationStrategy=Writer, cache=true}
-    MatrixTestCase(SerializeDocument.class, ...)      → filtered against 
{spec=soap11, serializationStrategy=Writer, cache=true}
+MatrixTestContainer([SOAPSpec.SOAP11, SOAPSpec.SOAP12])
+  MatrixTestContainer([SerializeToWriter(cache=true), ...])
+    MatrixTestCase(SerializeElement.class, ...)
+    MatrixTestCase(SerializeDocument.class, ...)
+
+→ spec=soap11
+    → serializationStrategy=Writer, cache=true
+        → SerializeElement  (filtered against {spec=soap11, 
serializationStrategy=Writer, cache=true})
+        → SerializeDocument (filtered against {spec=soap11, 
serializationStrategy=Writer, cache=true})
+  spec=soap12
+    → serializationStrategy=Writer, cache=true
+        → ...
 ```
 
 Note that `SerializeToWriter` contributes two parameters 
(`serializationStrategy` and
@@ -354,11 +368,10 @@ Consumers apply exclusions exactly as they do today:
 class OMImplementationTests {
     @TestFactory
     Stream<DynamicNode> omTests() {
-        MatrixTestContainer root = new OMTestTreeBuilder(metaFactory).build();
+        MatrixTestContainer<?> root = new 
OMTestTreeBuilder(metaFactory).build();
         List<Filter> excludes = new ArrayList<>();
         excludes.add(Filter.forClass(TestSerialize.class, "(spec=soap12)"));
-        return root.toDynamicNode(new Hashtable<>(), excludes)
-                .children(); // unwrap the root container
+        return root.toDynamicNodes(new Hashtable<>(), excludes);
     }
 }
 ```

Reply via email to