Skip to content

Commit 6423f31

Browse files
Add support for all constraint types in ContextBuilder
Extend ContextBuilder to support the full set of constraint types: - IAllowedValuesConstraint (existing) - IMatchesConstraint (existing) - IExpectConstraint (existing) - IIndexHasKeyConstraint (existing) - ICardinalityConstraint (new) - IIndexConstraint (new) - IUniqueConstraint (new) Add comprehensive unit tests for each constraint type to verify the builder correctly constructs constraint sets with all supported constraint types.
1 parent bd0d18c commit 6423f31

File tree

2 files changed

+132
-5
lines changed

2 files changed

+132
-5
lines changed

core/src/test/java/gov/nist/secauto/metaschema/core/testsupport/builder/ContextBuilder.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010
import gov.nist.secauto.metaschema.core.model.constraint.AbstractConstraintBuilder;
1111
import gov.nist.secauto.metaschema.core.model.constraint.AssemblyConstraintSet;
1212
import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValuesConstraint;
13+
import gov.nist.secauto.metaschema.core.model.constraint.ICardinalityConstraint;
1314
import gov.nist.secauto.metaschema.core.model.constraint.IConstraint;
1415
import gov.nist.secauto.metaschema.core.model.constraint.IExpectConstraint;
16+
import gov.nist.secauto.metaschema.core.model.constraint.IIndexConstraint;
1517
import gov.nist.secauto.metaschema.core.model.constraint.IIndexHasKeyConstraint;
1618
import gov.nist.secauto.metaschema.core.model.constraint.IMatchesConstraint;
1719
import gov.nist.secauto.metaschema.core.model.constraint.IModelConstrained;
20+
import gov.nist.secauto.metaschema.core.model.constraint.IUniqueConstraint;
1821
import gov.nist.secauto.metaschema.core.model.constraint.MetaConstraintSet;
1922
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
2023

@@ -28,17 +31,17 @@
2831
/**
2932
* Implementation of {@link IContextBuilder} for creating constraint contexts.
3033
* <p>
31-
* This builder supports the following constraint types:
34+
* This builder supports all constraint types defined in the Metaschema
35+
* constraint model:
3236
* <ul>
3337
* <li>{@link IAllowedValuesConstraint}</li>
3438
* <li>{@link IMatchesConstraint}</li>
3539
* <li>{@link IExpectConstraint}</li>
3640
* <li>{@link IIndexHasKeyConstraint}</li>
41+
* <li>{@link ICardinalityConstraint}</li>
42+
* <li>{@link IIndexConstraint}</li>
43+
* <li>{@link IUniqueConstraint}</li>
3744
* </ul>
38-
* Other constraint types (such as {@code ICardinalityConstraint},
39-
* {@code IIndexConstraint}, or {@code IUniqueConstraint}) will throw an
40-
* {@link UnsupportedOperationException} when added. To support additional
41-
* constraint types, extend the {@link #addConstraint} method.
4245
*/
4346
public class ContextBuilder implements IContextBuilder {
4447
@NonNull
@@ -131,6 +134,7 @@ MetaConstraintSet.Context build(@Nullable MetaConstraintSet.Context parent) {
131134
* @throws UnsupportedOperationException
132135
* if the constraint type is not supported
133136
*/
137+
@SuppressWarnings("PMD.CyclomaticComplexity")
134138
private static void addConstraint(@NonNull IModelConstrained modelConstrained, @NonNull IConstraint constraint) {
135139
if (constraint instanceof IAllowedValuesConstraint) {
136140
modelConstrained.addConstraint((IAllowedValuesConstraint) constraint);
@@ -140,6 +144,12 @@ private static void addConstraint(@NonNull IModelConstrained modelConstrained, @
140144
modelConstrained.addConstraint((IExpectConstraint) constraint);
141145
} else if (constraint instanceof IIndexHasKeyConstraint) {
142146
modelConstrained.addConstraint((IIndexHasKeyConstraint) constraint);
147+
} else if (constraint instanceof ICardinalityConstraint) {
148+
modelConstrained.addConstraint((ICardinalityConstraint) constraint);
149+
} else if (constraint instanceof IIndexConstraint) {
150+
modelConstrained.addConstraint((IIndexConstraint) constraint);
151+
} else if (constraint instanceof IUniqueConstraint) {
152+
modelConstrained.addConstraint((IUniqueConstraint) constraint);
143153
} else {
144154
throw new UnsupportedOperationException(
145155
"Unsupported constraint type: " + constraint.getClass().getName());

core/src/test/java/gov/nist/secauto/metaschema/core/testsupport/tests/ConstraintSetBuilderTest.java

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@
1515
import gov.nist.secauto.metaschema.core.model.ISource;
1616
import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValue;
1717
import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValuesConstraint;
18+
import gov.nist.secauto.metaschema.core.model.constraint.ICardinalityConstraint;
1819
import gov.nist.secauto.metaschema.core.model.constraint.IConstraintSet;
20+
import gov.nist.secauto.metaschema.core.model.constraint.IExpectConstraint;
21+
import gov.nist.secauto.metaschema.core.model.constraint.IIndexConstraint;
22+
import gov.nist.secauto.metaschema.core.model.constraint.IIndexHasKeyConstraint;
23+
import gov.nist.secauto.metaschema.core.model.constraint.IKeyField;
1924
import gov.nist.secauto.metaschema.core.model.constraint.IMatchesConstraint;
25+
import gov.nist.secauto.metaschema.core.model.constraint.IUniqueConstraint;
2026
import gov.nist.secauto.metaschema.core.testsupport.MockedModelTestSupport;
2127
import gov.nist.secauto.metaschema.core.testsupport.builder.IConstraintSetBuilder;
2228

@@ -188,4 +194,115 @@ void testConstraintSetWithMultipleContexts() {
188194
assertNotNull(constraintSet, "Constraint set should not be null");
189195
assertEquals(source, constraintSet.getSource(), "Source should match");
190196
}
197+
198+
@Test
199+
void testConstraintSetWithExpectConstraint() {
200+
// Given
201+
MockedModelTestSupport mocking = new MockedModelTestSupport();
202+
ISource source = ISource.externalSource(URI.create(TEST_NAMESPACE));
203+
204+
// When
205+
IConstraintSet constraintSet = mocking.constraintSet()
206+
.source(source)
207+
.context(ctx -> ctx
208+
.metapath("//item")
209+
.constraint(IExpectConstraint.builder()
210+
.source(source)
211+
.target(IMetapathExpression.compile("."))
212+
.test(IMetapathExpression.compile("@id != ''"))))
213+
.build();
214+
215+
// Then
216+
assertNotNull(constraintSet, "Constraint set should not be null");
217+
assertEquals(source, constraintSet.getSource(), "Source should match");
218+
}
219+
220+
@Test
221+
void testConstraintSetWithCardinalityConstraint() {
222+
// Given
223+
MockedModelTestSupport mocking = new MockedModelTestSupport();
224+
ISource source = ISource.externalSource(URI.create(TEST_NAMESPACE));
225+
226+
// When
227+
IConstraintSet constraintSet = mocking.constraintSet()
228+
.source(source)
229+
.context(ctx -> ctx
230+
.metapath("//parent")
231+
.constraint(ICardinalityConstraint.builder()
232+
.source(source)
233+
.target(IMetapathExpression.compile("child"))
234+
.minOccurs(1)
235+
.maxOccurs(5)))
236+
.build();
237+
238+
// Then
239+
assertNotNull(constraintSet, "Constraint set should not be null");
240+
assertEquals(source, constraintSet.getSource(), "Source should match");
241+
}
242+
243+
@Test
244+
void testConstraintSetWithIndexConstraint() {
245+
// Given
246+
MockedModelTestSupport mocking = new MockedModelTestSupport();
247+
ISource source = ISource.externalSource(URI.create(TEST_NAMESPACE));
248+
249+
// When
250+
IConstraintSet constraintSet = mocking.constraintSet()
251+
.source(source)
252+
.context(ctx -> ctx
253+
.metapath("//items")
254+
.constraint(IIndexConstraint.builder("item-index")
255+
.source(source)
256+
.target(IMetapathExpression.compile("item"))
257+
.keyField(IKeyField.of(IMetapathExpression.compile("@id"), null, null))))
258+
.build();
259+
260+
// Then
261+
assertNotNull(constraintSet, "Constraint set should not be null");
262+
assertEquals(source, constraintSet.getSource(), "Source should match");
263+
}
264+
265+
@Test
266+
void testConstraintSetWithIndexHasKeyConstraint() {
267+
// Given
268+
MockedModelTestSupport mocking = new MockedModelTestSupport();
269+
ISource source = ISource.externalSource(URI.create(TEST_NAMESPACE));
270+
271+
// When
272+
IConstraintSet constraintSet = mocking.constraintSet()
273+
.source(source)
274+
.context(ctx -> ctx
275+
.metapath("//reference")
276+
.constraint(IIndexHasKeyConstraint.builder("item-index")
277+
.source(source)
278+
.target(IMetapathExpression.compile("."))
279+
.keyField(IKeyField.of(IMetapathExpression.compile("@item-ref"), null, null))))
280+
.build();
281+
282+
// Then
283+
assertNotNull(constraintSet, "Constraint set should not be null");
284+
assertEquals(source, constraintSet.getSource(), "Source should match");
285+
}
286+
287+
@Test
288+
void testConstraintSetWithUniqueConstraint() {
289+
// Given
290+
MockedModelTestSupport mocking = new MockedModelTestSupport();
291+
ISource source = ISource.externalSource(URI.create(TEST_NAMESPACE));
292+
293+
// When
294+
IConstraintSet constraintSet = mocking.constraintSet()
295+
.source(source)
296+
.context(ctx -> ctx
297+
.metapath("//collection")
298+
.constraint(IUniqueConstraint.builder()
299+
.source(source)
300+
.target(IMetapathExpression.compile("entry"))
301+
.keyField(IKeyField.of(IMetapathExpression.compile("@key"), null, null))))
302+
.build();
303+
304+
// Then
305+
assertNotNull(constraintSet, "Constraint set should not be null");
306+
assertEquals(source, constraintSet.getSource(), "Source should match");
307+
}
191308
}

0 commit comments

Comments
 (0)