• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

xmlunit / xmlunit / 3f7651ec-f6b5-44df-b60a-ba2dbc5d7339

21 Jun 2025 01:18PM CUT coverage: 91.769%. Remained the same
3f7651ec-f6b5-44df-b60a-ba2dbc5d7339

push

circleci

web-flow
Merge pull request #305 from xmlunit/extend-compat-test-range

add additional compatibility tests

4014 of 4722 branches covered (85.01%)

11774 of 12830 relevant lines covered (91.77%)

2.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

32.35
/xmlunit-assertj/src/main/java/org/xmlunit/assertj/AssertFactoryProvider.java
1
/*
2
  This file is licensed to You under the Apache License, Version 2.0
3
  (the "License"); you may not use this file except in compliance with
4
  the License.  You may obtain a copy of the License at
5

6
  http://www.apache.org/licenses/LICENSE-2.0
7

8
  Unless required by applicable law or agreed to in writing, software
9
  distributed under the License is distributed on an "AS IS" BASIS,
10
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
  See the License for the specific language governing permissions and
12
  limitations under the License.
13
*/
14
package org.xmlunit.assertj;
15

16
import net.bytebuddy.ByteBuddy;
17
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
18
import net.bytebuddy.implementation.MethodDelegation;
19
import net.bytebuddy.matcher.ElementMatchers;
20
import net.bytebuddy.utility.RandomString;
21

22
import org.assertj.core.api.Assert;
23
import org.assertj.core.api.AssertFactory;
24
import org.w3c.dom.Node;
25
import org.xmlunit.xpath.XPathEngine;
26

27
import java.lang.reflect.ParameterizedType;
28
import java.lang.reflect.Type;
29
import java.lang.reflect.TypeVariable;
30

31
/**
32
 * In AssertJ before 3.13.0 {@link AssertFactory} class looks like this:
33
 * <pre>
34
 * public interface AssertFactory<T, ASSERT> {
35
 *      ASSERT createAssert(T t);
36
 * }
37
 * </pre>
38
 * <p>
39
 * So after type erasure it should be like this:
40
 * <pre>
41
 * public interface AssertFactory {
42
 *      Object createAssert(Object t);
43
 * }
44
 *
45
 * In AssertJ 3.13.0 AssertFactory class was change to:
46
 * <pre>
47
 * public interface AssertFactory&lt;T, ASSERT extends Assert&lt;?, ?&gt;&gt; {
48
 *      ASSERT createAssert(T t);
49
 * }
50
 * </pre>
51
 * <p>
52
 * So after type erasure it should be like this:
53
 * <pre>
54
 * public interface AssertFactory {
55
 *      Assert createAssert(Object t);
56
 * }
57
 * </pre>
58
 * <p>
59
 * That change brings binary incompatibility so {@link NodeAssertFactory} cannot be used along with latest AssertJ.
60
 * AssertFactoryProvider checks if there is new version of AssertFactory on class path
61
 * and if so dynamically creates AssertFactory subclass otherwise return instance of NodeAssertFactory.
62
 * <p>
63
 * AssertFactoryProvider uses ByteBuddy internally witch should be provided by latest AssertJ.
64
 *
65
 * @see org.assertj.core.api.AssertFactory
66
 * @see org.assertj.core.api.FactoryBasedNavigableIterableAssert
67
 * @since XMLUnit 2.6.4
68
 */
69
class AssertFactoryProvider {
1✔
70

71
    @SuppressWarnings("rawtypes")
72
    private static Class<? extends AssertFactory> assertFactoryClass;
73

74
    AssertFactory<Node, SingleNodeAssert> create(XPathEngine engine) {
75

76
        if (hasAssertFactoryUpperBoundOnAssertType()) {
1!
77
            return createProxyInstance(engine);
×
78
        }
79

80
        return createDefaultInstance(engine);
1✔
81
    }
82

83
    private boolean hasAssertFactoryUpperBoundOnAssertType() {
84

85
        @SuppressWarnings("rawtypes")
86
        TypeVariable<Class<AssertFactory>>[] typeParameters = AssertFactory.class.getTypeParameters();
1✔
87
        if (typeParameters.length == 2) {
1!
88
            Type[] bounds = typeParameters[1].getBounds();
1✔
89
            if (bounds.length == 1) {
1!
90
                Type assertType = bounds[0];
1✔
91
                if (assertType instanceof ParameterizedType) {
1!
92
                    ParameterizedType at = (ParameterizedType) assertType;
×
93
                    return at.getRawType().equals(Assert.class);
×
94
                }
95
            }
96
        }
97

98
        return false;
1✔
99
    }
100

101
    private AssertFactory<Node, SingleNodeAssert> createProxyInstance(XPathEngine engine) {
102

103
        try {
104
            synchronized (AssertFactoryProvider.class) {
×
105
                if (assertFactoryClass == null) {
×
106
                    assertFactoryClass = new ByteBuddy()
×
107
                            .subclass(AssertFactory.class)
×
108
                            .name(NodeAssertFactoryDelegate.class.getPackage().getName() + ".XmlUnit$AssertFactory$" + RandomString.make())
×
109
                            .method(ElementMatchers.named("createAssert"))
×
110
                            .intercept(MethodDelegation.to(new NodeAssertFactoryDelegate(createDefaultInstance(engine))))
×
111
                            .make()
×
112
                            .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
×
113
                            .getLoaded();
×
114
                }
115
            }
×
116

117
            @SuppressWarnings("unchecked")
118
            AssertFactory<Node, SingleNodeAssert> instance = (AssertFactory<Node, SingleNodeAssert>) assertFactoryClass.newInstance();
×
119
            return instance;
×
120

121
        } catch (IllegalAccessException | InstantiationException e) {
×
122
            e.printStackTrace();
×
123
        }
124

125
        return createDefaultInstance(engine);
×
126
    }
127

128
    private NodeAssertFactory createDefaultInstance(XPathEngine engine) {
129
        return new NodeAssertFactory(engine);
1✔
130
    }
131

132
    /**
133
     * This class should has delegate method with signature matching to type erasure AssertFactory class from AssertJ 3.13.0 or higher
134
     * which is `Assert createAssert(Object var1)`
135
     */
136
    static class NodeAssertFactoryDelegate {
137

138
        private final NodeAssertFactory delegate;
139

140
        private NodeAssertFactoryDelegate(NodeAssertFactory delegate) {
×
141
            this.delegate = delegate;
×
142
        }
×
143

144
        @SuppressWarnings("rawtypes")
145
        Assert delegate(Object obj) {
146
            return delegate.createAssert((Node) obj);
×
147
        }
148
    }
149
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc