diff --git a/common/src/main/java/com/scottlogic/deg/common/profile/Field.java b/common/src/main/java/com/scottlogic/deg/common/profile/Field.java index 296815085..183da847e 100644 --- a/common/src/main/java/com/scottlogic/deg/common/profile/Field.java +++ b/common/src/main/java/com/scottlogic/deg/common/profile/Field.java @@ -23,12 +23,18 @@ public class Field { public final Types type; private final boolean unique; private final String formatting; + private final boolean internal; - public Field(String name, Types type, Boolean unique, String formatting) { + public Field(String name, Types type, boolean unique, String formatting, boolean internal) { this.name = name; this.type = type; this.unique = unique; this.formatting = formatting; + this.internal = internal; + } + + public boolean isInternal() { + return internal; } public boolean isUnique() { diff --git a/common/src/main/java/com/scottlogic/deg/common/profile/ProfileFields.java b/common/src/main/java/com/scottlogic/deg/common/profile/ProfileFields.java index bd8e314a9..34eb9bfeb 100644 --- a/common/src/main/java/com/scottlogic/deg/common/profile/ProfileFields.java +++ b/common/src/main/java/com/scottlogic/deg/common/profile/ProfileFields.java @@ -49,6 +49,10 @@ public Stream stream() { return this.fields.stream(); } + public Stream getExternalStream() { + return this.stream().filter(f -> !f.isInternal()); + } + public List asList() { return fields; } diff --git a/common/src/main/java/com/scottlogic/deg/common/profile/constraints/atomic/IsInMapConstraint.java b/common/src/main/java/com/scottlogic/deg/common/profile/constraints/atomic/IsInMapConstraint.java new file mode 100644 index 000000000..b686162a5 --- /dev/null +++ b/common/src/main/java/com/scottlogic/deg/common/profile/constraints/atomic/IsInMapConstraint.java @@ -0,0 +1,74 @@ +/* + * Copyright 2019 Scott Logic Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.scottlogic.deg.common.profile.constraints.atomic; + +import com.scottlogic.deg.common.profile.Field; +import com.scottlogic.deg.generator.fieldspecs.whitelist.DistributedList; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class IsInMapConstraint implements AtomicConstraint { + public final Field field; + public final DistributedList legalValues; + + public IsInMapConstraint(Field field, DistributedList legalValues) { + this.field = field; + this.legalValues = legalValues; + + if (legalValues.distributedList().isEmpty()) { + throw new IllegalArgumentException("Cannot create an IsInMapConstraint for field '" + + field.name + "' with an empty set."); + } + + if (legalValues.list().contains(null)) { + throw new IllegalArgumentException("Cannot create an IsInMapConstraint for field '" + + field.name + "' with a list containing null."); + } + } + + @Override + public Field getField() { + return field; + } + + public String toString(){ + boolean overLimit = legalValues.list().size() > 3; + return String.format("%s in [%s%s](%d values)", + field.name, + legalValues.stream().limit(3).map(Object::toString).collect(Collectors.joining(", ")), + overLimit ? ", ..." : "", + legalValues.list().size()); + } + + @Override + public boolean equals(Object o){ + if (this == o) return true; + if (o instanceof ViolatedAtomicConstraint) { + return o.equals(this); + } + if (o == null || getClass() != o.getClass()) return false; + IsInMapConstraint constraint = (IsInMapConstraint) o; + return Objects.equals(field, constraint.field) && Objects.equals(legalValues, constraint.legalValues); + } + + @Override + public int hashCode(){ + return Objects.hash(field, legalValues); + } +} diff --git a/common/src/test/java/com/scottlogic/deg/common/profile/FieldBuilder.java b/common/src/test/java/com/scottlogic/deg/common/profile/FieldBuilder.java index 4fa7066ee..59e068713 100644 --- a/common/src/test/java/com/scottlogic/deg/common/profile/FieldBuilder.java +++ b/common/src/test/java/com/scottlogic/deg/common/profile/FieldBuilder.java @@ -20,7 +20,10 @@ public class FieldBuilder { public static Field createField(String name) { return createField(name, Types.STRING); } + public static Field createInternalField(String name) { + return new Field(name, Types.STRING, false, null, true); + } public static Field createField(String name, Types type) { - return new Field(name, type, false, null); + return new Field(name, type, false, null, false); } } diff --git a/common/src/test/java/com/scottlogic/deg/common/profile/constraints/atomic/IsInMapConstraintTests.java b/common/src/test/java/com/scottlogic/deg/common/profile/constraints/atomic/IsInMapConstraintTests.java new file mode 100644 index 000000000..921a19fe3 --- /dev/null +++ b/common/src/test/java/com/scottlogic/deg/common/profile/constraints/atomic/IsInMapConstraintTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019 Scott Logic Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.scottlogic.deg.common.profile.constraints.atomic; + +import com.scottlogic.deg.common.profile.Field; +import com.scottlogic.deg.generator.fieldspecs.whitelist.DistributedList; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static com.scottlogic.deg.common.profile.FieldBuilder.createField; + +public class IsInMapConstraintTests { + + @Test + public void testConstraintThrowsIfGivenEmptySet(){ + Field field1 = createField("TestField"); + + Assertions.assertThrows( + IllegalArgumentException.class, + () -> new IsInMapConstraint(field1, DistributedList.empty())); + } + + @Test + public void testConstraintThrowsIfGivenNullInASet(){ + Field field1 = createField("TestField"); + + Assertions.assertThrows( + IllegalArgumentException.class, + () -> new IsInMapConstraint(field1, DistributedList.singleton(null))); + } + + @Test + public void testConstraintThrowsNothingIfGivenAValidSet(){ + Field field1 = createField("TestField"); + Assertions.assertDoesNotThrow( + () -> new IsInMapConstraint(field1, DistributedList.singleton("foo"))); + } + +} diff --git a/generator/src/main/java/com/scottlogic/deg/generator/fieldspecs/FieldSpecFactory.java b/generator/src/main/java/com/scottlogic/deg/generator/fieldspecs/FieldSpecFactory.java index 1c08248dd..e08efeff2 100644 --- a/generator/src/main/java/com/scottlogic/deg/generator/fieldspecs/FieldSpecFactory.java +++ b/generator/src/main/java/com/scottlogic/deg/generator/fieldspecs/FieldSpecFactory.java @@ -52,6 +52,8 @@ private FieldSpec construct(AtomicConstraint constraint, boolean negate) { return construct(((NotConstraint) constraint).negatedConstraint, !negate); } else if (constraint instanceof IsInSetConstraint) { return construct((IsInSetConstraint) constraint, negate); + } else if (constraint instanceof IsInMapConstraint) { + return construct((IsInMapConstraint) constraint, negate); } else if (constraint instanceof EqualToConstraint) { return construct((EqualToConstraint) constraint, negate); } else if (constraint instanceof IsGreaterThanConstantConstraint) { @@ -101,6 +103,14 @@ private FieldSpec construct(IsInSetConstraint constraint, boolean negate) { return FieldSpec.fromList(constraint.legalValues); } + private FieldSpec construct(IsInMapConstraint constraint, boolean negate) { + if (negate) { + throw new UnsupportedOperationException("negation of inMap not supported"); + } + + return FieldSpec.fromList(constraint.legalValues); + } + private FieldSpec construct(EqualToConstraint constraint, boolean negate) { if (negate) { return FieldSpec.empty().withBlacklist(Collections.singleton(constraint.value)); diff --git a/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/ProfileViolator.java b/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/ProfileViolator.java deleted file mode 100644 index d4dedfd7e..000000000 --- a/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/ProfileViolator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2019 Scott Logic Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.scottlogic.deg.generator.inputs.profileviolation; - -import com.scottlogic.deg.common.profile.Profile; -import com.scottlogic.deg.common.profile.ViolatedProfile; - -import java.io.IOException; -import java.util.List; - -/** - * Defines an interface for a profile validator, a class which has a - * specific implementation of how to violate an input profile object. - */ -public interface ProfileViolator { - /** - * Violate takes a profile and produces a list of violated profiles - * according to the violator's specific violation rules. - * @param profile Input profile. - * @return List of profile objects that represent the multiple violations. - */ - List violate(Profile profile) throws IOException; -} diff --git a/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/RuleViolator.java b/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/RuleViolator.java deleted file mode 100644 index d674598b2..000000000 --- a/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/RuleViolator.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2019 Scott Logic Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.scottlogic.deg.generator.inputs.profileviolation; - -import com.scottlogic.deg.common.profile.Rule; - -public interface RuleViolator { - /** - * Given a rule will produce a violated version of this same rule. - * @param rule Input rule to be violated - * @return Violated version of the rule. - */ - Rule violateRule(Rule rule); -} diff --git a/generator/src/test/java/com/scottlogic/deg/generator/generation/FieldSpecValueGeneratorTests.java b/generator/src/test/java/com/scottlogic/deg/generator/generation/FieldSpecValueGeneratorTests.java index ba01e38b8..769d7bf54 100644 --- a/generator/src/test/java/com/scottlogic/deg/generator/generation/FieldSpecValueGeneratorTests.java +++ b/generator/src/test/java/com/scottlogic/deg/generator/generation/FieldSpecValueGeneratorTests.java @@ -121,7 +121,7 @@ void generateRandom_uniqueFieldSpec_returnsAllValues() { randomNumberGenerator ); - fieldSpecFulfiller.generate(new Field(null, Types.STRING, true, null), fieldSpec).collect(Collectors.toSet()); + fieldSpecFulfiller.generate(new Field(null, Types.STRING, true, null, false), fieldSpec).collect(Collectors.toSet()); verify(fieldValueSource, times(1)).generateAllValues(); verify(fieldValueSource, times(0)).generateInterestingValues(); @@ -155,7 +155,7 @@ void generateInteresting_uniqueFieldSpec_returnsAllValues() { randomNumberGenerator ); - fieldSpecFulfiller.generate(new Field(null, STRING, true, null), fieldSpec).collect(Collectors.toSet()); + fieldSpecFulfiller.generate(new Field(null, STRING, true, null, false), fieldSpec).collect(Collectors.toSet()); verify(fieldValueSource, times(1)).generateAllValues(); verify(fieldValueSource, times(0)).generateInterestingValues(); diff --git a/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/generate/GenerateCommandLine.java b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/generate/GenerateCommandLine.java index 1cc398d8e..72894f9c8 100644 --- a/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/generate/GenerateCommandLine.java +++ b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/generate/GenerateCommandLine.java @@ -159,7 +159,7 @@ public boolean useStdOut() { @Override public boolean useNdJson() { - return (ndjson == null && this.useStdOut()) || ndjson; + return ndjson == null ? this.useStdOut() : ndjson; } @Override diff --git a/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolateExecute.java b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolateExecute.java index 80346f404..65743f5c3 100644 --- a/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolateExecute.java +++ b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolateExecute.java @@ -19,12 +19,11 @@ import com.google.inject.Inject; import com.scottlogic.deg.common.output.GeneratedObject; import com.scottlogic.deg.common.profile.Profile; -import com.scottlogic.deg.common.profile.ViolatedProfile; import com.scottlogic.deg.generator.generation.DataGenerator; -import com.scottlogic.deg.generator.inputs.profileviolation.ProfileViolator; +import com.scottlogic.deg.orchestrator.violate.violator.ProfileViolator; import com.scottlogic.deg.generator.inputs.validation.ProfileValidator; import com.scottlogic.deg.common.util.FileUtils; -import com.scottlogic.deg.output.manifest.ManifestWriter; +import com.scottlogic.deg.orchestrator.violate.manifest.ManifestWriter; import com.scottlogic.deg.output.outputtarget.OutputTargetFactory; import com.scottlogic.deg.output.outputtarget.SingleDatasetOutputTarget; import com.scottlogic.deg.output.writer.DataSetWriter; diff --git a/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolateModule.java b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolateModule.java index 17e7431c0..1a92d93f2 100644 --- a/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolateModule.java +++ b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolateModule.java @@ -19,14 +19,9 @@ import com.google.inject.AbstractModule; import com.google.inject.TypeLiteral; import com.scottlogic.deg.orchestrator.guice.AllConfigSource; -import com.scottlogic.deg.generator.guice.GeneratorModule; -import com.scottlogic.deg.generator.inputs.profileviolation.IndividualConstraintRuleViolator; -import com.scottlogic.deg.generator.inputs.profileviolation.IndividualRuleProfileViolator; -import com.scottlogic.deg.generator.inputs.profileviolation.ProfileViolator; -import com.scottlogic.deg.generator.inputs.profileviolation.RuleViolator; +import com.scottlogic.deg.orchestrator.violate.violator.RuleViolator; import com.scottlogic.deg.generator.violations.filters.ViolationFilter; import com.scottlogic.deg.orchestrator.guice.AllModule; -import com.scottlogic.deg.profile.guice.ProfileModule; import java.util.List; @@ -42,9 +37,6 @@ protected void configure() { bind(AllConfigSource.class).toInstance(configSource); bind(ViolateConfigSource.class).toInstance(configSource); - bind(ProfileViolator.class).to(IndividualRuleProfileViolator.class); - bind(RuleViolator.class).to(IndividualConstraintRuleViolator.class); - bind(new TypeLiteral>(){}).toProvider(ViolationFiltersProvider.class); install(new AllModule(configSource)); diff --git a/common/src/main/java/com/scottlogic/deg/common/profile/ViolatedProfile.java b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolatedProfile.java similarity index 87% rename from common/src/main/java/com/scottlogic/deg/common/profile/ViolatedProfile.java rename to orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolatedProfile.java index b118d7489..584996c1b 100644 --- a/common/src/main/java/com/scottlogic/deg/common/profile/ViolatedProfile.java +++ b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/ViolatedProfile.java @@ -14,7 +14,11 @@ * limitations under the License. */ -package com.scottlogic.deg.common.profile; +package com.scottlogic.deg.orchestrator.violate; + +import com.scottlogic.deg.common.profile.Profile; +import com.scottlogic.deg.common.profile.ProfileFields; +import com.scottlogic.deg.common.profile.Rule; import java.util.Collection; diff --git a/output/src/main/java/com/scottlogic/deg/output/manifest/ManifestDTO.java b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/manifest/ManifestDTO.java similarity index 95% rename from output/src/main/java/com/scottlogic/deg/output/manifest/ManifestDTO.java rename to orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/manifest/ManifestDTO.java index 9a92d5325..059ac7c4c 100644 --- a/output/src/main/java/com/scottlogic/deg/output/manifest/ManifestDTO.java +++ b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/manifest/ManifestDTO.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.scottlogic.deg.output.manifest; +package com.scottlogic.deg.orchestrator.violate.manifest; import java.util.Collection; diff --git a/output/src/main/java/com/scottlogic/deg/output/manifest/JsonManifestWriter.java b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/manifest/ManifestWriter.java similarity index 91% rename from output/src/main/java/com/scottlogic/deg/output/manifest/JsonManifestWriter.java rename to orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/manifest/ManifestWriter.java index ed0bfb34b..f8382a93d 100644 --- a/output/src/main/java/com/scottlogic/deg/output/manifest/JsonManifestWriter.java +++ b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/manifest/ManifestWriter.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.scottlogic.deg.output.manifest; +package com.scottlogic.deg.orchestrator.violate.manifest; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Charsets; import com.google.inject.Inject; -import com.scottlogic.deg.common.profile.ViolatedProfile; +import com.scottlogic.deg.orchestrator.violate.ViolatedProfile; import com.scottlogic.deg.common.util.FileUtils; import com.scottlogic.deg.output.OutputPath; @@ -36,11 +36,11 @@ * write out a JSON manifest file during violation. * This file shows which rule has been violated in which output file. */ -public class JsonManifestWriter implements ManifestWriter { +public class ManifestWriter { private final Path outputPath; @Inject - public JsonManifestWriter(OutputPath outputPath){ + public ManifestWriter(OutputPath outputPath){ this.outputPath = outputPath.getPath(); } diff --git a/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualRuleProfileViolator.java b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/violator/ProfileViolator.java similarity index 92% rename from generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualRuleProfileViolator.java rename to orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/violator/ProfileViolator.java index 943a41dce..b4a71935d 100644 --- a/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualRuleProfileViolator.java +++ b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/violator/ProfileViolator.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.scottlogic.deg.generator.inputs.profileviolation; +package com.scottlogic.deg.orchestrator.violate.violator; import com.google.inject.Inject; import com.scottlogic.deg.common.profile.Profile; import com.scottlogic.deg.common.profile.Rule; -import com.scottlogic.deg.common.profile.ViolatedProfile; +import com.scottlogic.deg.orchestrator.violate.ViolatedProfile; import java.io.IOException; import java.util.ArrayList; @@ -32,12 +32,12 @@ * Within each violated ruleInformation we violate each constraint independently. This is consistent with the current * implementation of violation. */ -public class IndividualRuleProfileViolator implements ProfileViolator { +public class ProfileViolator { private final RuleViolator ruleViolator; @Inject - public IndividualRuleProfileViolator(RuleViolator ruleViolator) { + public ProfileViolator(RuleViolator ruleViolator) { this.ruleViolator = ruleViolator; } @@ -52,7 +52,6 @@ public IndividualRuleProfileViolator(RuleViolator ruleViolator) { * @return List of profiles each with a different rule violated. * @throws IOException if the manifest writer fails to write */ - @Override public List violate(Profile profile) throws IOException { // For each rule in the profile generate a profile with this one rule violated List violatedProfiles = diff --git a/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualConstraintRuleViolator.java b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/violator/RuleViolator.java similarity index 96% rename from generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualConstraintRuleViolator.java rename to orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/violator/RuleViolator.java index b116c71ac..d8b17d0e6 100644 --- a/generator/src/main/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualConstraintRuleViolator.java +++ b/orchestrator/src/main/java/com/scottlogic/deg/orchestrator/violate/violator/RuleViolator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.scottlogic.deg.generator.inputs.profileviolation; +package com.scottlogic.deg.orchestrator.violate.violator; import com.google.inject.Inject; import com.scottlogic.deg.common.profile.constraints.grammatical.AndConstraint; @@ -37,15 +37,14 @@ * Rule violator which violates rules by individually violating each constraint within the rule. * I.E. VIOLATE(A,B,C) => VIOLATE(A),B,C OR A,VIOLATE(B),C OR A,B,VIOLATE(C) */ -public class IndividualConstraintRuleViolator implements RuleViolator { +public class RuleViolator { private final List constraintsToNotViolate; @Inject - public IndividualConstraintRuleViolator(List constraintsToNotViolate) { + public RuleViolator(List constraintsToNotViolate) { this.constraintsToNotViolate = constraintsToNotViolate; } - @Override public Rule violateRule(Rule rule) { List newConstraints = new ArrayList<>(); List violate = new ArrayList<>(); diff --git a/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/cucumber/testframework/utils/CucumberTestModule.java b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/cucumber/testframework/utils/CucumberTestModule.java index 92c72d0fc..27f11e383 100644 --- a/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/cucumber/testframework/utils/CucumberTestModule.java +++ b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/cucumber/testframework/utils/CucumberTestModule.java @@ -17,16 +17,14 @@ package com.scottlogic.deg.orchestrator.cucumber.testframework.utils; import com.google.inject.AbstractModule; -import com.scottlogic.deg.generator.decisiontree.DecisionTreeFactory; import com.scottlogic.deg.generator.generation.DataGenerator; import com.scottlogic.deg.generator.generation.GenerationConfigSource; import com.scottlogic.deg.generator.generation.NoopDataGeneratorMonitor; import com.scottlogic.deg.generator.generation.AbstractDataGeneratorMonitor; -import com.scottlogic.deg.generator.inputs.validation.MultipleProfileValidator; import com.scottlogic.deg.generator.inputs.validation.ProfileValidator; import com.scottlogic.deg.generator.inputs.validation.UniquenessValidator; import com.scottlogic.deg.generator.validators.ErrorReporter; -import com.scottlogic.deg.output.manifest.ManifestWriter; +import com.scottlogic.deg.orchestrator.violate.manifest.ManifestWriter; import com.scottlogic.deg.output.outputtarget.OutputTargetFactory; import com.scottlogic.deg.output.outputtarget.SingleDatasetOutputTarget; import com.scottlogic.deg.profile.reader.ProfileReader; @@ -34,8 +32,6 @@ import com.scottlogic.deg.profile.dto.NoopVersionChecker; import com.scottlogic.deg.profile.dto.SchemaVersionValidator; -import java.util.ArrayList; -import java.util.Collection; import java.util.stream.Stream; import static org.mockito.Matchers.any; diff --git a/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/cucumber/testframework/utils/CucumberTestState.java b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/cucumber/testframework/utils/CucumberTestState.java index 24c3cc719..d91e9c518 100644 --- a/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/cucumber/testframework/utils/CucumberTestState.java +++ b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/cucumber/testframework/utils/CucumberTestState.java @@ -122,7 +122,7 @@ private Collection getSetValues(List values) { } public void addField(String fieldName) { - this.profileFields.add(new Field(fieldName, null, false, null)); + this.profileFields.add(createField(fieldName, null)); } public void addException(Exception e){ @@ -176,7 +176,7 @@ public void setFieldUnique(String fieldName) { .findFirst() .orElseThrow(UnsupportedOperationException::new); - Field newField = new Field(oldField.name, oldField.type, true, oldField.getFormatting()); + Field newField = new Field(oldField.name, oldField.type, true, oldField.getFormatting(), oldField.isInternal()); profileFields.remove(oldField); profileFields.add(newField); @@ -188,7 +188,7 @@ public void setFieldType(String fieldName, Types types) { .findFirst() .orElseThrow(UnsupportedOperationException::new); - Field newField = new Field(oldField.name, types, oldField.isUnique(), oldField.getFormatting()); + Field newField = new Field(oldField.name, types, oldField.isUnique(), oldField.getFormatting(), oldField.isInternal()); profileFields.remove(oldField); profileFields.add(newField); @@ -200,7 +200,7 @@ public void setFieldFormatting(String fieldName, String formatting) { .findFirst() .orElseThrow(UnsupportedOperationException::new); - Field newField = new Field(oldField.name, oldField.type, oldField.isUnique(), formatting); + Field newField = new Field(oldField.name, oldField.type, oldField.isUnique(), formatting, oldField.isInternal()); profileFields.remove(oldField); profileFields.add(newField); diff --git a/generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/ProfileViolationTests.java b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/ProfileViolationTests.java similarity index 99% rename from generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/ProfileViolationTests.java rename to orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/ProfileViolationTests.java index 37f05eaa5..990f665b9 100644 --- a/generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/ProfileViolationTests.java +++ b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/ProfileViolationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.scottlogic.deg.generator.inputs.profileviolation; +package com.scottlogic.deg.orchestrator.violate.violator; import com.scottlogic.deg.common.profile.*; import com.scottlogic.deg.common.profile.constraints.atomic.*; @@ -28,6 +28,7 @@ import com.scottlogic.deg.generator.fieldspecs.whitelist.WeightedElement; import com.scottlogic.deg.generator.violations.filters.ConstraintTypeViolationFilter; import com.scottlogic.deg.generator.violations.filters.ViolationFilter; +import com.scottlogic.deg.orchestrator.violate.ViolatedProfile; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -44,14 +45,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.scottlogic.deg.generator.inputs.profileviolation.TypeEqualityHelper.assertProfileListsAreEquivalent; +import static com.scottlogic.deg.orchestrator.violate.violator.TypeEqualityHelper.assertProfileListsAreEquivalent; import static com.scottlogic.deg.common.profile.FieldBuilder.createField; /** * Defines tests for all business logic involved in Profile Violation. */ public class ProfileViolationTests { - private IndividualRuleProfileViolator profileViolator; + private ProfileViolator profileViolator; private ArrayList constraintsToNotViolate; private Field field1; @@ -165,8 +166,8 @@ public void setUp() throws IOException { MockitoAnnotations.initMocks(this); constraintsToNotViolate = new ArrayList<>(); - IndividualConstraintRuleViolator ruleViolator = new IndividualConstraintRuleViolator(constraintsToNotViolate); - profileViolator = new IndividualRuleProfileViolator(ruleViolator); + RuleViolator ruleViolator = new RuleViolator(constraintsToNotViolate); + profileViolator = new ProfileViolator(ruleViolator); field1 = createField("field1"); field2 = createField("field2"); field3 = createField("field3"); diff --git a/generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualRuleProfileViolatorTests.java b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/ProfileViolatorTests.java similarity index 94% rename from generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualRuleProfileViolatorTests.java rename to orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/ProfileViolatorTests.java index 203f36761..7560c9479 100644 --- a/generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualRuleProfileViolatorTests.java +++ b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/ProfileViolatorTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.scottlogic.deg.generator.inputs.profileviolation; +package com.scottlogic.deg.orchestrator.violate.violator; import com.scottlogic.deg.common.profile.Field; import com.scottlogic.deg.common.profile.Profile; @@ -24,7 +24,7 @@ import com.scottlogic.deg.common.profile.constraints.atomic.IsGreaterThanConstantConstraint; import com.scottlogic.deg.common.profile.constraints.atomic.IsLessThanConstantConstraint; import com.scottlogic.deg.common.profile.RuleInformation; -import com.scottlogic.deg.common.profile.ViolatedProfile; +import com.scottlogic.deg.orchestrator.violate.ViolatedProfile; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; @@ -36,15 +36,15 @@ import java.util.Collections; import java.util.List; -import static com.scottlogic.deg.generator.inputs.profileviolation.TypeEqualityHelper.assertListProfileTypeEquality; +import static com.scottlogic.deg.orchestrator.violate.violator.TypeEqualityHelper.assertListProfileTypeEquality; import static com.shazam.shazamcrest.MatcherAssert.assertThat; import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; import static org.mockito.Mockito.*; import static com.scottlogic.deg.common.profile.FieldBuilder.createField; -public class IndividualRuleProfileViolatorTests { +public class ProfileViolatorTests { - private IndividualRuleProfileViolator target; + private ProfileViolator target; @Mock private RuleViolator mockRuleViolator; @@ -59,7 +59,7 @@ public class IndividualRuleProfileViolatorTests { public void setUp() { MockitoAnnotations.initMocks(this); - target = new IndividualRuleProfileViolator( + target = new ProfileViolator( mockRuleViolator ); diff --git a/generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualConstraintRuleViolatorTests.java b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/RuleViolatorTests.java similarity index 97% rename from generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualConstraintRuleViolatorTests.java rename to orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/RuleViolatorTests.java index 68bdbbd76..f43e06206 100644 --- a/generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/IndividualConstraintRuleViolatorTests.java +++ b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/RuleViolatorTests.java @@ -14,12 +14,11 @@ * limitations under the License. */ -package com.scottlogic.deg.generator.inputs.profileviolation; +package com.scottlogic.deg.orchestrator.violate.violator; import com.scottlogic.deg.common.profile.constraints.grammatical.AndConstraint; import com.scottlogic.deg.common.profile.constraints.grammatical.ConditionalConstraint; import com.scottlogic.deg.common.profile.constraints.grammatical.OrConstraint; -import com.scottlogic.deg.common.profile.Field; import com.scottlogic.deg.common.profile.Rule; import com.scottlogic.deg.common.profile.constraints.Constraint; import com.scottlogic.deg.common.profile.constraintdetail.UnviolatableConstraintException; @@ -38,7 +37,7 @@ import java.math.BigDecimal; import java.util.*; -import static com.scottlogic.deg.generator.inputs.profileviolation.TypeEqualityHelper.assertRuleTypeEquality; +import static com.scottlogic.deg.orchestrator.violate.violator.TypeEqualityHelper.assertRuleTypeEquality; import static com.shazam.shazamcrest.MatcherAssert.assertThat; import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -47,11 +46,11 @@ import static com.scottlogic.deg.common.profile.FieldBuilder.createField; /** - * Tests the behaviour of the IndividualConstraintRuleViolator class. + * Tests the behaviour of the RuleViolator class. */ -public class IndividualConstraintRuleViolatorTests { +public class RuleViolatorTests { - private IndividualConstraintRuleViolator target; + private RuleViolator target; private AtomicConstraint atomicConstraint1; private AtomicConstraint atomicConstraint2; @@ -69,7 +68,7 @@ public void commonTestSetup() { List inputFilters = Collections.singletonList(mockFilter); when(mockFilter.canViolate(any(Constraint.class))).thenReturn(true); - target = new IndividualConstraintRuleViolator(inputFilters); + target = new RuleViolator(inputFilters); atomicConstraint1 = new IsLessThanConstantConstraint(createField("foo"), BigDecimal.valueOf(10)); atomicConstraint2 = new IsLessThanConstantConstraint(createField("bar"), BigDecimal.valueOf(20)); @@ -397,7 +396,7 @@ public void violateRule_withUnsupportedConstraints_throwsRuntimeException() { @Test public void violateRule_withEmptyViolationFilter_doesNotThrow() { //Arrange - target = new IndividualConstraintRuleViolator(new ArrayList<>()); + target = new RuleViolator(new ArrayList<>()); inputConstraints.add(atomicConstraint1); Rule inputRule = new Rule(ruleInformation, inputConstraints); diff --git a/generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/TypeEqualityHelper.java b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/TypeEqualityHelper.java similarity index 99% rename from generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/TypeEqualityHelper.java rename to orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/TypeEqualityHelper.java index 82a441811..f7c9afae4 100644 --- a/generator/src/test/java/com/scottlogic/deg/generator/inputs/profileviolation/TypeEqualityHelper.java +++ b/orchestrator/src/test/java/com/scottlogic/deg/orchestrator/violate/violator/TypeEqualityHelper.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.scottlogic.deg.generator.inputs.profileviolation; +package com.scottlogic.deg.orchestrator.violate.violator; import com.scottlogic.deg.common.profile.Profile; import com.scottlogic.deg.common.profile.Rule; diff --git a/output/src/main/java/com/scottlogic/deg/output/guice/OutputModule.java b/output/src/main/java/com/scottlogic/deg/output/guice/OutputModule.java index 2c307f682..7dfdecb01 100644 --- a/output/src/main/java/com/scottlogic/deg/output/guice/OutputModule.java +++ b/output/src/main/java/com/scottlogic/deg/output/guice/OutputModule.java @@ -19,8 +19,6 @@ import com.google.inject.AbstractModule; import com.google.inject.name.Names; import com.scottlogic.deg.output.OutputPath; -import com.scottlogic.deg.output.manifest.JsonManifestWriter; -import com.scottlogic.deg.output.manifest.ManifestWriter; import com.scottlogic.deg.output.outputtarget.SingleDatasetOutputTarget; import com.scottlogic.deg.output.writer.OutputWriterFactory; @@ -37,7 +35,6 @@ protected void configure() { bind(OutputWriterFactory.class).toProvider(OutputWriterFactoryProvider.class); bind(SingleDatasetOutputTarget.class).toProvider(SingleDatasetOutputTargetProvider.class); - bind(ManifestWriter.class).to(JsonManifestWriter.class); bind(OutputPath.class).toInstance(new OutputPath(outputConfigSource.getOutputPath())); diff --git a/output/src/main/java/com/scottlogic/deg/output/manifest/ManifestWriter.java b/output/src/main/java/com/scottlogic/deg/output/manifest/ManifestWriter.java deleted file mode 100644 index 89d5dd7b9..000000000 --- a/output/src/main/java/com/scottlogic/deg/output/manifest/ManifestWriter.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2019 Scott Logic Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.scottlogic.deg.output.manifest; - -import com.scottlogic.deg.common.profile.ViolatedProfile; - -import java.io.IOException; -import java.util.List; - -public interface ManifestWriter { - void writeManifest(List result) throws IOException; -} diff --git a/output/src/main/java/com/scottlogic/deg/output/writer/csv/CsvDataSetWriter.java b/output/src/main/java/com/scottlogic/deg/output/writer/csv/CsvDataSetWriter.java index f731f711d..1c340bda3 100644 --- a/output/src/main/java/com/scottlogic/deg/output/writer/csv/CsvDataSetWriter.java +++ b/output/src/main/java/com/scottlogic/deg/output/writer/csv/CsvDataSetWriter.java @@ -16,8 +16,8 @@ package com.scottlogic.deg.output.writer.csv; -import com.scottlogic.deg.common.profile.ProfileFields; import com.scottlogic.deg.common.output.GeneratedObject; +import com.scottlogic.deg.common.profile.ProfileFields; import com.scottlogic.deg.output.writer.DataSetWriter; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; @@ -51,7 +51,7 @@ static DataSetWriter open(OutputStream stream, ProfileFields fields) throws IOEx CSVPrinter csvPrinter = writerFormat .withEscape('\0') //Dont escape any character, we're formatting strings ourselves .withQuoteMode(QuoteMode.NONE) - .withHeader(fields.stream() + .withHeader(fields.getExternalStream() .map(f -> f.name) .toArray(String[]::new)) .print(outputStreamAsAppendable); @@ -61,7 +61,7 @@ static DataSetWriter open(OutputStream stream, ProfileFields fields) throws IOEx @Override public void writeRow(GeneratedObject row) throws IOException { - csvPrinter.printRecord(fieldOrder.stream() + csvPrinter.printRecord(fieldOrder.getExternalStream() .map(row::getFormattedValue) .map(CsvDataSetWriter::wrapInQuotesIfString) .collect(Collectors.toList())); @@ -74,8 +74,8 @@ public void close() throws IOException { csvPrinter.close(); } - private static Object wrapInQuotesIfString(Object value){ - if (value == null){ + private static Object wrapInQuotesIfString(Object value) { + if (value == null) { return null; } @@ -83,11 +83,11 @@ private static Object wrapInQuotesIfString(Object value){ return ((BigDecimal) value).toPlainString(); } - if (value instanceof OffsetDateTime){ + if (value instanceof OffsetDateTime) { return standardDateFormat.format((OffsetDateTime) value); } - if (value instanceof String){ + if (value instanceof String) { return csvStringFormatter.format(value); } diff --git a/output/src/main/java/com/scottlogic/deg/output/writer/json/JsonDataSetWriter.java b/output/src/main/java/com/scottlogic/deg/output/writer/json/JsonDataSetWriter.java index 20d729694..dc28beec0 100644 --- a/output/src/main/java/com/scottlogic/deg/output/writer/json/JsonDataSetWriter.java +++ b/output/src/main/java/com/scottlogic/deg/output/writer/json/JsonDataSetWriter.java @@ -44,8 +44,10 @@ class JsonDataSetWriter implements DataSetWriter { @Override public void writeRow(GeneratedObject row) throws IOException { Map jsonObject = new HashMap<>(); - fields.forEach(field -> jsonObject - .put(field, convertValue(row.getFormattedValue(field)))); + + fields.getExternalStream() + .forEach(field -> jsonObject + .put(field , convertValue(row.getFormattedValue(field)))); writer.write(jsonObject); } diff --git a/output/src/test/java/com/scottlogic/deg/output/writer/csv/CsvOutputWriterFactoryTests.java b/output/src/test/java/com/scottlogic/deg/output/writer/csv/CsvOutputWriterFactoryTests.java index 7907faab4..e8aeec4ef 100644 --- a/output/src/test/java/com/scottlogic/deg/output/writer/csv/CsvOutputWriterFactoryTests.java +++ b/output/src/test/java/com/scottlogic/deg/output/writer/csv/CsvOutputWriterFactoryTests.java @@ -34,6 +34,8 @@ import java.util.Arrays; import java.util.stream.Collectors; +import static com.scottlogic.deg.common.profile.FieldBuilder.createField; +import static com.scottlogic.deg.common.profile.FieldBuilder.createInternalField; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -94,6 +96,21 @@ void writeRow_withDateTimeGranularToAMillisecondAndNoFormat_shouldFormatDateUsin Matchers.containsString("2001-02-03T04:05:06.777Z")); } + @Test + void writeRow_withInternalFields_shouldNotWriteInternalFields() throws IOException { + ProfileFields fields = new ProfileFields( + Arrays.asList( + createField("External"), + createInternalField("Internal") + ) + ); + expectCsv( + fields, + (100), + Matchers.equalTo("External\n100\n") + ); + } + private static ProfileFields fields(String ...names) { return new ProfileFields( Arrays.stream(names) diff --git a/output/src/test/java/com/scottlogic/deg/output/writer/json/JsonOutputWriterFactoryTest.java b/output/src/test/java/com/scottlogic/deg/output/writer/json/JsonOutputWriterFactoryTest.java index 164363f00..c22afbb68 100644 --- a/output/src/test/java/com/scottlogic/deg/output/writer/json/JsonOutputWriterFactoryTest.java +++ b/output/src/test/java/com/scottlogic/deg/output/writer/json/JsonOutputWriterFactoryTest.java @@ -12,8 +12,11 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Collections; +import static com.scottlogic.deg.common.profile.FieldBuilder.createField; +import static com.scottlogic.deg.common.profile.FieldBuilder.createInternalField; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -22,23 +25,40 @@ class JsonOutputWriterFactoryTest { @Test void writer_withNDJSONTrue__shouldOutputNewLineDelimiterRows() throws IOException { + ProfileFields fields = new ProfileFields(Collections.singletonList(FieldBuilder.createField("my_field"))); + expectJson( + fields, true, Matchers.equalTo("{\n \"my_field\" : \"my_value\"\n}\n{\n \"my_field\" : \"my_value\"\n}")); } @Test void writer_withNDJSONFalse__shouldOutputRowsWrappedInAnArray() throws IOException { + ProfileFields fields = new ProfileFields(Collections.singletonList(FieldBuilder.createField("my_field"))); + expectJson( + fields, false, Matchers.equalTo("[ {\n \"my_field\" : \"my_value\"\n}, {\n \"my_field\" : \"my_value\"\n} ]")); } - private static void expectJson(boolean useNdJson, Matcher matcher) throws IOException { - //Arrange - ProfileFields fields = new ProfileFields(Collections.singletonList(FieldBuilder.createField("my_field"))); - + @Test + void writeRow_withInternalFields_shouldNotWriteInternalFields() throws IOException { + ProfileFields fields = new ProfileFields( + Arrays.asList( + createField("External"), + createInternalField("Internal") + ) + ); + expectJson( + fields, + true, + Matchers.equalTo("{\n \"External\" : \"my_value\"\n}\n{\n \"External\" : \"my_value\"\n}") + ); + } + private static void expectJson(ProfileFields fields, boolean useNdJson, Matcher matcher) throws IOException { // Act GeneratedObject mockGeneratedObject = mock(GeneratedObject.class); when(mockGeneratedObject.getFormattedValue(eq(fields.iterator().next()))).thenReturn("my_value"); diff --git a/profile/src/main/java/com/scottlogic/deg/profile/reader/JsonProfileReader.java b/profile/src/main/java/com/scottlogic/deg/profile/reader/JsonProfileReader.java index 0e531f688..979ffe5bb 100644 --- a/profile/src/main/java/com/scottlogic/deg/profile/reader/JsonProfileReader.java +++ b/profile/src/main/java/com/scottlogic/deg/profile/reader/JsonProfileReader.java @@ -78,7 +78,8 @@ public Profile read(String profileJson) throws IOException { fDto.name, getFieldType(fieldTypes.getOrDefault(fDto.name, fDto.type)), fDto.unique, - fDto.formatting) + fDto.formatting, + false) ) .collect(Collectors.toList())); diff --git a/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/AtomicConstraintFactory.java b/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/AtomicConstraintFactory.java index 5ba21cb5d..d060ba6ff 100644 --- a/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/AtomicConstraintFactory.java +++ b/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/AtomicConstraintFactory.java @@ -22,6 +22,8 @@ public static Constraint create(AtomicConstraintType type, Field field, Object v return new EqualToConstraint(field, value); case IS_IN_SET: return new IsInSetConstraint(field, (DistributedList)value); + case IS_IN_MAP: + return new IsInMapConstraint(field, (DistributedList)value); case IS_NULL: return new IsNullConstraint(field); diff --git a/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/AtomicConstraintValueReader.java b/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/AtomicConstraintValueReader.java index c4ae761bb..d3f6feb65 100644 --- a/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/AtomicConstraintValueReader.java +++ b/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/AtomicConstraintValueReader.java @@ -44,7 +44,7 @@ private Object tryGetValue(ConstraintDTO dto, Types type){ } if (dto.file != null && dto.is.equals(AtomicConstraintType.IS_IN_MAP.getText())){ - throw new UnsupportedOperationException("inMap is unsupported"); + return fromFileReader.listFromMapFile(dto.file, dto.key); } return getValue(dto.value, type); diff --git a/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/FromFileReader.java b/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/FromFileReader.java index 06d2ccde2..043b22ed5 100644 --- a/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/FromFileReader.java +++ b/profile/src/main/java/com/scottlogic/deg/profile/reader/atomic/FromFileReader.java @@ -35,6 +35,18 @@ public DistributedList setFromFile(String file) { .collect(Collectors.toList())); } + public DistributedList listFromMapFile(String file, String key) { + InputStream streamFromPath = createStreamFromPath(appendPath(file)); + + DistributedList names = CsvInputStreamReader.retrieveLines(streamFromPath, key); + closeStream(streamFromPath); + + return new DistributedList<>( + names.distributedList().stream() + .map(holder -> new WeightedElement<>((Object) holder.element(), holder.weight())) + .collect(Collectors.toList())); + } + private String appendPath(String path) { return fromFilePath + path; } diff --git a/profile/src/main/java/com/scottlogic/deg/profile/reader/file/CsvInputStreamReader.java b/profile/src/main/java/com/scottlogic/deg/profile/reader/file/CsvInputStreamReader.java index d11ed8d96..d98ed7cae 100644 --- a/profile/src/main/java/com/scottlogic/deg/profile/reader/file/CsvInputStreamReader.java +++ b/profile/src/main/java/com/scottlogic/deg/profile/reader/file/CsvInputStreamReader.java @@ -16,6 +16,7 @@ package com.scottlogic.deg.profile.reader.file; +import com.scottlogic.deg.common.ValidationException; import com.scottlogic.deg.generator.fieldspecs.whitelist.DistributedList; import com.scottlogic.deg.generator.fieldspecs.whitelist.WeightedElement; import org.apache.commons.csv.CSVFormat; @@ -26,7 +27,7 @@ import java.io.InputStream; import java.io.UncheckedIOException; import java.nio.charset.Charset; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; public final class CsvInputStreamReader { @@ -38,16 +39,44 @@ private CsvInputStreamReader() { public static DistributedList retrieveLines(InputStream stream) { List records = parse(stream); return new DistributedList<>(records.stream() - .map(CsvInputStreamReader::createWeightedElement) + .map(CsvInputStreamReader::createWeightedElementFromRecord) .collect(Collectors.toList())); } - private static WeightedElement createWeightedElement(CSVRecord record) { - if (record.size() > 1) { - return new WeightedElement<>(record.get(0), Double.parseDouble(record.get(1))); - } else { - return WeightedElement.withDefaultWeight(record.get(0)); + public static DistributedList retrieveLines(InputStream stream, String key) { + List records = parse(stream); + + int index = getIndexForKey(records.get(0), key); + + //Remove the header + records.remove(0); + + return new DistributedList<>(records.stream() + .map(record -> record.get(index)) + .map(record -> createWeightedElement(record, Optional.empty())) + .collect(Collectors.toList())); + } + + private static int getIndexForKey(CSVRecord header, String key) { + int index = 0; + for (String title : header) { + if (title.equals(key)) { + return index; + } + index++; } + throw new ValidationException("unable to find data for key " + key); + } + + private static WeightedElement createWeightedElementFromRecord(CSVRecord record) { + return createWeightedElement(record.get(0), + record.size() == 1 ? Optional.empty() : Optional.of(Double.parseDouble(record.get(1)))); + } + + + private static WeightedElement createWeightedElement(String element, Optional weight) { + return weight.map(integer -> new WeightedElement<>(element, integer)) + .orElseGet(() -> WeightedElement.withDefaultWeight(element)); } private static List parse(InputStream stream) { diff --git a/profile/src/test/java/com/scottlogic/deg/profile/reader/ConstraintValidationAndReadingTests.java b/profile/src/test/java/com/scottlogic/deg/profile/reader/ConstraintValidationAndReadingTests.java index f97d019d5..58cd9e89c 100644 --- a/profile/src/test/java/com/scottlogic/deg/profile/reader/ConstraintValidationAndReadingTests.java +++ b/profile/src/test/java/com/scottlogic/deg/profile/reader/ConstraintValidationAndReadingTests.java @@ -210,7 +210,7 @@ public void testAtomicConstraintReader(AtomicConstraintType type, ConstraintDTO try { Object value = new AtomicConstraintValueReader(null).getValue(dto, types); - ConstraintValueValidator.validate(new Field(dto.field, types, false, null), type, value); + ConstraintValueValidator.validate(createField(dto.field, types), type, value); Constraint constraint = AtomicConstraintFactory.create(type, createField(dto.field), value); @@ -242,7 +242,7 @@ public void testBaseConstraintReaderMapWithUnmappedOperands() { @MethodSource("numericOutOfBoundsOperandProvider") public void testAtomicConstraintReaderWithOutOfBoundValues(AtomicConstraintType type, ConstraintDTO dto) { Assertions.assertThrows(InvalidProfileException.class, () -> - ConstraintValueValidator.validate(new Field(dto.field, NUMERIC, false, null), type, dto.value)); + ConstraintValueValidator.validate(createField(dto.field, NUMERIC), type, dto.value)); } @DisplayName("Should pass when string lengths have an integer operand") @@ -342,7 +342,7 @@ private OffsetDateTime tryParseConstraintDateTimeValue(Object value) { dateDto.value = value; Object val = new AtomicConstraintValueReader(null).getValue(dateDto, DATETIME); - ConstraintValueValidator.validate(new Field("test", DATETIME, false, null), IS_AFTER_CONSTANT_DATE_TIME, val); + ConstraintValueValidator.validate(createField("test", DATETIME), IS_AFTER_CONSTANT_DATE_TIME, val); return (OffsetDateTime)val; }