diff --git a/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/AbstractValidator.java b/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/AbstractValidator.java index 1c560d849c..d45f7d4948 100644 --- a/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/AbstractValidator.java +++ b/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/AbstractValidator.java @@ -22,6 +22,7 @@ import com.mastercard.test.flow.validation.check.InteractionIdentityCheck; import com.mastercard.test.flow.validation.check.MessageSharingCheck; import com.mastercard.test.flow.validation.check.ModelTaggingCheck; +import com.mastercard.test.flow.validation.check.ModelUniquenessCheck; import com.mastercard.test.flow.validation.check.ReflectiveModelTaggingCheck; import com.mastercard.test.flow.validation.check.ResultTagCheck; import com.mastercard.test.flow.validation.check.TraceUniquenessCheck; @@ -49,6 +50,7 @@ public static final Validation[] defaultChecks() { new InteractionIdentityCheck(), new MessageSharingCheck(), new ModelTaggingCheck(), + new ModelUniquenessCheck(), new ReflectiveModelTaggingCheck(), new ResultTagCheck(), new TraceUniquenessCheck(), diff --git a/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/check/ModelTaggingCheck.java b/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/check/ModelTaggingCheck.java index 7f322445d2..13bb8b0138 100644 --- a/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/check/ModelTaggingCheck.java +++ b/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/check/ModelTaggingCheck.java @@ -69,10 +69,10 @@ private List buildChecks( Model model, List checks ) { } ); flowUnionTags.removeAll( flowIntersectionTags ); - String expected = flowsFound.get() + String actual = flowsFound.get() ? formatCopypasta( flowUnionTags, flowIntersectionTags ) : "null;"; - String actual = Optional.ofNullable( model.tags() ) + String expected = Optional.ofNullable( model.tags() ) .map( mt -> { Set modelUnionTags = mt.union() .collect( Collectors.toCollection( TreeSet::new ) ); @@ -83,8 +83,9 @@ private List buildChecks( Model model, List checks ) { } ) .orElse( "null;" ); - if( !expected.equals( actual ) ) { - return new Violation( this, "Inaccurate tagging", expected, actual ); + if( !actual.equals( expected ) ) { + return new Violation( this, "Inaccurate tagging in model: " + model.title(), expected, + actual ); } return null; diff --git a/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/check/ModelUniquenessCheck.java b/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/check/ModelUniquenessCheck.java new file mode 100644 index 0000000000..161bdf132a --- /dev/null +++ b/validation/validation-core/src/main/java/com/mastercard/test/flow/validation/check/ModelUniquenessCheck.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 Mastercard. All rights reserved. + */ + +package com.mastercard.test.flow.validation.check; + +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; + +import com.mastercard.test.flow.Model; +import com.mastercard.test.flow.validation.Check; +import com.mastercard.test.flow.validation.Validation; +import com.mastercard.test.flow.validation.Violation; + +/** + * Checks that all {@link Model} have a unique title + */ +public final class ModelUniquenessCheck implements Validation { + @Override + public String name() { + return "Model uniqueness"; + } + + @Override + public String explanation() { + return "Models should be uniquely identified by its title"; + } + + @Override + public Stream checks( Model model ) { + Set modelTitles = new HashSet<>(); + return checkModelTitles( model, modelTitles ).stream(); + } + + private Set checkModelTitles( Model model, Set modelTitles ) { + Set checks = new HashSet<>(); + if( !modelTitles.add( model.title() ) ) { + checks.add( new Check( this, model.title(), + () -> new Violation( this, "Duplicate model title found: " + model.title() ) ) ); + } + model.subModels() + .forEach( subModel -> checks.addAll( checkModelTitles( subModel, modelTitles ) ) ); + return checks; + } +} diff --git a/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/AbstractValidatorTest.java b/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/AbstractValidatorTest.java index fde0bd9290..6030687b17 100644 --- a/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/AbstractValidatorTest.java +++ b/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/AbstractValidatorTest.java @@ -44,6 +44,7 @@ void with() { + "Interaction Identity\n" + "Message sharing\n" + "Model tagging\n" + + "Model uniqueness\n" + "Reflective model tagging\n" + "Result tag misuse\n" + "Trace uniqueness", diff --git a/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/check/ModelTaggingCheckTest.java b/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/check/ModelTaggingCheckTest.java index 0569fdde64..8942c3160c 100644 --- a/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/check/ModelTaggingCheckTest.java +++ b/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/check/ModelTaggingCheckTest.java @@ -65,27 +65,27 @@ void violation() { test( leaf( "empty model tags", null, "a,b,c" ), - " details: Inaccurate tagging\n" - + " expected: new TaggedGroup(\"a\", \"b\", \"c\");\n" - + " actual: null;\n" + " details: Inaccurate tagging in model: empty model tags\n" + + " expected: null;\n" + + " actual: new TaggedGroup(\"a\", \"b\", \"c\");\n" + "offenders: " ); test( leaf( "empty flow tags", new TaggedGroup( "a", "b", "c" ).union( "d" ) ), - " details: Inaccurate tagging\n" - + " expected: null;\n" - + " actual: new TaggedGroup(\"a\", \"b\", \"c\")\n" + " details: Inaccurate tagging in model: empty flow tags\n" + + " expected: new TaggedGroup(\"a\", \"b\", \"c\")\n" + " .union(\"d\");\n" + + " actual: null;\n" + "offenders: " ); test( leaf( "mismatch", new TaggedGroup( "a", "b", "c" ).union( "d" ), "a,b,c", "b,c,d" ), - " details: Inaccurate tagging\n" - + " expected: new TaggedGroup(\"b\", \"c\")\n" - + " .union(\"a\", \"d\");\n" - + " actual: new TaggedGroup(\"a\", \"b\", \"c\")\n" + " details: Inaccurate tagging in model: mismatch\n" + + " expected: new TaggedGroup(\"a\", \"b\", \"c\")\n" + " .union(\"d\");\n" + + " actual: new TaggedGroup(\"b\", \"c\")\n" + + " .union(\"a\", \"d\");\n" + "offenders: " ); } @@ -99,15 +99,15 @@ void recursiveViolation() { leaf( "left", new TaggedGroup( "a", "b" ), "a,b" ), leaf( "right", new TaggedGroup( "b", "c" ), "b,c,d" ) ), "left : pass", - " details: Inaccurate tagging\n" - + " expected: new TaggedGroup(\"b\", \"c\", \"d\");\n" - + " actual: new TaggedGroup(\"b\", \"c\");\n" + " details: Inaccurate tagging in model: right\n" + + " expected: new TaggedGroup(\"b\", \"c\");\n" + + " actual: new TaggedGroup(\"b\", \"c\", \"d\");\n" + "offenders: ", - " details: Inaccurate tagging\n" + " details: Inaccurate tagging in model: branch\n" + " expected: new TaggedGroup(\"b\")\n" - + " .union(\"a\", \"c\", \"d\");\n" - + " actual: new TaggedGroup(\"b\")\n" + " .union(\"a\", \"c\", \"x\");\n" + + " actual: new TaggedGroup(\"b\")\n" + + " .union(\"a\", \"c\", \"d\");\n" + "offenders: " ); } diff --git a/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/check/ModelUniquenessCheckTest.java b/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/check/ModelUniquenessCheckTest.java new file mode 100644 index 0000000000..4fad583382 --- /dev/null +++ b/validation/validation-core/src/test/java/com/mastercard/test/flow/validation/check/ModelUniquenessCheckTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 Mastercard. All rights reserved. + */ + +package com.mastercard.test.flow.validation.check; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.mastercard.test.flow.Model; + +/** + * Exercises {@link ModelUniquenessCheck} + */ +class ModelUniquenessCheckTest extends AbstractValidationTest { + + ModelUniquenessCheckTest() { + super( new ModelUniquenessCheck(), "Model uniqueness", + "Models should be uniquely identified by its title" ); + } + + private List createMockModels( List titles ) { + return titles.stream().map( title -> { + Model model = mock( Model.class ); + when( model.title() ).thenReturn( title ); + when( model.subModels() ).thenReturn( Stream.empty() ); + return model; + } ).collect( Collectors.toList() ); + } + + @Test + void testModelUniquenessFailureAssertion() { + // Create a list of model titles + List titles = Arrays.asList( "Model1", "Model2", "Model1" ); + + // Create mock models + List models = createMockModels( titles ); + + // Create a parent model and set its subModels + Model parentModel = mock( Model.class ); + when( parentModel.title() ).thenReturn( "ParentModel" ); + when( parentModel.subModels() ).thenReturn( models.stream() ); + + test( parentModel, " details: Duplicate model title found: Model1\n" + + " expected: null\n" + + " actual: null\n" + + "offenders: " ); + + } + + @Test + void testModelUniquenessSuccessAssertion() { + // Create a list of model titles + List titles = Arrays.asList( "Model1", "Model2", "Model3" ); + + // Create mock models + List models = createMockModels( titles ); + + // Create a parent model and set its subModels + Model parentModel = mock( Model.class ); + when( parentModel.title() ).thenReturn( "ParentModel" ); + when( parentModel.subModels() ).thenReturn( models.stream() ); + + test( parentModel ); + + } + +}