Repository: smithy-lang/smithy
Pull request #1975 (2023-09-12 00:37:26)

Fixed duplicate NoninclusiveTerms events
*Description of changes:*

Previously, the testcase

`"smithy.api#examples": [
                    {
                        "MasterUsername": "master"
                    }
                ]`

would produce the following ValidationEvents

``[WARNING] ns.foo#A: 'examples' trait value at path {0/MasterUsername} contains a non-inclusive term `Master`. Consider using one of the following terms instead: `Main`, `Parent`, `Primary` | NoninclusiveTerms.Trait.master.examples.0/MasterUsername``
``[WARNING] ns.foo#A: 'examples' trait value at path {0/MasterUsername} contains a non-inclusive term `master`. Consider using one of the following terms instead: `main`, `parent`, `primary` | NoninclusiveTerms.Trait.master.examples.0/MasterUsername``

Now, it will add `/key` to the TextIndex path when referencing a the key, to produce

``
[WARNING] ns.foo#A: 'examples' trait value at path {0/MasterUsername/key} contains a non-inclusive term `Master`. Consider using one of the following terms instead: `Main`, `Parent`, `Primary` | NoninclusiveTerms.Trait.master.examples.0/MasterUsername/key
``
``
[WARNING] ns.foo#A: 'examples' trait value at path {0/MasterUsername} contains a non-inclusive term `master`. Consider using one of the following terms instead: `main`, `parent`, `primary` | NoninclusiveTerms.Trait.master.examples.0/MasterUsername
``


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.


kstich: >which seems more dangerous in my opinion. 

What is dangerous about this approach? The portion of the id altered (`.toLowerCase()` call inside `.id()`) is done in this same case statement.

However, this approach may still be preferable since there's little difference in what to change here.
rchache: I believe changing (not extending) event ids of validation events is dangerous, as it could break consumers who have tests on the expected output events. 

Patch:
diff --git a/smithy-cli/src/main/java/software/amazon/smithy/cli/dependencies/FileCacheResolver.java b/smithy-cli/src/main/java/software/amazon/smithy/cli/dependencies/FileCacheResolver.java
index cbb33c80b..3c439f7e0 100644
--- a/smithy-cli/src/main/java/software/amazon/smithy/cli/dependencies/FileCacheResolver.java
+++ b/smithy-cli/src/main/java/software/amazon/smithy/cli/dependencies/FileCacheResolver.java
@@ -21,6 +21,7 @@ import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -39,7 +40,6 @@ import software.amazon.smithy.model.node.ObjectNode;
  * given reference point in time.
  */
 public final class FileCacheResolver implements DependencyResolver {
-    private static final String CURRENT_CACHE_FILE_VERSION = "1.0";
 
     // This is hard-coded for now to 1 day, and it can become an environment variable in the future if needed.
     private static final Duration SMITHY_MAVEN_TTL = Duration.parse("P1D");
@@ -113,28 +113,17 @@ public final class FileCacheResolver implements DependencyResolver {
             throw new DependencyResolverException("Error loading dependency cache file from " + location, e);
         }
 
-        // If the version of the cache file does not match the current version or does not exist
-        // invalidate it so we can replace it with a more recent version.
-        if (!node.containsMember("version")
-                || !CURRENT_CACHE_FILE_VERSION.equals(node.expectStringMember("version").getValue())
-        ) {
-            LOGGER.fine(() -> "Invalidating dependency cache: cache file uses old version");
-            invalidate();
-            return Collections.emptyList();
-        }
-
-        ObjectNode artifactNode = node.expectObjectMember("artifacts");
-        List<ResolvedArtifact> result = new ArrayList<>(artifactNode.getStringMap().size());
-        for (Map.Entry<String, Node> entry : artifactNode.getStringMap().entrySet()) {
-            ResolvedArtifact artifact = ResolvedArtifact.fromNode(entry.getKey(), entry.getValue());
-            long lastModifiedOfArtifact = artifact.getLastModified();
+        List<ResolvedArtifact> result = new ArrayList<>(node.getStringMap().size());
+        for (Map.Entry<String, Node> entry : node.getStringMap().entrySet()) {
+            Path artifactLocation = Paths.get(entry.getValue().expectStringNode().getValue());
+            long lastModifiedOfArtifact = artifactLocation.toFile().lastModified();
             // Invalidate the cache if the JAR file was updated since the cache was created.
             if (lastModifiedOfArtifact == 0 || lastModifiedOfArtifact > cacheLastModifiedMillis) {
-                LOGGER.fine(() -> "Invalidating dependency cache: artifact is newer than cache: " + artifact.getPath());
+                LOGGER.fine(() -> "Invalidating dependency cache: artifact is newer than cache: " + artifactLocation);
                 invalidate();
                 return Collections.emptyList();
             }
-            result.add(artifact);
+            result.add(ResolvedArtifact.fromCoordinates(artifactLocation, entry.getKey()));
         }
 
         return result;
@@ -150,13 +139,11 @@ public final class FileCacheResolver implements DependencyResolver {
         try {
             Files.createDirectories(parent);
             ObjectNode.Builder builder = Node.objectNodeBuilder();
-            builder.withMember("version", CURRENT_CACHE_FILE_VERSION);
-            ObjectNode.Builder artifactNodeBuilder = Node.objectNodeBuilder();
             for (ResolvedArtifact artifact : result) {
-                artifactNodeBuilder.withMember(artifact.getCoordinates(), artifact.toNode());
+                builder.withMember(artifact.getCoordinates(), artifact.getPath().toString());
             }
-            builder.withMember("artifacts", artifactNodeBuilder.build());
-            Files.write(filePath, Node.printJson(builder.build()).getBytes(StandardCharsets.UTF_8));
+            ObjectNode objectNode = builder.build();
+            Files.write(filePath, Node.printJson(objectNode).getBytes(StandardCharsets.UTF_8));
         } catch (IOException e) {
             throw new DependencyResolverException("Unable to write classpath cache file: " + e.getMessage(), e);
         }
diff --git a/smithy-cli/src/main/java/software/amazon/smithy/cli/dependencies/ResolvedArtifact.java b/smithy-cli/src/main/java/software/amazon/smithy/cli/dependencies/ResolvedArtifact.java
index 8079848ed..ab42f1bf9 100644
--- a/smithy-cli/src/main/java/software/amazon/smithy/cli/dependencies/ResolvedArtifact.java
+++ b/smithy-cli/src/main/java/software/amazon/smithy/cli/dependencies/ResolvedArtifact.java
@@ -16,39 +16,26 @@
 package software.amazon.smithy.cli.dependencies;
 
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Objects;
-import software.amazon.smithy.model.node.Node;
-import software.amazon.smithy.model.node.ObjectNode;
-import software.amazon.smithy.model.node.ToNode;
-import software.amazon.smithy.utils.IoUtils;
 
 /**
  * An artifact resolved from a repository that provides the path on disk where the artifact
  * was downloaded, and the coordinates of the artifact.
  */
-public final class ResolvedArtifact implements ToNode {
-    private static final String SHA_SUM_MEMBER_NAME = "shaSum";
-    private static final String PATH_MEMBER_NAME = "path";
-
+public final class ResolvedArtifact {
     private final Path path;
     private final String coordinates;
     private final String groupId;
     private final String artifactId;
     private final String version;
-    private final String shaSum;
 
     public ResolvedArtifact(Path path, String groupId, String artifactId, String version) {
-        this(path, groupId + ':' + artifactId + ':' + version, groupId, artifactId,
-                version, IoUtils.computeSha256(path));
+        this(path, groupId + ':' + artifactId + ':' + version, groupId, artifactId, version);
     }
 
-    private ResolvedArtifact(Path path, String coordinates, String groupId, String artifactId,
-                             String version, String shaSum
-    ) {
+    private ResolvedArtifact(Path path, String coordinates, String groupId, String artifactId, String version) {
         this.coordinates = Objects.requireNonNull(coordinates);
         this.path = Objects.requireNonNull(path);
-        this.shaSum = Objects.requireNonNull(shaSum);
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.version = version;
@@ -57,21 +44,17 @@ public final class ResolvedArtifact implements ToNode {
     /**
      * Creates a resolved artifact from a file path and Maven coordinates string.
      *
+     * @param location    Location of the artifact.
      * @param coordinates Maven coordinates (e.g., group:artifact:version).
-     * @param node Node containing the resolved artifact data.
      * @return Returns the created artifact.
      * @throws DependencyResolverException if the provided coordinates are invalid.
      */
-    public static ResolvedArtifact fromNode(String coordinates, Node node) {
+    public static ResolvedArtifact fromCoordinates(Path location, String coordinates) {
         String[] parts = coordinates.split(":");
         if (parts.length != 3) {
             throw new DependencyResolverException("Invalid Maven coordinates: " + coordinates);
         }
-        ObjectNode objectNode = node.expectObjectNode();
-        Path location = Paths.get(objectNode.expectMember(PATH_MEMBER_NAME).expectStringNode().getValue());
-        String shaSum = objectNode.expectMember(SHA_SUM_MEMBER_NAME).expectStringNode().getValue();
-
-        return new ResolvedArtifact(location, coordinates, parts[0], parts[1], parts[2], shaSum);
+        return new ResolvedArtifact(location, coordinates, parts[0], parts[1], parts[2]);
     }
 
     /**
@@ -113,28 +96,14 @@ public final class ResolvedArtifact implements ToNode {
         return version;
     }
 
-    /**
-     * @return Get the sha256 digest of the artifact.
-     */
-    public String getShaSum() {
-        return shaSum;
-    }
-
-    /**
-     * @return Get the last time the artifact was modified.
-     */
-    public long getLastModified() {
-        return path.toFile().lastModified();
-    }
-
     @Override
     public String toString() {
-        return "{path=" + path + ", coordinates='" + coordinates + ", shaSum='" + shaSum + "'}";
+        return "{path=" + path + ", coordinates='" + coordinates + "'}";
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(coordinates, path, shaSum);
+        return Objects.hash(coordinates, path);
     }
 
     @Override
@@ -145,16 +114,6 @@ public final class ResolvedArtifact implements ToNode {
             return false;
         }
         ResolvedArtifact artifact = (ResolvedArtifact) o;
-        return path.equals(artifact.path)
-                && shaSum.equals(artifact.shaSum)
-                && coordinates.equals(artifact.coordinates);
-    }
-
-    @Override
-    public Node toNode() {
-        return Node.objectNodeBuilder()
-                .withMember(PATH_MEMBER_NAME, path.toString())
-                .withMember(SHA_SUM_MEMBER_NAME, shaSum)
-                .build();
+        return path.equals(artifact.path) && coordinates.equals(artifact.coordinates);
     }
 }
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/TextIndex.java b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/TextIndex.java
index 3525f2bf1..056dbbacb 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/TextIndex.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/TextIndex.java
@@ -105,8 +105,10 @@ public final class TextIndex implements KnowledgeIndex {
                 if (memberTypeShape == null) {
                     //This means the "property" key value isn't modeled in the trait's structure/shape definition
                     //and this text instance is unique
+                    propertyPath.offerLast("key");
                     textInstances.add(TextInstance.createTraitInstance(
                         memberEntry.getKey(), parentShape, trait, propertyPath));
+                    propertyPath.removeLast();
                 }
                 computeTextInstancesForAppliedTrait(memberEntry.getValue(), trait, parentShape, textInstances,
                         propertyPath, model, memberTypeShape);
diff --git a/smithy-utils/src/main/java/software/amazon/smithy/utils/IoUtils.java b/smithy-utils/src/main/java/software/amazon/smithy/utils/IoUtils.java
index 33c5c5a0a..1a5107cf4 100644
--- a/smithy-utils/src/main/java/software/amazon/smithy/utils/IoUtils.java
+++ b/smithy-utils/src/main/java/software/amazon/smithy/utils/IoUtils.java
@@ -31,9 +31,6 @@ import java.nio.file.Paths;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.StandardCopyOption;
 import java.nio.file.attribute.BasicFileAttributes;
-import java.security.DigestInputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -155,40 +152,6 @@ public final class IoUtils {
         }
     }
 
-    /**
-     * Computes the sha256 digest of a file.
-     *
-     * @param path Path to file to compute hash for.
-     * @return sha256 digest string.
-     * @throws UncheckedIOException if the specified file could not be read.
-     */
-    public static String computeSha256(Path path) {
-        try (InputStream in = Files.newInputStream(path)) {
-            MessageDigest md = MessageDigest.getInstance("SHA-256");
-            try (DigestInputStream din = new DigestInputStream(in, md)) {
-                byte[] buf = new byte[8192];
-                int n;
-                do {
-                    n = din.read(buf);
-                } while (n > 0);
-            }
-            StringBuilder sb = new StringBuilder();
-            for (byte b : md.digest()) {
-                int decimal = (int) b & 0xff;
-                String hex = Integer.toHexString(decimal);
-                if (hex.length() == 1) {
-                    sb.append('0');
-                }
-                sb.append(hex);
-            }
-            return sb.toString();
-        } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException(e);
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
-        }
-    }
-
     /**
      * Helper to run a process.
      *


Test patch:
diff --git a/smithy-cli/src/it/java/software/amazon/smithy/cli/MavenResolverTest.java b/smithy-cli/src/it/java/software/amazon/smithy/cli/MavenResolverTest.java
index 27052529f..40bb424a8 100644
--- a/smithy-cli/src/it/java/software/amazon/smithy/cli/MavenResolverTest.java
+++ b/smithy-cli/src/it/java/software/amazon/smithy/cli/MavenResolverTest.java
@@ -154,9 +154,8 @@ public class MavenResolverTest {
             String cacheContents = result.getFile("build", "smithy", "classpath.json");
 
             ObjectNode node = Node.parse(cacheContents).expectObjectNode();
-            ObjectNode artifacts = node.expectObjectMember("artifacts");
-            String location = artifacts.expectObjectMember("software.amazon.smithy:smithy-aws-traits:"
-                                                      + TEST_VERSION).expectStringMember("path").getValue();
+            String location = node.expectStringMember("software.amazon.smithy:smithy-aws-traits:"
+                                                      + TEST_VERSION).getValue();
 
             // Set the lastModified of the JAR to the current time, which is > than the time of the config file,
             // so the cache is invalided.
diff --git a/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/FileCacheResolverTest.java b/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/FileCacheResolverTest.java
index 26e9aea97..629219eb4 100644
--- a/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/FileCacheResolverTest.java
+++ b/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/FileCacheResolverTest.java
@@ -11,7 +11,6 @@ import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
-import java.nio.file.Path;
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Date;
@@ -19,7 +18,6 @@ import java.util.List;
 import java.util.function.Consumer;
 import org.junit.jupiter.api.Test;
 import software.amazon.smithy.build.model.MavenRepository;
-import software.amazon.smithy.model.node.Node;
 import software.amazon.smithy.utils.IoUtils;
 import software.amazon.smithy.utils.ListUtils;
 
@@ -43,7 +41,7 @@ public class FileCacheResolverTest {
         File jar = File.createTempFile("foo", ".json");
 
         List<ResolvedArtifact> result = ListUtils.of(
-                ResolvedArtifact.fromNode("com.foo:bar:1.0.0", getNodeForPath(jar.toPath())));
+                ResolvedArtifact.fromCoordinates(jar.toPath(), "com.foo:bar:1.0.0"));
         Mock mock = new Mock(result);
         DependencyResolver resolver = new FileCacheResolver(cache, System.currentTimeMillis(), mock);
 
@@ -69,8 +67,7 @@ public class FileCacheResolverTest {
         File jar = File.createTempFile("foo", ".jar");
         Files.write(jar.toPath(), "{}".getBytes(StandardCharsets.UTF_8));
 
-        ResolvedArtifact artifact = ResolvedArtifact.fromNode("com.foo:bar:1.0.0",
-                getNodeForPath(jar.toPath()));
+        ResolvedArtifact artifact = ResolvedArtifact.fromCoordinates(jar.toPath(), "com.foo:bar:1.0.0");
         List<ResolvedArtifact> result = new ArrayList<>();
         result.add(artifact);
 
@@ -107,8 +104,7 @@ public class FileCacheResolverTest {
         File jar = File.createTempFile("foo", ".jar");
         Files.write(jar.toPath(), "{}".getBytes(StandardCharsets.UTF_8));
 
-        ResolvedArtifact artifact = ResolvedArtifact.fromNode("com.foo:bar:1.0.0",
-                getNodeForPath(jar.toPath()));
+        ResolvedArtifact artifact = ResolvedArtifact.fromCoordinates(jar.toPath(), "com.foo:bar:1.0.0");
         List<ResolvedArtifact> result = new ArrayList<>();
         result.add(artifact);
 
@@ -139,8 +135,7 @@ public class FileCacheResolverTest {
         File jar = File.createTempFile("foo", ".jar");
         Files.write(jar.toPath(), "{}".getBytes(StandardCharsets.UTF_8));
 
-        ResolvedArtifact artifact = ResolvedArtifact.fromNode("com.foo:bar:1.0.0",
-                getNodeForPath(jar.toPath()));
+        ResolvedArtifact artifact = ResolvedArtifact.fromCoordinates(jar.toPath(), "com.foo:bar:1.0.0");
         List<ResolvedArtifact> result = new ArrayList<>();
         result.add(artifact);
 
@@ -187,11 +182,4 @@ public class FileCacheResolverTest {
             return artifacts;
         }
     }
-
-    private static Node getNodeForPath(Path path) {
-        return Node.objectNodeBuilder()
-                .withMember("path", path.toString())
-                .withMember("shaSum", IoUtils.computeSha256(path))
-                .build();
-    }
 }
diff --git a/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/FilterCliVersionResolverTest.java b/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/FilterCliVersionResolverTest.java
index 413b0f2a3..8ef15ebbe 100644
--- a/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/FilterCliVersionResolverTest.java
+++ b/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/FilterCliVersionResolverTest.java
@@ -4,13 +4,13 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.empty;
 
+import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import software.amazon.smithy.build.model.MavenRepository;
-import software.amazon.smithy.model.node.Node;
 import software.amazon.smithy.utils.ListUtils;
 
 public class FilterCliVersionResolverTest {
@@ -52,17 +52,17 @@ public class FilterCliVersionResolverTest {
             @Override
             public List<ResolvedArtifact> resolve() {
                 return Arrays.asList(
-                    ResolvedArtifact.fromNode("software.amazon.smithy:smithy-model:1.25.0", getNodeForPath("/a")),
-                    ResolvedArtifact.fromNode("software.amazon.smithy:smithy-utils:1.25.0", getNodeForPath("/b")),
-                    ResolvedArtifact.fromNode("software.amazon.smithy:smithy-other:1.25.0", getNodeForPath("/c")),
-                    ResolvedArtifact.fromNode("software.amazon.foo:foo-other:1.0.0", getNodeForPath("/d"))
+                    ResolvedArtifact.fromCoordinates(Paths.get("/a"), "software.amazon.smithy:smithy-model:1.25.0"),
+                    ResolvedArtifact.fromCoordinates(Paths.get("/b"), "software.amazon.smithy:smithy-utils:1.25.0"),
+                    ResolvedArtifact.fromCoordinates(Paths.get("/c"), "software.amazon.smithy:smithy-other:1.25.0"),
+                    ResolvedArtifact.fromCoordinates(Paths.get("/d"), "software.amazon.foo:foo-other:1.0.0")
                 );
             }
         });
 
         assertThat(filter.resolve(), contains(
-            ResolvedArtifact.fromNode("software.amazon.smithy:smithy-other:1.25.0", getNodeForPath("/c")),
-            ResolvedArtifact.fromNode("software.amazon.foo:foo-other:1.0.0", getNodeForPath("/d"))
+            ResolvedArtifact.fromCoordinates(Paths.get("/c"), "software.amazon.smithy:smithy-other:1.25.0"),
+            ResolvedArtifact.fromCoordinates(Paths.get("/d"), "software.amazon.foo:foo-other:1.0.0")
         ));
     }
 
@@ -81,18 +81,11 @@ public class FilterCliVersionResolverTest {
 
             @Override
             public List<ResolvedArtifact> resolve() {
-                return ListUtils.of(ResolvedArtifact.fromNode("software.amazon.smithy:smithy-model:1.27.0",
-                        getNodeForPath("/a")));
+                return ListUtils.of(ResolvedArtifact.fromCoordinates(Paths.get("/a"),
+                                                                     "software.amazon.smithy:smithy-model:1.27.0"));
             }
         });
 
         Assertions.assertThrows(DependencyResolverException.class, filter::resolve);
     }
-
-    private static Node getNodeForPath(String pathStr) {
-        return Node.objectNodeBuilder()
-                .withMember("path", pathStr)
-                .withMember("shaSum", pathStr)
-                .build();
-    }
 }
diff --git a/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/ResolvedArtifactTest.java b/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/ResolvedArtifactTest.java
index c6b7f2705..eb4ea7b40 100644
--- a/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/ResolvedArtifactTest.java
+++ b/smithy-cli/src/test/java/software/amazon/smithy/cli/dependencies/ResolvedArtifactTest.java
@@ -3,34 +3,28 @@ package software.amazon.smithy.cli.dependencies;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 
-import java.net.URISyntaxException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.Objects;
-
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
-import software.amazon.smithy.model.node.Node;
 
 public class ResolvedArtifactTest {
     @Test
-    public void loadsFromNode() {
+    public void loadsFromCoordinates() {
+        Path path = Paths.get("/a");
         String coordinates = "com.foo:baz-bam:1.2.0";
+        ResolvedArtifact artifact = ResolvedArtifact.fromCoordinates(path, coordinates);
 
-        ResolvedArtifact artifact = ResolvedArtifact.fromNode(coordinates, getNodeForPath());
-
-        assertThat(artifact.getPath(), equalTo(Paths.get("/a")));
+        assertThat(artifact.getPath(), equalTo(path));
         assertThat(artifact.getCoordinates(), equalTo(coordinates));
         assertThat(artifact.getGroupId(), equalTo("com.foo"));
         assertThat(artifact.getArtifactId(), equalTo("baz-bam"));
         assertThat(artifact.getVersion(), equalTo("1.2.0"));
-        assertThat(artifact.getShaSum(), equalTo("sum"));
     }
 
     @Test
-    public void createsCoordinatesStringFromParts() throws URISyntaxException {
-        Path path =  Paths.get(Objects.requireNonNull(getClass().getResource("test.txt")).toURI());
-
+    public void createsCoordinatesStringFromParts() {
+        Path path = Paths.get("/a");
         ResolvedArtifact artifact = new ResolvedArtifact(path, "com.foo", "baz-bam", "1.2.0");
 
         assertThat(artifact.getPath(), equalTo(path));
@@ -42,22 +36,19 @@ public class ResolvedArtifactTest {
 
     @Test
     public void validatesCoordinatesNotTooManyParts() {
+        Path path = Paths.get("/a");
         String coordinates = "com.foo:baz-bam:1.2.0:boo";
+
         Assertions.assertThrows(DependencyResolverException.class,
-                                () -> ResolvedArtifact.fromNode(coordinates, getNodeForPath()));
+                                () -> ResolvedArtifact.fromCoordinates(path, coordinates));
     }
 
     @Test
     public void validatesCoordinatesEnoughParts() {
+        Path path = Paths.get("/a");
         String coordinates = "com.foo:baz-bam";
-        Assertions.assertThrows(DependencyResolverException.class,
-                                () -> ResolvedArtifact.fromNode(coordinates, getNodeForPath()));
-    }
 
-    private static Node getNodeForPath() {
-        return Node.objectNodeBuilder()
-                .withMember("path", "/a")
-                .withMember("shaSum", "sum")
-                .build();
+        Assertions.assertThrows(DependencyResolverException.class,
+                                () -> ResolvedArtifact.fromCoordinates(path, coordinates));
     }
 }
diff --git a/smithy-cli/src/test/resources/software/amazon/smithy/cli/dependencies/test.txt b/smithy-cli/src/test/resources/software/amazon/smithy/cli/dependencies/test.txt
deleted file mode 100644
index 484ba93ef..000000000
--- a/smithy-cli/src/test/resources/software/amazon/smithy/cli/dependencies/test.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-This is a test.
diff --git a/smithy-linters/src/test/resources/software/amazon/smithy/linters/errorfiles/noninclusive-term-filter.errors b/smithy-linters/src/test/resources/software/amazon/smithy/linters/errorfiles/noninclusive-term-filter.errors
index 50e535aea..535e9af21 100644
--- a/smithy-linters/src/test/resources/software/amazon/smithy/linters/errorfiles/noninclusive-term-filter.errors
+++ b/smithy-linters/src/test/resources/software/amazon/smithy/linters/errorfiles/noninclusive-term-filter.errors
@@ -7,7 +7,10 @@
 [WARNING] ns.foo#AOutput: 'ns.foo#MyWhitelistTrait' trait value at path {document/foo/0/bar} contains a non-inclusive term `whitelist`. Consider using one of the following terms instead: `allowList` | NoninclusiveTerms.Trait.whitelist.ns.foo#MyWhitelistTrait.document/foo/0/bar
 [WARNING] ns.foo#AOutput: 'ns.foo#MyWhitelistTrait' trait value at path {nested/master_key_violation} contains a non-inclusive term `whitelist`. Consider using one of the following terms instead: `allowList` | NoninclusiveTerms.Trait.whitelist.ns.foo#MyWhitelistTrait.nested/master_key_violation
 [WARNING] ns.foo#AOutput: 'ns.foo#MyWhitelistTrait' trait value at path {string_value} contains a non-inclusive term `whitelist`. Consider using one of the following terms instead: `allowList` | NoninclusiveTerms.Trait.whitelist.ns.foo#MyWhitelistTrait.string_value
-[WARNING] ns.foo#AOutput: 'ns.foo#MyWhitelistTrait' trait value at path {document/whitelist_doc_key_violation_1} contains a non-inclusive term `whitelist`. Consider using one of the following terms instead: `allowList` | NoninclusiveTerms.Trait.whitelist.ns.foo#MyWhitelistTrait.document/whitelist_doc_key_violation_1
+[WARNING] ns.foo#AOutput: 'ns.foo#MyWhitelistTrait' trait value at path {document/whitelist_doc_key_violation_1/key} contains a non-inclusive term `whitelist`. Consider using one of the following terms instead: `allowList` | NoninclusiveTerms.Trait.whitelist.ns.foo#MyWhitelistTrait.document/whitelist_doc_key_violation_1/key
 [WARNING] ns.foo#AOutput: 'ns.foo#MyWhitelistTrait' trait value at path {collection/2/key} contains a non-inclusive term `whitelist`. Consider using one of the following terms instead: `allowList` | NoninclusiveTerms.Trait.whitelist.ns.foo#MyWhitelistTrait.collection/2/key
-[WARNING] ns.foo#AOutput: 'ns.foo#MyWhitelistTrait' trait value at path {collection/1/blacklist_key} contains a non-inclusive term `blacklist`. Consider using one of the following terms instead: `denyList` | NoninclusiveTerms.Trait.blacklist.ns.foo#MyWhitelistTrait.collection/1/blacklist_key
+[WARNING] ns.foo#AOutput: 'ns.foo#MyWhitelistTrait' trait value at path {collection/1/blacklist_key/key} contains a non-inclusive term `blacklist`. Consider using one of the following terms instead: `denyList` | NoninclusiveTerms.Trait.blacklist.ns.foo#MyWhitelistTrait.collection/1/blacklist_key/key
 [WARNING] ns.foo#MyUnionTrait$int_whitelist: Member shape uses a non-inclusive term `whitelist`. Consider using one of the following terms instead: `allowList` | NoninclusiveTerms.Shape.whitelist
+[WARNING] ns.foo#A: Error validating trait `examples`.0: Invalid structure member `MasterUsername` found for `smithy.api#Example` | TraitValue.smithy.api#Example.MasterUsername
+[WARNING] ns.foo#A: 'examples' trait value at path {0/MasterUsername/key} contains a non-inclusive term `Master`. Consider using one of the following terms instead: `Main`, `Parent`, `Primary` | NoninclusiveTerms.Trait.master.examples.0/MasterUsername/key
+[WARNING] ns.foo#A: 'examples' trait value at path {0/MasterUsername} contains a non-inclusive term `master`. Consider using one of the following terms instead: `main`, `parent`, `primary` | NoninclusiveTerms.Trait.master.examples.0/MasterUsername
diff --git a/smithy-linters/src/test/resources/software/amazon/smithy/linters/errorfiles/noninclusive-term-filter.json b/smithy-linters/src/test/resources/software/amazon/smithy/linters/errorfiles/noninclusive-term-filter.json
index 62ab36088..c09034ab8 100644
--- a/smithy-linters/src/test/resources/software/amazon/smithy/linters/errorfiles/noninclusive-term-filter.json
+++ b/smithy-linters/src/test/resources/software/amazon/smithy/linters/errorfiles/noninclusive-term-filter.json
@@ -76,7 +76,13 @@
                 "target": "ns.foo#AOutput"
             },
             "traits": {
-                "smithy.api#readonly": {}
+                "smithy.api#readonly": {},
+                "smithy.api#examples": [
+                    {
+                        "title": "testing noninclusive key and value",
+                        "MasterUsername": "master"
+                    }
+                ]
             }
         },
         "ns.foo#AInput": {
diff --git a/smithy-utils/src/test/java/software/amazon/smithy/utils/IoUtilsTest.java b/smithy-utils/src/test/java/software/amazon/smithy/utils/IoUtilsTest.java
index 85f8c6ca5..0636226db 100644
--- a/smithy-utils/src/test/java/software/amazon/smithy/utils/IoUtilsTest.java
+++ b/smithy-utils/src/test/java/software/amazon/smithy/utils/IoUtilsTest.java
@@ -30,7 +30,6 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.Objects;
 import java.util.Random;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
@@ -149,12 +148,4 @@ public class IoUtilsTest {
 
         Files.delete(path);
     }
-
-    @Test
-    public void computesCorrectShaHash() throws URISyntaxException {
-        // Expected sha was computed using the `sha256sum` command line utility
-        String expectedSha = "4c5a232ddc90924079fd73170b97a6c32a8132437d37ca622cc70b1024396693";
-        String shaHash = IoUtils.computeSha256(Paths.get(Objects.requireNonNull(getClass().getResource("sha-test.txt")).toURI()));
-        assertEquals(shaHash, expectedSha);
-    }
 }
diff --git a/smithy-utils/src/test/resources/software/amazon/smithy/utils/sha-test.txt b/smithy-utils/src/test/resources/software/amazon/smithy/utils/sha-test.txt
deleted file mode 100644
index 8058eda3a..000000000
--- a/smithy-utils/src/test/resources/software/amazon/smithy/utils/sha-test.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-Tests sha digest.
\ No newline at end of file