From ab41c74722a3b1b690518158a6ff337767d814de Mon Sep 17 00:00:00 2001 From: Chase Coalwell <782571+srchase@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:57:26 -0600 Subject: [PATCH] Set source locations on smithy-diff events --- .../diff/evaluators/AddedOperationError.java | 8 +- .../diff/evaluators/AddedRequiredMember.java | 1 + .../diff/evaluators/AddedTraitDefinition.java | 1 + .../diff/evaluators/ChangedEnumTrait.java | 10 ++- .../diff/evaluators/ChangedMemberTarget.java | 1 + .../diff/evaluators/ChangedNullability.java | 33 ++++--- .../smithy/diff/evaluators/ModifiedTrait.java | 1 + .../diff/evaluators/RemovedEntityBinding.java | 1 + .../evaluators/RemovedTraitDefinition.java | 1 + .../evaluators/AddedOperationErrorTest.java | 7 ++ .../evaluators/AddedRequiredMemberTest.java | 15 +++- .../evaluators/AddedTraitDefinitionTest.java | 5 ++ .../diff/evaluators/ChangedEnumTraitTest.java | 89 +++++++++++++++++++ .../evaluators/ChangedMemberTargetTest.java | 9 +- .../evaluators/ChangedNullabilityTest.java | 74 +++++++++------ .../diff/evaluators/ModifiedTraitTest.java | 24 +++++ .../evaluators/RemovedEntityBindingTest.java | 15 +++- .../evaluators/RemovedOperationErrorTest.java | 4 + .../RemovedTraitDefinitionTest.java | 6 +- .../diff/evaluators/ServiceRenameTest.java | 10 +++ .../amazon/smithy/model/shapes/EnumShape.java | 6 ++ 21 files changed, 271 insertions(+), 50 deletions(-) diff --git a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedOperationError.java b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedOperationError.java index 1f431156c86..3bbf2e327dc 100644 --- a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedOperationError.java +++ b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedOperationError.java @@ -21,6 +21,8 @@ import java.util.stream.Collectors; import software.amazon.smithy.diff.ChangedShape; import software.amazon.smithy.diff.Differences; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.validation.Severity; @@ -33,17 +35,18 @@ public final class AddedOperationError extends AbstractDiffEvaluator { @Override public List evaluate(Differences differences) { return differences.changedShapes(OperationShape.class) - .flatMap(change -> createErrorViolations(change).stream()) + .flatMap(change -> createErrorViolations(change, differences.getNewModel()).stream()) .collect(Collectors.toList()); } - private List createErrorViolations(ChangedShape change) { + private List createErrorViolations(ChangedShape change, Model newModel) { if (change.getOldShape().getErrors().equals(change.getNewShape().getErrors())) { return Collections.emptyList(); } List events = new ArrayList<>(); for (ShapeId error : change.getNewShape().getErrors()) { + SourceLocation errorSource = newModel.expectShape(error).getSourceLocation(); if (!change.getOldShape().getErrors().contains(error)) { events.add( ValidationEvent.builder() @@ -57,6 +60,7 @@ private List createErrorViolations(ChangedShape + "parameter to an operation).", error, change.getShapeId())) .shape(change.getNewShape()) + .sourceLocation(errorSource) .build() ); } diff --git a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedRequiredMember.java b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedRequiredMember.java index ad48555bf02..0e729f2cfce 100644 --- a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedRequiredMember.java +++ b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedRequiredMember.java @@ -53,6 +53,7 @@ private ValidationEvent emit(MemberShape memberShape) { return ValidationEvent.builder() .id(getEventId()) .shapeId(memberShape.getId()) + .sourceLocation(memberShape.getSourceLocation()) .message("Adding a new member with the `required` trait " + "but not the `default` trait is backwards-incompatible.") .severity(Severity.ERROR) diff --git a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedTraitDefinition.java b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedTraitDefinition.java index 5bb7bd6b48f..11528c6eaf4 100644 --- a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedTraitDefinition.java +++ b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/AddedTraitDefinition.java @@ -34,6 +34,7 @@ public List evaluate(Differences differences) { .id(getEventId()) .severity(Severity.NOTE) .shape(shape) + .sourceLocation(shape.getSourceLocation()) .message(String.format("Trait definition `%s` was added", shape.getId())) .build()) .collect(Collectors.toList()); diff --git a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ChangedEnumTrait.java b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ChangedEnumTrait.java index d9d06cbfe24..c9ec37947d4 100644 --- a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ChangedEnumTrait.java +++ b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ChangedEnumTrait.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import software.amazon.smithy.diff.ChangedShape; import software.amazon.smithy.diff.Differences; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.traits.EnumDefinition; import software.amazon.smithy.model.traits.EnumTrait; @@ -85,6 +86,7 @@ private List validateEnum(ChangedShape change, Pair validateEnum(ChangedShape change, Pair validateEnum(ChangedShape change, Pair eventsToAdd = new ArrayList<>(); + SourceLocation newMemberContainerSource = differences.getNewModel().expectShape(newMember.getContainer()) + .getSourceLocation(); if (oldHasInput && !newHasInput) { // If there was an input trait before, but not now, then the nullability must have // changed from nullable to non-nullable. - eventsToAdd.add(emit(Severity.ERROR, "RemovedInputTrait", shape, message, + eventsToAdd.add(emit(Severity.ERROR, "RemovedInputTrait", shape, newMemberContainerSource, message, "The @input trait was removed from " + newMember.getContainer())); } else if (!oldHasInput && newHasInput) { // If there was no input trait before, but there is now, then the nullability must have // changed from non-nullable to nullable. - eventsToAdd.add(emit(Severity.DANGER, "AddedInputTrait", shape, message, + eventsToAdd.add(emit(Severity.DANGER, "AddedInputTrait", shape, newMemberContainerSource, message, "The @input trait was added to " + newMember.getContainer())); } else if (!newHasInput) { // Can't add clientOptional to a preexisting required member. if (change.isTraitAdded(ClientOptionalTrait.ID) && change.isTraitInBoth(RequiredTrait.ID)) { - eventsToAdd.add(emit(Severity.ERROR, "AddedClientOptionalTrait", shape, message, - "The @clientOptional trait was added to a @required member.")); + eventsToAdd.add(emit(Severity.ERROR, "AddedClientOptionalTrait", shape, oldMemberSourceLocation, + message, "The @clientOptional trait was added to a @required member.")); } // Can't add required to a member unless the member is marked as @clientOptional or part of @input. if (change.isTraitAdded(RequiredTrait.ID) && !newMember.hasTrait(ClientOptionalTrait.ID)) { - eventsToAdd.add(emit(Severity.ERROR, "AddedRequiredTrait", shape, message, + eventsToAdd.add(emit(Severity.ERROR, "AddedRequiredTrait", shape, oldMemberSourceLocation, message, "The @required trait was added to a member.")); } // Can't add the default trait to a member unless the member was previously required. if (change.isTraitAdded(DefaultTrait.ID) && !change.isTraitRemoved(RequiredTrait.ID)) { - eventsToAdd.add(emit(Severity.ERROR, "AddedDefaultTrait", shape, message, + eventsToAdd.add(emit(Severity.ERROR, "AddedDefaultTrait", shape, oldMemberSourceLocation, message, "The @default trait was added to a member that was not previously @required.")); } // Can only remove the required trait if the member was nullable or replaced by the default trait. @@ -131,20 +135,21 @@ private void createErrors( && !oldMember.hasTrait(ClientOptionalTrait.ID)) { if (newTarget.isStructureShape() || newTarget.isUnionShape()) { eventsToAdd.add(emit(Severity.WARNING, "RemovedRequiredTrait.StructureOrUnion", shape, - message, "The @required trait was removed from a member that targets a " - + newTarget.getType() + ". This is backward compatible in generators that " - + "always treat structures and unions as optional (e.g., AWS generators)")); + oldMemberSourceLocation, message, "The @required trait was removed from a member " + + "that targets a " + newTarget.getType() + ". This is backward compatible in " + + "generators that always treat structures and unions as optional " + + "(e.g., AWS generators)")); } else { - eventsToAdd.add(emit(Severity.ERROR, "RemovedRequiredTrait", shape, message, - "The @required trait was removed and not replaced with the @default trait and " - + "@addedDefault trait.")); + eventsToAdd.add(emit(Severity.ERROR, "RemovedRequiredTrait", shape, oldMemberSourceLocation, + message, "The @required trait was removed and not replaced with the @default " + + "trait and @addedDefault trait.")); } } } // If not specific event was emitted, emit a generic event. if (eventsToAdd.isEmpty()) { - eventsToAdd.add(emit(Severity.ERROR, null, shape, null, message)); + eventsToAdd.add(emit(Severity.ERROR, null, shape, oldMemberSourceLocation, null, message)); } events.addAll(eventsToAdd); @@ -158,6 +163,7 @@ private ValidationEvent emit( Severity severity, String eventIdSuffix, ShapeId shape, + SourceLocation sourceLocation, String prefixMessage, String message ) { @@ -166,6 +172,7 @@ private ValidationEvent emit( return ValidationEvent.builder() .id(actualId) .shapeId(shape) + .sourceLocation(sourceLocation) .message(actualMessage) .severity(severity) .build(); diff --git a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ModifiedTrait.java b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ModifiedTrait.java index 3a792e72469..fc51e84a016 100644 --- a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ModifiedTrait.java +++ b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ModifiedTrait.java @@ -273,6 +273,7 @@ List validate( .id(getValidationEventId(this, trait)) .severity(severity) .shape(shape) + .sourceLocation(left.getSourceLocation()) .message(message) .build()); } diff --git a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/RemovedEntityBinding.java b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/RemovedEntityBinding.java index eb36e130615..445732c1164 100644 --- a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/RemovedEntityBinding.java +++ b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/RemovedEntityBinding.java @@ -72,6 +72,7 @@ private ValidationEvent createRemovedEvent(String typeOfRemoval, EntityShape par .id(typeOfRemoval + typeOfParentShape + childShape.getName()) .severity(Severity.ERROR) .shape(parentEntity) + .sourceLocation(parentEntity.getSourceLocation()) .message(message) .build(); } diff --git a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/RemovedTraitDefinition.java b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/RemovedTraitDefinition.java index 87fe377e5e8..5364f6f8db0 100644 --- a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/RemovedTraitDefinition.java +++ b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/RemovedTraitDefinition.java @@ -34,6 +34,7 @@ public List evaluate(Differences differences) { .id(getEventId()) .severity(Severity.ERROR) .shape(shape) + .sourceLocation(shape.expectTrait(TraitDefinition.class).getSourceLocation()) .message(String.format("Trait definition `%s` was removed", shape.getId())) .build()) .collect(Collectors.toList()); diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedOperationErrorTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedOperationErrorTest.java index 38fa859a307..032c6f12f9d 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedOperationErrorTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedOperationErrorTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.StructureShape; @@ -31,13 +32,17 @@ public class AddedOperationErrorTest { @Test public void detectsAddedErrors() { + SourceLocation s1 = new SourceLocation("main.smithy", 1, 2); + SourceLocation s2 = new SourceLocation("main.smithy", 3, 4); Shape e1 = StructureShape.builder() .id("foo.baz#E1") .addTrait(new ErrorTrait("client")) + .source(s1) .build(); Shape e2 = StructureShape.builder() .id("foo.baz#E2") .addTrait(new ErrorTrait("client")) + .source(s2) .build(); OperationShape operation1 = OperationShape.builder().id("foo.baz#Operation").build(); Shape operation2 = operation1.toBuilder().addError(e1.getId()).addError(e2.getId()).build(); @@ -47,6 +52,8 @@ public void detectsAddedErrors() { assertThat(TestHelper.findEvents(events, "AddedOperationError").size(), equalTo(2)); assertThat(TestHelper.findEvents(events, "AddedOperationError.E1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "AddedOperationError.E1").stream().findFirst().get().getSourceLocation(), equalTo(s1)); assertThat(TestHelper.findEvents(events, "AddedOperationError.E2").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "AddedOperationError.E2").stream().findFirst().get().getSourceLocation(), equalTo(s2)); } } diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedRequiredMemberTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedRequiredMemberTest.java index ff5fc358759..e25aaccacdd 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedRequiredMemberTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedRequiredMemberTest.java @@ -1,15 +1,19 @@ package software.amazon.smithy.diff.evaluators; +import java.util.List; import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.node.StringNode; +import software.amazon.smithy.model.shapes.MemberShape; +import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.shapes.StringShape; import software.amazon.smithy.model.shapes.StructureShape; import software.amazon.smithy.model.traits.DefaultTrait; import software.amazon.smithy.model.traits.RequiredTrait; import software.amazon.smithy.model.validation.Severity; +import software.amazon.smithy.model.validation.ValidationEvent; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; @@ -20,8 +24,15 @@ public void addingRequiredTraitWithoutDefaultIsAnError() { StringShape s = StringShape.builder().id("smithy.example#Str").build(); StructureShape a = StructureShape.builder().id("smithy.example#A") .build(); + SourceLocation source = new SourceLocation("main.smithy", 1, 2); + MemberShape member = MemberShape.builder() + .id(a.getId().withMember("foo")) + .target(s.getId()) + .addTrait(new RequiredTrait()) + .source(source) + .build(); StructureShape b = StructureShape.builder().id("smithy.example#A") - .addMember("foo", s.getId(), b2 -> b2.addTrait(new RequiredTrait())) + .addMember(member) .build(); Model model1 = Model.builder().addShapes(s, a).build(); Model model2 = Model.builder().addShapes(s, b).build(); @@ -34,6 +45,8 @@ public void addingRequiredTraitWithoutDefaultIsAnError() { assertThat(TestHelper.findEvents(result.getDiffEvents(), "AddedRequiredMember").get(0).getMessage(), equalTo("Adding a new member with the `required` trait " + "but not the `default` trait is backwards-incompatible.")); + assertThat(TestHelper.findEvents(result.getDiffEvents(), "AddedRequiredMember").get(0).getSourceLocation(), + equalTo(source)); } @Test diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedTraitDefinitionTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedTraitDefinitionTest.java index bdff64d471b..c01b43b62b8 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedTraitDefinitionTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/AddedTraitDefinitionTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.StringShape; import software.amazon.smithy.model.traits.TraitDefinition; @@ -30,9 +31,11 @@ public class AddedTraitDefinitionTest { @Test public void detectsAddedTraitDefinition() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); Shape definition = StringShape.builder() .id("foo.baz#bam") .addTrait(TraitDefinition.builder().build()) + .source(source) .build(); Model modelA = Model.assembler().assemble().unwrap(); @@ -40,5 +43,7 @@ public void detectsAddedTraitDefinition() { List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "AddedTraitDefinition").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "AddedTraitDefinition").stream().findFirst().get() + .getSourceLocation(), equalTo(source)); } } diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedEnumTraitTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedEnumTraitTest.java index ec3bf185341..c3d959fbb30 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedEnumTraitTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedEnumTraitTest.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.EnumShape; import software.amazon.smithy.model.shapes.StringShape; import software.amazon.smithy.model.traits.EnumDefinition; @@ -36,6 +37,7 @@ public class ChangedEnumTraitTest { @Test public void detectsAppendedEnums() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -47,6 +49,7 @@ public void detectsAppendedEnums() { .addTrait(EnumTrait.builder() .addEnum(EnumDefinition.builder().value("foo").build()) .addEnum(EnumDefinition.builder().value("baz").build()) + .sourceLocation(source) .build()) .build(); Model modelA = Model.assembler().addShape(s1).assemble().unwrap(); @@ -55,10 +58,12 @@ public void detectsAppendedEnums() { assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").size(), equalTo(1)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(0).getSeverity(), equalTo(Severity.NOTE)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(0).getSourceLocation(), equalTo(source)); } @Test public void detectsAppendedEnumsEnumTraitNoNameToEnumShape() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -71,6 +76,7 @@ public void detectsAppendedEnumsEnumTraitNoNameToEnumShape() { .id("foo.baz#Baz") .addMember("foo", "foo") .addMember("baz", "baz") + .source(source) .build(); Model modelA = Model.assembler().addShape(s1).assemble().unwrap(); Model modelB = Model.assembler().addShape(s2).assemble().unwrap(); @@ -80,12 +86,17 @@ public void detectsAppendedEnumsEnumTraitNoNameToEnumShape() { assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").size(), equalTo(1)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSeverity(), equalTo(Severity.ERROR)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(1).getSeverity(), equalTo(Severity.NOTE)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(1).getSourceLocation(), + equalTo(source)); } @Test public void detectsAppendedEnumsEnumTraitWithNameToEnumShape() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -93,30 +104,36 @@ public void detectsAppendedEnumsEnumTraitWithNameToEnumShape() { .name("foo") .value("foo") .build()) + .sourceLocation(source) .build()) .build(); EnumShape s2 = EnumShape.builder() .id("foo.baz#Baz") .addMember("foo", "foo") .addMember("baz", "baz") + .source(source) .build(); Model modelA = Model.assembler().addShape(s1).assemble().unwrap(); Model modelB = Model.assembler().addShape(s2).assemble().unwrap(); List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").stream() .allMatch(e -> e.getSeverity() == Severity.NOTE), equalTo(true)); } @Test public void detectsRemovedEnums() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() .addEnum(EnumDefinition.builder().value("foo").build()) .addEnum(EnumDefinition.builder().value("baz").build()) .addEnum(EnumDefinition.builder().value("bat").build()) + .sourceLocation(source) .build()) .build(); StringShape s2 = StringShape.builder() @@ -130,12 +147,18 @@ public void detectsRemovedEnums() { List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.2").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.2").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(2)); } @Test public void detectsRemovedEnumsEnumTraitNoNameToEnumShape() { + SourceLocation beforeSource = new SourceLocation("before.smithy", 1, 2); + SourceLocation afterSource = new SourceLocation("after.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -145,24 +168,31 @@ public void detectsRemovedEnumsEnumTraitNoNameToEnumShape() { .addEnum(EnumDefinition.builder() .value("baz") .build()) + .sourceLocation(beforeSource) .build()) .build(); EnumShape s2 = EnumShape.builder() .id("foo.baz#Baz") .addMember("foo", "foo") + .source(afterSource) .build(); Model modelA = Model.assembler().addShape(s1).assemble().unwrap(); Model modelB = Model.assembler().addShape(s2).assemble().unwrap(); List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").get(0).getSourceLocation(), + equalTo(beforeSource)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSourceLocation(), + equalTo(afterSource)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").stream() .allMatch(e -> e.getSeverity() == Severity.ERROR), equalTo(true)); } @Test public void detectsRemovedEnumsEnumTraitWithNameToEnumShape() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -174,6 +204,7 @@ public void detectsRemovedEnumsEnumTraitWithNameToEnumShape() { .name("baz") .value("baz") .build()) + .sourceLocation(source) .build()) .build(); EnumShape s2 = EnumShape.builder() @@ -185,12 +216,15 @@ public void detectsRemovedEnumsEnumTraitWithNameToEnumShape() { List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").stream() .allMatch(e -> e.getSeverity() == Severity.ERROR), equalTo(true)); } @Test public void detectsRenamedEnums() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -204,18 +238,24 @@ public void detectsRenamedEnums() { .addEnum(EnumDefinition.builder().value("foo").name("NEW1").build()) .addEnum(EnumDefinition.builder().value("baz").name("NEW2").build()) .build()) + .source(source) .build(); Model modelA = Model.assembler().addShape(s1).assemble().unwrap(); Model modelB = Model.assembler().addShape(s2).assemble().unwrap(); List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.1").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(2)); } @Test public void detectsRenamedEnumsEnumTraitNoNameToEnumShape() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -227,18 +267,22 @@ public void detectsRenamedEnumsEnumTraitNoNameToEnumShape() { EnumShape s2 = EnumShape.builder() .id("foo.baz#Baz") .addMember("NEW", "foo") + .source(source) .build(); Model modelA = Model.assembler().addShape(s1).assemble().unwrap(); Model modelB = Model.assembler().addShape(s2).assemble().unwrap(); List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSeverity(), equalTo(Severity.ERROR)); } @Test public void detectsRenamedEnumsEnumTraitWithNameToEnumShape() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -251,22 +295,27 @@ public void detectsRenamedEnumsEnumTraitWithNameToEnumShape() { EnumShape s2 = EnumShape.builder() .id("foo.baz#Baz") .addMember("NEW", "foo") + .source(source) .build(); Model modelA = Model.assembler().addShape(s1).assemble().unwrap(); Model modelB = Model.assembler().addShape(s2).assemble().unwrap(); List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSeverity(), equalTo(Severity.ERROR)); } @Test public void detectsInsertedEnums() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() .addEnum(EnumDefinition.builder().value("foo").build()) + .sourceLocation(source) .build()) .build(); StringShape s2 = StringShape.builder() @@ -282,16 +331,22 @@ public void detectsInsertedEnums() { List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.0").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.0").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.1").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(2)); } @Test public void detectsInsertedEnumsBeforeAppendedEnums() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() .addEnum(EnumDefinition.builder().value("foo").build()) + .sourceLocation(source) .build()) .build(); StringShape s2 = StringShape.builder() @@ -308,18 +363,24 @@ public void detectsInsertedEnumsBeforeAppendedEnums() { List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.0").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.0").get(0) + .getSourceLocation(), equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.1").get(0) + .getSourceLocation(), equalTo(source)); assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(2)); } @Test public void detectsInsertedEnumsEnumTraitNoNameToEnumShape() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() .addEnum(EnumDefinition.builder() .value("foo") .build()) + .sourceLocation(source) .build()) .build(); EnumShape s2 = EnumShape.builder() @@ -333,12 +394,15 @@ public void detectsInsertedEnumsEnumTraitNoNameToEnumShape() { assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").size(), equalTo(2)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.0").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.0").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").stream() .allMatch(e -> e.getSeverity() == Severity.ERROR), equalTo(true)); } @Test public void detectsInsertedEnumsEnumTraitWithNameToEnumShape() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -346,6 +410,7 @@ public void detectsInsertedEnumsEnumTraitWithNameToEnumShape() { .name("foo") .value("foo") .build()) + .sourceLocation(source) .build()) .build(); EnumShape s2 = EnumShape.builder() @@ -358,18 +423,23 @@ public void detectsInsertedEnumsEnumTraitWithNameToEnumShape() { List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.0").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.0").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.OrderChanged.0").stream() .allMatch(e -> e.getSeverity() == Severity.ERROR), equalTo(true)); } @Test public void detectsAppendedEnumsAfterRemovedEnums() { + SourceLocation beforeSource = new SourceLocation("before.smithy", 1, 2); + SourceLocation afterSource = new SourceLocation("after.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() .addEnum(EnumDefinition.builder().value("old1").build()) .addEnum(EnumDefinition.builder().value("old2").build()) .addEnum(EnumDefinition.builder().value("old3").build()) + .sourceLocation(beforeSource) .build()) .build(); StringShape s2 = StringShape.builder() @@ -378,6 +448,7 @@ public void detectsAppendedEnumsAfterRemovedEnums() { .addEnum(EnumDefinition.builder().value("old1").build()) .addEnum(EnumDefinition.builder().value("old3").build()) .addEnum(EnumDefinition.builder().value("new1").build()) + .sourceLocation(afterSource) .build()) .build(); Model modelA = Model.assembler().addShape(s1).assemble().unwrap(); @@ -387,18 +458,24 @@ public void detectsAppendedEnumsAfterRemovedEnums() { List changeEvents = TestHelper.findEvents(allEvents, "ChangedEnumTrait"); assertThat(changeEvents.size(), equalTo(2)); assertThat(TestHelper.findEvents(changeEvents, "ChangedEnumTrait.Removed.1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(changeEvents, "ChangedEnumTrait.Removed.1").get(0).getSourceLocation(), + equalTo(beforeSource)); ValidationEvent removedEvent = changeEvents.get(0); assertThat(removedEvent.getSeverity(), equalTo(Severity.ERROR)); assertThat(removedEvent.getMessage(), stringContainsInOrder("Enum value `old2` was removed")); + assertThat(removedEvent.getSourceLocation(), equalTo(beforeSource)); ValidationEvent appendedEvent = changeEvents.get(1); assertThat(appendedEvent.getSeverity(), equalTo(Severity.NOTE)); assertThat(appendedEvent.getMessage(), stringContainsInOrder("Enum value `new1` was appended")); + assertThat(appendedEvent.getSourceLocation(), equalTo(afterSource)); } @Test public void detectsAppendedEnumsAfterRemovedEnumsEnumTraitNoNameToEnumShape() { + SourceLocation beforeSource = new SourceLocation("before.smithy", 1, 2); + SourceLocation afterSource = new SourceLocation("after.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -411,6 +488,7 @@ public void detectsAppendedEnumsAfterRemovedEnumsEnumTraitNoNameToEnumShape() { .addEnum(EnumDefinition.builder() .value("old3") .build()) + .sourceLocation(beforeSource) .build()) .build(); EnumShape s2 = EnumShape.builder() @@ -418,6 +496,7 @@ public void detectsAppendedEnumsAfterRemovedEnumsEnumTraitNoNameToEnumShape() { .addMember("old1", "old1") .addMember("old3", "old3") .addMember("new1", "new1") + .source(afterSource) .build(); Model modelA = Model.assembler().addShape(s1).assemble().unwrap(); Model modelB = Model.assembler().addShape(s2).assemble().unwrap(); @@ -425,8 +504,14 @@ public void detectsAppendedEnumsAfterRemovedEnumsEnumTraitNoNameToEnumShape() { assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").size(), equalTo(4)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSourceLocation(), + equalTo(afterSource)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").get(0).getSourceLocation(), + equalTo(beforeSource)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.2").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.2").get(0).getSourceLocation(), + equalTo(afterSource)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").subList(0, 3).stream() .allMatch(e -> e.getSeverity() == Severity.ERROR), equalTo(true)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").subList(3, 4).stream() @@ -435,6 +520,7 @@ public void detectsAppendedEnumsAfterRemovedEnumsEnumTraitNoNameToEnumShape() { @Test public void detectsAppendedEnumsAfterRemovedEnumsEnumTraitWithNameToEnumShape() { + SourceLocation source = new SourceLocation("main.smithy", 1, 2); StringShape s1 = StringShape.builder() .id("foo.baz#Baz") .addTrait(EnumTrait.builder() @@ -450,6 +536,7 @@ public void detectsAppendedEnumsAfterRemovedEnumsEnumTraitWithNameToEnumShape() .name("old3") .value("old3") .build()) + .sourceLocation(source) .build()) .build(); EnumShape s2 = EnumShape.builder() @@ -464,6 +551,8 @@ public void detectsAppendedEnumsAfterRemovedEnumsEnumTraitWithNameToEnumShape() assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").size(), equalTo(2)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").stream() .allMatch(e -> e.getSeverity() == Severity.ERROR), equalTo(true)); assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").subList(1, 2).stream() diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedMemberTargetTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedMemberTargetTest.java index d1d16ae4828..a405893f140 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedMemberTargetTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedMemberTargetTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.ListShape; import software.amazon.smithy.model.shapes.MemberShape; import software.amazon.smithy.model.shapes.Shape; @@ -38,17 +39,21 @@ public class ChangedMemberTargetTest { @Test public void detectsIncompatibleTypeChanges() { + SourceLocation source = new SourceLocation("a.smithy", 2, 3); Shape shape1 = StringShape.builder().id("foo.baz#String").build(); MemberShape member1 = MemberShape.builder().id("foo.baz#List$member").target(shape1.getId()).build(); ListShape list1 = ListShape.builder().id("foo.baz#List").member(member1).build(); Shape shape2 = TimestampShape.builder().id("foo.baz#Timestamp").build(); - MemberShape member2 = MemberShape.builder().id("foo.baz#List$member").target(shape2.getId()).build(); + MemberShape member2 = MemberShape.builder().id("foo.baz#List$member").target(shape2.getId()).source(source) + .build(); ListShape list2 = ListShape.builder().id("foo.baz#List").member(member2).build(); Model modelA = Model.assembler().addShapes(shape1, shape2, member1, list1).assemble().unwrap(); Model modelB = Model.assembler().addShapes(shape1, shape2, member2, list2).assemble().unwrap(); List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "ChangedMemberTarget").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "ChangedMemberTarget").get(0).getSourceLocation(), + equalTo(source)); assertThat(TestHelper.findEvents(events, member2.getId()).size(), equalTo(1)); assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(1)); } @@ -152,7 +157,7 @@ public void detectsTraitRemovalOnMemberTarget() { @Test public void detectsTraitAddedToMemberTarget() { - StringShape shape1 = StringShape.builder().id("foo.baz#String1").build(); + StringShape shape1 = StringShape.builder().id("foo.baz#String1").build(); MemberShape member1 = MemberShape.builder().id("foo.baz#List$member").target(shape1.getId()).build(); ListShape list1 = ListShape.builder().id("foo.baz#List").member(member1).build(); diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedNullabilityTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedNullabilityTest.java index 0205a2990e9..3f7444756c7 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedNullabilityTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedNullabilityTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.shapes.MemberShape; import software.amazon.smithy.model.shapes.ModelSerializer; @@ -18,6 +19,7 @@ import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.shapes.StringShape; import software.amazon.smithy.model.shapes.StructureShape; +import software.amazon.smithy.model.shapes.UnionShape; import software.amazon.smithy.model.traits.BoxTrait; import software.amazon.smithy.model.traits.ClientOptionalTrait; import software.amazon.smithy.model.traits.DefaultTrait; @@ -75,10 +77,12 @@ public void addingDefaultWithRequiredTraitIsOk() { @Test public void detectsInvalidAdditionOfDefaultTrait() { + SourceLocation source = new SourceLocation("a.smithy", 5, 6); StringShape s = StringShape.builder().id("smithy.example#Str").build(); StructureShape a = StructureShape.builder() .id("smithy.example#A") - .addMember("foo", s.getId()) + .addMember("foo", s.getId(), builder -> builder.source(source)) + .source(source) .build(); StructureShape b = StructureShape.builder() .id("smithy.example#A") @@ -93,6 +97,7 @@ public void detectsInvalidAdditionOfDefaultTrait() { .filter(event -> event.getSeverity() == Severity.ERROR) .filter(event -> event.getId().equals("ChangedNullability.AddedDefaultTrait")) .filter(event -> event.getShapeId().get().equals(a.getAllMembers().get("foo").getId())) + .filter(event -> event.getSourceLocation().equals(source)) .filter(event -> event.getMessage().contains("The @default trait was added to a member that " + "was not previously @required")) .count(), equalTo(1L)); @@ -122,17 +127,22 @@ public void removingTheRequiredTraitOnInputStructureIsOk() { @Test public void detectsInvalidRemovalOfRequired() { + SourceLocation source = new SourceLocation("a.smithy", 5, 6); StringShape s = StringShape.builder().id("smithy.example#Str").build(); + MemberShape requiredM = MemberShape.builder().id("smithy.example#A$foo").target(s).addTrait(new RequiredTrait()) + .source(source).build(); + MemberShape m = MemberShape.builder().id("smithy.example#A$foo").target(s).source(source).build(); StructureShape a = StructureShape.builder() .id("smithy.example#A") - .addMember("foo", s.getId(), b1 -> b1.addTrait(new RequiredTrait())) + .addMember(requiredM) + .source(source) .build(); StructureShape b = StructureShape.builder() .id("smithy.example#A") - .addMember("foo", s.getId()) + .addMember(m) .build(); - Model model1 = Model.builder().addShapes(s, a).build(); - Model model2 = Model.builder().addShapes(s, b).build(); + Model model1 = Model.builder().addShapes(s, a, requiredM).build(); + Model model2 = Model.builder().addShapes(s, b, m).build(); ModelDiff.Result result = ModelDiff.builder().oldModel(model1).newModel(model2).compare(); assertThat(result.isDiffBreaking(), is(true)); @@ -140,6 +150,7 @@ public void detectsInvalidRemovalOfRequired() { .filter(event -> event.getSeverity() == Severity.ERROR) .filter(event -> event.getId().equals("ChangedNullability.RemovedRequiredTrait")) .filter(event -> event.getShapeId().get().equals(a.getAllMembers().get("foo").getId())) + .filter(event -> event.getSourceLocation().equals(source)) .filter(event -> event.getMessage().contains("The @required trait was removed and not " + "replaced with the @default trait")) .count(), equalTo(1L)); @@ -147,7 +158,9 @@ public void detectsInvalidRemovalOfRequired() { @Test public void detectAdditionOfRequiredTrait() { - MemberShape member1 = MemberShape.builder().id("foo.baz#Baz$bam").target("foo.baz#String").build(); + SourceLocation source = new SourceLocation("a.smithy", 5, 6); + MemberShape member1 = MemberShape.builder().id("foo.baz#Baz$bam").target("foo.baz#String").source(source) + .build(); MemberShape member2 = member1.toBuilder().addTrait(new RequiredTrait()).build(); StructureShape shapeA1 = StructureShape.builder().id("foo.baz#Baz").addMember(member1).build(); StructureShape shapeA2 = StructureShape.builder().id("foo.baz#Baz").addMember(member2).build(); @@ -159,16 +172,19 @@ public void detectAdditionOfRequiredTrait() { assertThat(events.stream() .filter(event -> event.getSeverity() == Severity.ERROR) .filter(event -> event.getId().equals("ChangedNullability.AddedRequiredTrait")) + .filter(event -> event.getSourceLocation().equals(source)) .filter(event -> event.getMessage().contains("The @required trait was added to a member")) .count(), equalTo(1L)); } @Test public void detectAdditionOfClientOptionalTrait() { + SourceLocation source = new SourceLocation("a.smithy", 5, 6); MemberShape member1 = MemberShape.builder() .id("foo.baz#Baz$bam") .target("foo.baz#String") .addTrait(new RequiredTrait()) + .source(source) .build(); MemberShape member2 = member1.toBuilder().addTrait(new ClientOptionalTrait()).build(); StructureShape shapeA1 = StructureShape.builder().id("foo.baz#Baz").addMember(member1).build(); @@ -181,6 +197,7 @@ public void detectAdditionOfClientOptionalTrait() { assertThat(events.stream() .filter(event -> event.getSeverity() == Severity.ERROR) .filter(event -> event.getId().equals("ChangedNullability.AddedClientOptionalTrait")) + .filter(event -> event.getSourceLocation().equals(source)) .filter(event -> event.getMessage().contains("The @clientOptional trait was added to a " + "@required member")) .count(), equalTo(1L)); @@ -188,6 +205,7 @@ public void detectAdditionOfClientOptionalTrait() { @Test public void detectsAdditionOfInputTrait() { + SourceLocation source = new SourceLocation("a.smithy", 5, 6); MemberShape member1 = MemberShape.builder() .id("foo.baz#Baz$bam") .target("foo.baz#String") @@ -196,7 +214,7 @@ public void detectsAdditionOfInputTrait() { MemberShape member2 = member1.toBuilder().addTrait(new DocumentationTrait("docs")).build(); StructureShape shapeA1 = StructureShape.builder().id("foo.baz#Baz").addMember(member1).build(); StructureShape shapeA2 = StructureShape.builder().id("foo.baz#Baz").addMember(member2) - .addTrait(new InputTrait()).build(); + .addTrait(new InputTrait()).source(source).build(); StringShape target = StringShape.builder().id("foo.baz#String").build(); Model modelA = Model.assembler().addShapes(shapeA1, member1, target).assemble().unwrap(); Model modelB = Model.assembler().addShapes(shapeA2, member2, target).assemble().unwrap(); @@ -205,15 +223,18 @@ public void detectsAdditionOfInputTrait() { assertThat(events.stream() .filter(event -> event.getSeverity() == Severity.DANGER) .filter(event -> event.getId().equals("ChangedNullability.AddedInputTrait")) + .filter(event -> event.getSourceLocation().equals(source)) .filter(event -> event.getMessage().contains("The @input trait was added to")) .count(), equalTo(1L)); assertThat(events.stream() .filter(event -> event.getId().contains("ChangedNullability")) + .filter(event -> event.getSourceLocation().equals(source)) .count(), equalTo(1L)); } @Test public void detectsRemovalOfInputTrait() { + SourceLocation source = new SourceLocation("a.smithy", 5, 6); MemberShape member1 = MemberShape.builder() .id("foo.baz#Baz$bam") .target("foo.baz#String") @@ -230,6 +251,7 @@ public void detectsRemovalOfInputTrait() { StructureShape shapeA2 = StructureShape.builder() .id("foo.baz#Baz") .addMember(member2) + .source(source) .build(); StringShape target = StringShape.builder().id("foo.baz#String").build(); Model modelA = Model.assembler().addShapes(shapeA1, member1, target).assemble().unwrap(); @@ -239,6 +261,7 @@ public void detectsRemovalOfInputTrait() { assertThat(events.stream() .filter(event -> event.getSeverity() == Severity.ERROR) .filter(event -> event.getId().equals("ChangedNullability.RemovedInputTrait")) + .filter(event -> event.getSourceLocation().equals(source)) .filter(event -> event.getMessage().contains("The @input trait was removed from")) .count(), equalTo(1L)); } @@ -324,15 +347,12 @@ public void roundTrippedV1ModelHasNoEvents() { @Test public void specialHandlingForRequiredStructureMembers() { - String originalModel = - "$version: \"2.0\"\n" - + "namespace smithy.example\n" - + "structure Baz {}\n" - + "structure Foo {\n" - + " @required\n" - + " baz: Baz\n" - + "}\n"; - Model oldModel = Model.assembler().addUnparsedModel("foo.smithy", originalModel).assemble().unwrap(); + SourceLocation source = new SourceLocation("a.smithy", 8, 2); + StructureShape structBaz = StructureShape.builder().id("smithy.example#Baz").build(); + MemberShape memberBaz = MemberShape.builder().id("smithy.example#Foo$baz").addTrait(new RequiredTrait()) + .target(structBaz).source(source).build(); + StructureShape structFoo = StructureShape.builder().id("smithy.example#Foo").addMember(memberBaz).build(); + Model oldModel = Model.assembler().addShapes(structFoo, structBaz, memberBaz).assemble().unwrap(); Model newModel = ModelTransformer.create().replaceShapes(oldModel, ListUtils.of( Shape.shapeToBuilder(oldModel.expectShape(ShapeId.from("smithy.example#Foo$baz"))) .removeTrait(RequiredTrait.ID) @@ -343,22 +363,19 @@ public void specialHandlingForRequiredStructureMembers() { assertThat(events, hasSize(1)); assertThat(events.get(0).getSeverity(), is(Severity.WARNING)); + assertThat(events.get(0).getSourceLocation(), equalTo(source)); } @Test public void specialHandlingForRequiredUnionMembers() { - String originalModel = - "$version: \"2.0\"\n" - + "namespace smithy.example\n" - + "union Baz {\n" - + " a: String\n" - + " b: String\n" - + "}\n" - + "structure Foo {\n" - + " @required\n" - + " baz: Baz\n" - + "}\n"; - Model oldModel = Model.assembler().addUnparsedModel("foo.smithy", originalModel).assemble().unwrap(); + SourceLocation source = new SourceLocation("b.smithy", 3, 4); + MemberShape memberA = MemberShape.builder().id("smithy.example#Baz$a").target("smithy.api#String").build(); + MemberShape memberB = MemberShape.builder().id("smithy.example#Baz$B").target("smithy.api#String").build(); + UnionShape union = UnionShape.builder().id("smithy.example#Baz").addMember(memberA).addMember(memberB).build(); + MemberShape memberBaz = MemberShape.builder().id("smithy.example#Foo$baz").addTrait(new RequiredTrait()) + .target(union).source(source).build(); + StructureShape struct = StructureShape.builder().id("smithy.example#Foo").addMember(memberBaz).build(); + Model oldModel = Model.assembler().addShapes(union, struct, memberA, memberB, memberBaz).assemble().unwrap(); Model newModel = ModelTransformer.create().replaceShapes(oldModel, ListUtils.of( Shape.shapeToBuilder(oldModel.expectShape(ShapeId.from("smithy.example#Foo$baz"))) .removeTrait(RequiredTrait.ID) @@ -369,6 +386,7 @@ public void specialHandlingForRequiredUnionMembers() { assertThat(events, hasSize(1)); assertThat(events.get(0).getSeverity(), is(Severity.WARNING)); + assertThat(events.get(0).getSourceLocation(), equalTo(source)); } @Test diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ModifiedTraitTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ModifiedTraitTest.java index 1034860b127..e27be290171 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ModifiedTraitTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ModifiedTraitTest.java @@ -153,7 +153,11 @@ public void modifiedShapeNoTag() { assertThat(events, hasSize(3)); assertThat(events.stream().filter(e -> e.getSeverity() == Severity.WARNING).count(), equalTo(1L)); + assertThat(events.stream().filter(e -> e.getSourceLocation().getFilename().endsWith("a.smithy")).count(), + equalTo(1L)); assertThat(events.stream().filter(e -> e.getSeverity() == Severity.NOTE).count(), equalTo(2L)); + assertThat(events.stream().filter(e -> e.getSourceLocation().getFilename().endsWith("b.smithy")).count(), + equalTo(2L)); assertThat(messages, containsInAnyOrder( "Changed trait `smithy.example#b` from \"hello\" to \"hello!\"", @@ -178,6 +182,8 @@ public void findsDifferencesInTraitValues() { assertThat(events, hasSize(2)); assertThat(events.stream().filter(e -> e.getSeverity() == Severity.ERROR).count(), equalTo(1L)); assertThat(events.stream().filter(e -> e.getSeverity() == Severity.WARNING).count(), equalTo(1L)); + assertThat(events.stream().filter(e -> e.getSourceLocation().getFilename().endsWith("b.smithy")).count(), + equalTo(2L)); assertThat(messages, containsInAnyOrder( "Added trait contents to `smithy.example#aTrait` at path `/bar` with value \"no\"", @@ -199,6 +205,10 @@ public void findsDifferencesInListTraitValues() { List messages = events.stream().map(ValidationEvent::getMessage).collect(Collectors.toList()); assertThat(events, hasSize(4)); + assertThat(events.stream().filter(e -> e.getMessage().contains("Removed")) + .filter(e -> e.getSourceLocation().getFilename().endsWith("a.smithy")).count(), equalTo(2L)); + assertThat(events.stream().filter(e -> !e.getMessage().contains("Removed")) + .filter(e -> e.getSourceLocation().getFilename().endsWith("b.smithy")).count(), equalTo(2L)); assertThat(messages, containsInAnyOrder( "Changed trait contents of `smithy.example#aTrait` at path `/foo/1` from \"b\" to \"B\"", "Added trait contents to `smithy.example#aTrait` at path `/foo/3` with value \"4\"", @@ -222,6 +232,10 @@ public void findsDifferencesInSetTraitValues() { List messages = events.stream().map(ValidationEvent::getMessage).collect(Collectors.toList()); assertThat(events, hasSize(4)); + assertThat(events.stream().filter(e -> e.getMessage().contains("Removed")) + .filter(e -> e.getSourceLocation().getFilename().endsWith("a.smithy")).count(), equalTo(2L)); + assertThat(events.stream().filter(e -> !e.getMessage().contains("Removed")) + .filter(e -> e.getSourceLocation().getFilename().endsWith("b.smithy")).count(), equalTo(2L)); assertThat(messages, containsInAnyOrder( "Changed trait contents of `smithy.example#aTrait` at path `/foo/1` from \"b\" to \"B\"", "Added trait contents to `smithy.example#aTrait` at path `/foo/3` with value \"4\"", @@ -244,6 +258,10 @@ public void findsDifferencesInMapTraitValues() { List messages = events.stream().map(ValidationEvent::getMessage).collect(Collectors.toList()); assertThat(events, hasSize(4)); + assertThat(events.stream().filter(e -> e.getMessage().contains("Removed")) + .filter(e -> e.getSourceLocation().getFilename().endsWith("a.smithy")).count(), equalTo(2L)); + assertThat(events.stream().filter(e -> !e.getMessage().contains("Removed")) + .filter(e -> e.getSourceLocation().getFilename().endsWith("b.smithy")).count(), equalTo(2L)); assertThat(messages, containsInAnyOrder( "Changed trait contents of `smithy.example#aTrait` at path `/foo/bam` from \"b\" to \"B\"", "Removed trait contents from `smithy.example#aTrait` at path `/foo`. Removed value: {\n \"baz\": \"1\",\n \"bam\": \"2\",\n \"boo\": \"3\"\n}", @@ -266,6 +284,8 @@ public void findsDifferencesInUnionTraitValues() { List messages = events.stream().map(ValidationEvent::getMessage).collect(Collectors.toList()); assertThat(events, hasSize(2)); + assertThat(events.stream().filter(e -> e.getSourceLocation().getFilename().endsWith("b.smithy")).count(), + equalTo(2L)); assertThat(messages, containsInAnyOrder( "Changed trait contents of `smithy.example#aTrait` at path `/baz/foo` from \"a\" to \"b\"", "Changed trait contents of `smithy.example#aTrait` at path `/baz/baz` from \"a\" to \"b\"" @@ -286,6 +306,10 @@ public void findsDifferencesInTraitValuesOfAllSeverities() { List messages = events.stream().map(ValidationEvent::getMessage).collect(Collectors.toList()); assertThat(events, hasSize(12)); + assertThat(events.stream().filter(e -> e.getMessage().contains("Removed")) + .filter(e -> e.getSourceLocation().getFilename().endsWith("a.smithy")).count(), equalTo(3L)); + assertThat(events.stream().filter(e -> e.getMessage().contains("Changed") || e.getMessage().contains("Added")) + .filter(e -> e.getSourceLocation().getFilename().endsWith("b.smithy")).count(), equalTo(9L)); assertThat(messages, containsInAnyOrder( "Added trait contents to `smithy.example#aTrait` at path `/a` with value \"a\"", "Removed trait contents from `smithy.example#aTrait` at path `/b`. Removed value: \"a\"", diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedEntityBindingTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedEntityBindingTest.java index 36c22dfa70b..7d1ce1cc22d 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedEntityBindingTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedEntityBindingTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.ResourceShape; import software.amazon.smithy.model.shapes.ServiceShape; @@ -30,11 +31,13 @@ public class RemovedEntityBindingTest { @Test public void detectsRemovedOperationFromService() { + SourceLocation source = new SourceLocation("foo.smithy"); OperationShape o = OperationShape.builder().id("foo.baz#Operation").build(); ServiceShape service1 = ServiceShape.builder() .version("1") .id("foo.baz#Service") .addOperation(o.getId()) + .source(source) .build(); ServiceShape service2 = service1.toBuilder().clearOperations().build(); Model modelA = Model.assembler().addShapes(service1, o).assemble().unwrap(); @@ -42,27 +45,32 @@ public void detectsRemovedOperationFromService() { List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "RemovedOperationBinding.FromService.Operation").size(), equalTo(1)); + assertThat(events.get(0).getSourceLocation(), equalTo(source)); } @Test public void detectsRemovedOperationFromResource() { + SourceLocation source = new SourceLocation("foo.smithy"); OperationShape o = OperationShape.builder().id("foo.baz#Operation").build(); - ResourceShape r1 = ResourceShape.builder().id("foo.baz#Resource").addOperation(o.getId()).build(); + ResourceShape r1 = ResourceShape.builder().id("foo.baz#Resource").addOperation(o.getId()).source(source).build(); ResourceShape r2 = r1.toBuilder().clearOperations().build(); Model modelA = Model.assembler().addShapes(r1, o).assemble().unwrap(); Model modelB = Model.assembler().addShapes(r2, o).assemble().unwrap(); List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "RemovedOperationBinding.FromResource.Operation").size(), equalTo(1)); + assertThat(events.get(0).getSourceLocation(), equalTo(source)); } @Test public void detectsRemovedResourceFromService() { + SourceLocation source = new SourceLocation("foo.smithy"); ResourceShape r = ResourceShape.builder().id("foo.baz#Resource").build(); ServiceShape service1 = ServiceShape.builder() .id("foo.baz#Service") .version("1") .addResource(r.getId()) + .source(source) .build(); ServiceShape service2 = service1.toBuilder().clearResources().build(); Model modelA = Model.assembler().addShapes(service1, r).assemble().unwrap(); @@ -70,17 +78,20 @@ public void detectsRemovedResourceFromService() { List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "RemovedResourceBinding.FromService.Resource").size(), equalTo(1)); + assertThat(events.get(0).getSourceLocation(), equalTo(source)); } @Test public void detectsRemovedResourceFromResource() { + SourceLocation source = new SourceLocation("foo.smithy"); ResourceShape child = ResourceShape.builder().id("foo.baz#C").build(); - ResourceShape p1 = ResourceShape.builder().id("foo.baz#P").addResource(child.getId()).build(); + ResourceShape p1 = ResourceShape.builder().id("foo.baz#P").addResource(child.getId()).source(source).build(); ResourceShape p2 = p1.toBuilder().clearResources().build(); Model modelA = Model.assembler().addShapes(p1, child).assemble().unwrap(); Model modelB = Model.assembler().addShapes(p2, child).assemble().unwrap(); List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "RemovedResourceBinding.FromResource.C").size(), equalTo(1)); + assertThat(events.get(0).getSourceLocation(), equalTo(source)); } } diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedOperationErrorTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedOperationErrorTest.java index 3c6ff908afb..70af4d2f8d5 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedOperationErrorTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedOperationErrorTest.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.StructureShape; @@ -32,6 +33,7 @@ public class RemovedOperationErrorTest { @Test public void detectsRemovedErrors() { + SourceLocation source = new SourceLocation("foo.smithy"); Shape e1 = StructureShape.builder() .id("foo.baz#E1") .addTrait(new ErrorTrait("client")) @@ -44,6 +46,7 @@ public void detectsRemovedErrors() { .id("foo.baz#Operation") .addError(e1) .addError(e2) + .source(source) .build(); Shape operation2 = operation1.toBuilder().clearErrors().build(); Model modelA = Model.assembler().addShapes(operation1, e1, e2).assemble().unwrap(); @@ -52,6 +55,7 @@ public void detectsRemovedErrors() { // Emits an event for each removal. assertThat(TestHelper.findEvents(events, "RemovedOperationError").size(), equalTo(2)); + assertThat(events.stream().filter(e -> e.getSourceLocation().equals(source)).count(), equalTo(2L)); assertThat(TestHelper.findEvents(events, "RemovedOperationError.E1").size(), equalTo(1)); assertThat(TestHelper.findEvents(events, "RemovedOperationError.E2").size(), equalTo(1)); assertThat(TestHelper.findEvents(events, "RemovedOperationError").get(0).toString(), diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedTraitDefinitionTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedTraitDefinitionTest.java index 59b27c7d158..5fdf3d2ebe0 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedTraitDefinitionTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedTraitDefinitionTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.StringShape; import software.amazon.smithy.model.traits.TraitDefinition; @@ -30,9 +31,10 @@ public class RemovedTraitDefinitionTest { @Test public void detectsRemovedTraitDefinition() { + SourceLocation source = new SourceLocation("bar.smithy"); Shape definition = StringShape.builder() .id("foo.baz#bam") - .addTrait(TraitDefinition.builder().build()) + .addTrait(TraitDefinition.builder().sourceLocation(source).build()) .build(); Model modelA = Model.assembler().addShape(definition).assemble().unwrap(); @@ -40,5 +42,7 @@ public void detectsRemovedTraitDefinition() { List events = ModelDiff.compare(modelA, modelB); assertThat(TestHelper.findEvents(events, "RemovedTraitDefinition").size(), equalTo(1)); + assertThat(TestHelper.findEvents(events, "RemovedTraitDefinition").get(0).getSourceLocation(), + equalTo(source)); } } diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ServiceRenameTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ServiceRenameTest.java index f94d572081b..aa9a584d62e 100644 --- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ServiceRenameTest.java +++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ServiceRenameTest.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test; import software.amazon.smithy.diff.ModelDiff; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.ServiceShape; import software.amazon.smithy.model.validation.Severity; @@ -48,6 +49,7 @@ public static void before() { @Test public void detectsRenameRemoved() { + SourceLocation source = new SourceLocation("foo.smithy"); ServiceShape service1 = service.toBuilder() .putRename(operation.getId(), "O1") .build(); @@ -57,6 +59,7 @@ public void detectsRenameRemoved() { ServiceShape service2 = service.toBuilder() .clearRename() + .source(source) .build(); Model modelB = modelA.toBuilder().addShape(service2).build(); @@ -64,10 +67,12 @@ public void detectsRenameRemoved() { assertThat(TestHelper.findEvents(events, "ServiceRename").size(), equalTo(1)); assertThat(TestHelper.findEvents(events, service2.getId()).size(), equalTo(1)); assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(1)); + assertThat(events.get(0).getSourceLocation(), equalTo(source)); } @Test public void detectsRenameChange() { + SourceLocation source = new SourceLocation("foo.smithy"); ServiceShape service1 = service.toBuilder() .putRename(operation.getId(), "O1") .build(); @@ -77,6 +82,7 @@ public void detectsRenameChange() { ServiceShape service2 = service.toBuilder() .putRename(operation.getId(), "O2") + .source(source) .build(); Model modelB = modelA.toBuilder().addShape(service2).build(); @@ -84,16 +90,19 @@ public void detectsRenameChange() { assertThat(TestHelper.findEvents(events, "ServiceRename").size(), equalTo(1)); assertThat(TestHelper.findEvents(events, service2.getId()).size(), equalTo(1)); assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(1)); + assertThat(events.get(0).getSourceLocation(), equalTo(source)); } @Test public void detectsRenameAdded() { + SourceLocation source = new SourceLocation("foo.smithy"); Model modelA = Model.builder() .addShapes(operation, service) .build(); ServiceShape service2 = service.toBuilder() .putRename(operation.getId(), "O2") + .source(source) .build(); Model modelB = modelA.toBuilder().addShape(service2).build(); @@ -102,6 +111,7 @@ public void detectsRenameAdded() { assertThat(TestHelper.findEvents(events, "ServiceRename").size(), equalTo(1)); assertThat(TestHelper.findEvents(events, service2.getId()).size(), equalTo(1)); assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(1)); + assertThat(events.get(0).getSourceLocation(), equalTo(source)); } @Test diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/shapes/EnumShape.java b/smithy-model/src/main/java/software/amazon/smithy/model/shapes/EnumShape.java index 95f8d7666a5..39eeb3c0258 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/shapes/EnumShape.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/shapes/EnumShape.java @@ -24,6 +24,7 @@ import java.util.logging.Logger; import java.util.regex.Pattern; import software.amazon.smithy.model.SourceException; +import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.traits.DeprecatedTrait; import software.amazon.smithy.model.traits.DocumentationTrait; import software.amazon.smithy.model.traits.EnumDefinition; @@ -517,5 +518,10 @@ public Builder flattenMixins() { members(NamedMemberUtils.flattenMixins(members.get(), getMixins(), getId(), getSourceLocation())); return (Builder) super.flattenMixins(); } + + @Override + public Builder source(SourceLocation source) { + return (Builder) super.source(source); + } } }