diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0758b7c..1a32c55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ jobs: runs-on: ${{ matrix.os }} name: Java ${{ matrix.java }} ${{ matrix.os }} strategy: + fail-fast: false matrix: java: [8, 11, 17] os: [ubuntu-latest, windows-latest, macos-latest] diff --git a/src/main/java/software/amazon/smithy/lsp/document/Document.java b/src/main/java/software/amazon/smithy/lsp/document/Document.java index 4f893cb..db3577d 100644 --- a/src/main/java/software/amazon/smithy/lsp/document/Document.java +++ b/src/main/java/software/amazon/smithy/lsp/document/Document.java @@ -561,7 +561,9 @@ private static int[] computeLineIndicies(StringBuilder buffer) { // Have to box sadly, unless there's some IntArray I'm not aware of. Maybe IntBuffer List indicies = new ArrayList<>(); indicies.add(0); - while ((next = buffer.indexOf(System.lineSeparator(), off)) != -1) { + // This works with \r\n line breaks by basically forgetting about the \r, since we don't actually + // care about the content of the line + while ((next = buffer.indexOf("\n", off)) != -1) { indicies.add(next + 1); off = next + 1; ++matchCount; diff --git a/src/main/java/software/amazon/smithy/lsp/handler/CompletionHandler.java b/src/main/java/software/amazon/smithy/lsp/handler/CompletionHandler.java index 2fbb692..c0c35ea 100644 --- a/src/main/java/software/amazon/smithy/lsp/handler/CompletionHandler.java +++ b/src/main/java/software/amazon/smithy/lsp/handler/CompletionHandler.java @@ -184,7 +184,7 @@ private static void addTextEdits(CompletionItem completionItem, ShapeId shapeId, } private static TextEdit getImportTextEdit(SmithyFile smithyFile, String importId) { - String insertText = "\n" + "use " + importId; + String insertText = System.lineSeparator() + "use " + importId; // We can only know where to put the import if there's already use statements, or a namespace if (smithyFile.getDocumentImports().isPresent()) { Range importsRange = smithyFile.getDocumentImports().get().importsRange(); diff --git a/src/main/java/software/amazon/smithy/lsp/project/ProjectLoader.java b/src/main/java/software/amazon/smithy/lsp/project/ProjectLoader.java index 625a3f7..d386705 100644 --- a/src/main/java/software/amazon/smithy/lsp/project/ProjectLoader.java +++ b/src/main/java/software/amazon/smithy/lsp/project/ProjectLoader.java @@ -66,6 +66,7 @@ private ProjectLoader() { * @return The loaded project */ public static Project loadDetached(String uri, String text) { + LOGGER.info("Loading detached project at " + uri); String asPath = UriAdapter.toPath(uri); ValidatedResult modelResult = Model.assembler() .addUnparsedModel(asPath, text) diff --git a/src/main/java/software/amazon/smithy/lsp/protocol/UriAdapter.java b/src/main/java/software/amazon/smithy/lsp/protocol/UriAdapter.java index bf2b53d..2b49e82 100644 --- a/src/main/java/software/amazon/smithy/lsp/protocol/UriAdapter.java +++ b/src/main/java/software/amazon/smithy/lsp/protocol/UriAdapter.java @@ -11,6 +11,7 @@ import java.net.URL; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; import java.util.logging.Logger; /** @@ -28,7 +29,7 @@ private UriAdapter() { */ public static String toPath(String uri) { if (uri.startsWith("file://")) { - return uri.replaceFirst("file://", ""); + return Paths.get(URI.create(uri)).toString(); } else if (isSmithyJarFile(uri)) { String decoded = decode(uri); return fixJarScheme(decoded); @@ -39,15 +40,15 @@ public static String toPath(String uri) { /** * @param path Path to convert to LSP URI * @return A URI representation of the given {@code path}, modified to have the - * correct scheme for jars + * correct scheme for our jars */ public static String toUri(String path) { - if (path.startsWith("/")) { - return "file://" + path; - } else if (path.startsWith("jar:file")) { + if (path.startsWith("jar:file")) { return path.replaceFirst("jar:file", "smithyjar"); - } else { + } else if (path.startsWith("smithyjar:")) { return path; + } else { + return Paths.get(path).toUri().toString(); } } diff --git a/src/test/java/software/amazon/smithy/lsp/LspMatchers.java b/src/test/java/software/amazon/smithy/lsp/LspMatchers.java index c315c9f..7c508e1 100644 --- a/src/test/java/software/amazon/smithy/lsp/LspMatchers.java +++ b/src/test/java/software/amazon/smithy/lsp/LspMatchers.java @@ -33,7 +33,7 @@ public void describeMismatchSafely(CompletionItem item, Description description) } public static Matcher makesEditedDocument(Document document, String expected) { - return new CustomTypeSafeMatcher("the right edit") { + return new CustomTypeSafeMatcher("makes an edited document " + expected) { @Override protected boolean matchesSafely(TextEdit item) { Document copy = document.copy(); diff --git a/src/test/java/software/amazon/smithy/lsp/RequestBuilders.java b/src/test/java/software/amazon/smithy/lsp/RequestBuilders.java index 9c4c057..2a033e5 100644 --- a/src/test/java/software/amazon/smithy/lsp/RequestBuilders.java +++ b/src/test/java/software/amazon/smithy/lsp/RequestBuilders.java @@ -6,6 +6,7 @@ package software.amazon.smithy.lsp; import java.net.URI; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -176,7 +177,7 @@ public DidOpen text(String text) { public DidOpenTextDocumentParams build() { if (text == null) { - text = IoUtils.readUtf8File(URI.create(uri).getPath()); + text = IoUtils.readUtf8File(Paths.get(URI.create(uri))); } return new DidOpenTextDocumentParams(new TextDocumentItem(uri, languageId, version, text)); } diff --git a/src/test/java/software/amazon/smithy/lsp/SmithyLanguageServerTest.java b/src/test/java/software/amazon/smithy/lsp/SmithyLanguageServerTest.java index a47904f..681fa75 100644 --- a/src/test/java/software/amazon/smithy/lsp/SmithyLanguageServerTest.java +++ b/src/test/java/software/amazon/smithy/lsp/SmithyLanguageServerTest.java @@ -24,16 +24,18 @@ import static software.amazon.smithy.lsp.SmithyMatchers.hasShapeWithId; import static software.amazon.smithy.lsp.SmithyMatchers.hasValue; import static software.amazon.smithy.lsp.UtilMatchers.anOptionalOf; +import static software.amazon.smithy.lsp.document.DocumentTest.safeString; +import static software.amazon.smithy.lsp.project.ProjectTest.toPath; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; import java.util.stream.Collectors; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionParams; @@ -72,10 +74,10 @@ public class SmithyLanguageServerTest { @Test public void runsSelector() throws Exception { - String model = "$version: \"2\"\n" + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" - + "string Foo\n"; + + "string Foo\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -87,7 +89,7 @@ public void runsSelector() throws Exception { @Test public void completion() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "structure Foo {\n" + @@ -95,7 +97,7 @@ public void completion() throws Exception { "}\n" + "\n" + "@default(0)\n" + - "integer Bar\n"; + "integer Bar\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -130,15 +132,15 @@ public void completion() throws Exception { @Test public void completionImports() throws Exception { - String model1 = "$version: \"2\"\n" + + String model1 = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "structure Foo {\n" + - "}\n"; - String model2 = "$version: \"2\"\n" + + "}\n"); + String model2 = safeString("$version: \"2\"\n" + "namespace com.bar\n" + "\n" + - "string Bar\n"; + "string Bar\n"); TestWorkspace workspace = TestWorkspace.multipleModels(model1, model2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -159,7 +161,7 @@ public void completionImports() throws Exception { .endLine(3) .endCharacter(15) .build()) - .text("\n bar: Ba") + .text(safeString("\n bar: Ba")) .build(); server.didChange(changeParams); @@ -175,18 +177,18 @@ public void completionImports() throws Exception { Document document = server.getProject().getDocument(uri); // TODO: The server puts the 'use' on the wrong line - assertThat(completions.get(0).getAdditionalTextEdits(), containsInAnyOrder(makesEditedDocument(document, "$version: \"2\"\n" + + assertThat(completions.get(0).getAdditionalTextEdits(), containsInAnyOrder(makesEditedDocument(document, safeString("$version: \"2\"\n" + "namespace com.foo\n" + "use com.bar#Bar\n" + "\n" + "structure Foo {\n" + " bar: Ba\n" + - "}\n"))); + "}\n")))); } @Test public void definition() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "@trait\n" + @@ -197,7 +199,7 @@ public void definition() throws Exception { "}\n" + "\n" + "@myTrait(\"\")\n" + - "string Baz\n"; + "string Baz\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -245,7 +247,7 @@ public void definition() throws Exception { @Test public void hover() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "@trait\n" + @@ -258,7 +260,7 @@ public void hover() throws Exception { "@myTrait(\"\")\n" + "structure Bar {\n" + " baz: String\n" + - "}\n"; + "}\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -292,13 +294,13 @@ public void hover() throws Exception { @Test public void hoverWithBrokenModel() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "structure Foo {\n" + " bar: Bar\n" + " baz: String\n" + - "}\n"; + "}\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -317,7 +319,7 @@ public void hoverWithBrokenModel() throws Exception { @Test public void documentSymbol() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "@trait\n" + @@ -334,7 +336,7 @@ public void documentSymbol() throws Exception { "}\n" + "\n" + "@myTrait(\"abc\")\n" + - "integer Baz\n"; + "integer Baz\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -355,7 +357,7 @@ public void documentSymbol() throws Exception { @Test public void formatting() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "structure Foo{\n" + @@ -364,7 +366,7 @@ public void formatting() throws Exception { "@tags(\n" + "[\"a\",\n" + " \"b\"])\n" + - "string Baz\n"; + "string Baz\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -375,7 +377,7 @@ public void formatting() throws Exception { List edits = server.formatting(params).get(); Document document = server.getProject().getDocument(uri); - assertThat(edits, (Matcher) containsInAnyOrder(makesEditedDocument(document, "$version: \"2\"\n" + + assertThat(edits, (Matcher) containsInAnyOrder(makesEditedDocument(document, safeString("$version: \"2\"\n" + "\n" + "namespace com.foo\n" + "\n" + @@ -384,12 +386,12 @@ public void formatting() throws Exception { "}\n" + "\n" + "@tags([\"a\", \"b\"])\n" + - "string Baz\n"))); + "string Baz\n")))); } @Test public void didChange() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "\n" + "namespace com.foo\n" + "\n" + @@ -397,7 +399,7 @@ public void didChange() throws Exception { "}\n" + "\n" + "operation GetFoo {\n" + - "}\n"; + "}\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -417,7 +419,7 @@ public void didChange() throws Exception { RequestBuilders.DidChange changeBuilder = new RequestBuilders.DidChange().uri(uri); // Add new line and leading spaces - server.didChange(changeBuilder.range(rangeAdapter.build()).text("\n ").build()); + server.didChange(changeBuilder.range(rangeAdapter.build()).text(safeString("\n ")).build()); // add 'input: G' server.didChange(changeBuilder.range(rangeAdapter.shiftNewLine().shiftRight(4).build()).text("i").build()); server.didChange(changeBuilder.range(rangeAdapter.shiftRight().build()).text("n").build()); @@ -431,7 +433,7 @@ public void didChange() throws Exception { server.getLifecycleManager().getTask(uri).get(); // mostly so you can see what it looks like - assertThat(server.getProject().getDocument(uri).copyText(), equalTo("$version: \"2\"\n" + + assertThat(server.getProject().getDocument(uri).copyText(), equalTo(safeString("$version: \"2\"\n" + "\n" + "namespace com.foo\n" + "\n" + @@ -440,7 +442,7 @@ public void didChange() throws Exception { "\n" + "operation GetFoo {\n" + " input: G\n" + - "}\n")); + "}\n"))); // input: G CompletionParams completionParams = new RequestBuilders.PositionRequest() @@ -455,10 +457,10 @@ public void didChange() throws Exception { @Test public void didChangeReloadsModel() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + - "operation Foo {}\n"; + "operation Foo {}\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -492,14 +494,14 @@ public void didChangeReloadsModel() throws Exception { @Test public void didChangeThenDefinition() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "structure Foo {\n" + " bar: Bar\n" + "}\n" + "\n" + - "string Bar\n"; + "string Bar\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -523,7 +525,7 @@ public void didChangeThenDefinition() throws Exception { .endLine(5) .endCharacter(1); RequestBuilders.DidChange change = new RequestBuilders.DidChange().uri(uri); - server.didChange(change.range(range.build()).text("\n\n").build()); + server.didChange(change.range(range.build()).text(safeString("\n\n")).build()); server.didChange(change.range(range.shiftNewLine().shiftNewLine().build()).text("s").build()); server.didChange(change.range(range.shiftRight().build()).text("t").build()); server.didChange(change.range(range.shiftRight().build()).text("r").build()); @@ -537,7 +539,7 @@ public void didChangeThenDefinition() throws Exception { server.getLifecycleManager().getTask(uri).get(); - assertThat(server.getProject().getDocument(uri).copyText(), equalTo("$version: \"2\"\n" + + assertThat(server.getProject().getDocument(uri).copyText(), equalTo(safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "structure Foo {\n" + @@ -546,7 +548,7 @@ public void didChangeThenDefinition() throws Exception { "\n" + "string Baz\n" + "\n" + - "string Bar\n")); + "string Bar\n"))); Location afterChanges = server.definition(definitionParams).get().getLeft().get(0); assertThat(afterChanges.getUri(), equalTo(uri)); @@ -555,7 +557,7 @@ public void didChangeThenDefinition() throws Exception { @Test public void definitionWithApply() throws Exception { - Path root = Paths.get(getClass().getResource("project/apply").getPath()); + Path root = toPath(getClass().getResource("project/apply")); SmithyLanguageServer server = initFromRoot(root); String foo = root.resolve("model/foo.smithy").toUri().toString(); String bar = root.resolve("model/bar.smithy").toUri().toString(); @@ -602,12 +604,12 @@ public void definitionWithApply() throws Exception { @Test public void newShapeMixinCompletion() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "@mixin\n" + "structure Foo {}\n" + - "\n"; + "\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -647,13 +649,13 @@ public void newShapeMixinCompletion() throws Exception { server.getLifecycleManager().getTask(uri).get(); - assertThat(server.getProject().getDocument(uri).copyText(), equalTo("$version: \"2\"\n" + + assertThat(server.getProject().getDocument(uri).copyText(), equalTo(safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "@mixin\n" + "structure Foo {}\n" + "\n" + - "structure Bar with [F]")); + "structure Bar with [F]"))); Position currentPosition = range.build().getStart(); CompletionParams completionParams = new RequestBuilders.PositionRequest() @@ -670,13 +672,13 @@ public void newShapeMixinCompletion() throws Exception { @Test public void existingShapeMixinCompletion() throws Exception { - String model = "$version: \"2\"\n" + + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "@mixin\n" + "structure Foo {}\n" + "\n" + - "structure Bar {}\n"; + "structure Bar {}\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -703,13 +705,13 @@ public void existingShapeMixinCompletion() throws Exception { server.getLifecycleManager().getTask(uri).get(); - assertThat(server.getProject().getDocument(uri).copyText(), equalTo("$version: \"2\"\n" + + assertThat(server.getProject().getDocument(uri).copyText(), equalTo(safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "@mixin\n" + "structure Foo {}\n" + "\n" + - "structure Bar with [F] {}\n")); + "structure Bar with [F] {}\n"))); Position currentPosition = range.build().getStart(); CompletionParams completionParams = new RequestBuilders.PositionRequest() @@ -726,12 +728,12 @@ public void existingShapeMixinCompletion() throws Exception { @Test public void diagnosticsOnMemberTarget() { - String model = "$version: \"2\"\n" + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "structure Foo {\n" + " bar: Bar\n" - + "}\n"; + + "}\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -748,13 +750,13 @@ public void diagnosticsOnMemberTarget() { @Test public void diagnosticOnTrait() { - String model = "$version: \"2\"\n" + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "structure Foo {\n" + " @bar\n" + " bar: String\n" - + "}\n"; + + "}\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -776,12 +778,12 @@ public void diagnosticOnTrait() { @Test public void diagnosticsOnShape() throws Exception { - String model = "$version: \"2\"\n" + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "list Foo {\n" + " \n" - + "}\n"; + + "}\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); StubClient client = new StubClient(); SmithyLanguageServer server = new SmithyLanguageServer(); @@ -820,12 +822,12 @@ public void diagnosticsOnShape() throws Exception { @Test public void insideJar() throws Exception { - String model = "$version: \"2\"\n" + String model = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" + "structure Foo {\n" - + " bar: String\n" - + "}\n"; + + " bar: PrimitiveInteger\n" + + "}\n"); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -847,10 +849,11 @@ public void insideJar() throws Exception { String preludeUri = preludeLocation.getUri(); assertThat(preludeUri, startsWith("smithyjar")); + Logger.getLogger(getClass().getName()).severe("DOCUMENT LINES: " + server.getProject().getDocument(preludeUri).getFullRange()); Hover appliedTraitInPreludeHover = server.hover(RequestBuilders.positionRequest() .uri(preludeUri) - .line(36) + .line(preludeLocation.getRange().getStart().getLine() - 1) // trait applied above 'PrimitiveInteger' .character(1) .buildHover()) .get(); @@ -900,9 +903,9 @@ public void addingWatchedFile() throws Exception { public void removingWatchedFile() { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "model/main.smithy"; - String modelText = "$version: \"2\"\n" + String modelText = safeString("$version: \"2\"\n" + "namespace com.foo\n" - + "string Foo\n"; + + "string Foo\n"); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -928,9 +931,9 @@ public void removingWatchedFile() { public void addingDetachedFile() { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "main.smithy"; - String modelText = "$version: \"2\"\n" + String modelText = safeString("$version: \"2\"\n" + "namespace com.foo\n" - + "string Foo\n"; + + "string Foo\n"); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -971,9 +974,9 @@ public void addingDetachedFile() { public void removingAttachedFile() { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "model/main.smithy"; - String modelText = "$version: \"2\"\n" + String modelText = safeString("$version: \"2\"\n" + "namespace com.foo\n" - + "string Foo\n"; + + "string Foo\n"); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1018,10 +1021,10 @@ public void loadsProjectWithUnNormalizedSourcesDirs() { .sources(Collections.singletonList("./././smithy")) .build(); String filename = "smithy/main.smithy"; - String modelText = "$version: \"2\"\n" + String modelText = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "\n" - + "string Foo\n"; + + "string Foo\n"); TestWorkspace workspace = TestWorkspace.builder() .withSourceDir(TestWorkspace.dir() .path("./smithy") @@ -1044,7 +1047,7 @@ public void loadsProjectWithUnNormalizedSourcesDirs() { @Test public void reloadingProjectWithArrayMetadataValues() throws Exception { - String modelText1 = "$version: \"2\"\n" + String modelText1 = safeString("$version: \"2\"\n" + "\n" + "metadata foo = [1]\n" + "metadata foo = [2]\n" @@ -1052,14 +1055,14 @@ public void reloadingProjectWithArrayMetadataValues() throws Exception { + "\n" + "namespace com.foo\n" + "\n" - + "string Foo\n"; - String modelText2 = "$version: \"2\"\n" + + "string Foo\n"); + String modelText2 = safeString("$version: \"2\"\n" + "\n" + "metadata foo = [3]\n" + "\n" + "namespace com.foo\n" + "\n" - + "string Bar\n"; + + "string Bar\n"); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1077,7 +1080,7 @@ public void reloadingProjectWithArrayMetadataValues() throws Exception { server.didChange(RequestBuilders.didChange() .uri(uri) .range(RangeAdapter.lineSpan(8, 0, 0)) - .text("\nstring Baz\n") + .text(safeString("\nstring Baz\n")) .build()); server.didSave(RequestBuilders.didSave() .uri(uri) @@ -1108,7 +1111,7 @@ public void reloadingProjectWithArrayMetadataValues() throws Exception { @Test public void changingWatchedFilesWithMetadata() throws Exception { - String modelText1 = "$version: \"2\"\n" + String modelText1 = safeString("$version: \"2\"\n" + "\n" + "metadata foo = [1]\n" + "metadata foo = [2]\n" @@ -1116,14 +1119,14 @@ public void changingWatchedFilesWithMetadata() throws Exception { + "\n" + "namespace com.foo\n" + "\n" - + "string Foo\n"; - String modelText2 = "$version: \"2\"\n" + + "string Foo\n"); + String modelText2 = safeString("$version: \"2\"\n" + "\n" + "metadata foo = [3]\n" + "\n" + "namespace com.foo\n" + "\n" - + "string Bar\n"; + + "string Bar\n"); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1154,11 +1157,11 @@ public void changingWatchedFilesWithMetadata() throws Exception { public void addingOpenedDetachedFile() throws Exception { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "main.smithy"; - String modelText = "$version: \"2\"\n" + String modelText = safeString("$version: \"2\"\n" + "\n" + "namespace com.foo\n" + "\n" - + "string Foo\n"; + + "string Foo\n"); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1180,7 +1183,7 @@ public void addingOpenedDetachedFile() throws Exception { server.didChange(RequestBuilders.didChange() .uri(uri) .range(RangeAdapter.point(3, 0)) - .text("string Bar\n") + .text(safeString("string Bar\n")) .build()); // Add the already-opened file to the project @@ -1206,9 +1209,9 @@ public void addingOpenedDetachedFile() throws Exception { @Test public void detachingOpenedFile() throws Exception { - String modelText = "$version: \"2\"\n" + String modelText = safeString("$version: \"2\"\n" + "namespace com.foo\n" - + "string Foo\n"; + + "string Foo\n"); TestWorkspace workspace = TestWorkspace.singleModel(modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1221,7 +1224,7 @@ public void detachingOpenedFile() throws Exception { server.didChange(RequestBuilders.didChange() .uri(uri) .range(RangeAdapter.point(3, 0)) - .text("string Bar\n") + .text(safeString("string Bar\n")) .build()); workspace.updateConfig(workspace.getConfig() @@ -1247,11 +1250,11 @@ public void detachingOpenedFile() throws Exception { public void movingDetachedFile() throws Exception { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "main.smithy"; - String modelText = "$version: \"2\"\n" + String modelText = safeString("$version: \"2\"\n" + "\n" + "namespace com.foo\n" + "\n" - + "string Foo\n"; + + "string Foo\n"); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1290,13 +1293,13 @@ public void updatesDiagnosticsAfterReload() throws Exception { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename1 = "model/main.smithy"; - String modelText1 = "$version: \"2\"\n" + String modelText1 = safeString("$version: \"2\"\n" + "\n" + "namespace com.foo\n" + "\n" + "// using an unknown trait\n" + "@foo\n" - + "string Bar\n"; + + "string Bar\n"); workspace.addModel(filename1, modelText1); StubClient client = new StubClient(); @@ -1318,13 +1321,13 @@ public void updatesDiagnosticsAfterReload() throws Exception { diagnosticWithMessage(containsString("Model.UnresolvedTrait")))); String filename2 = "model/trait.smithy"; - String modelText2 = "$version: \"2\"\n" + String modelText2 = safeString("$version: \"2\"\n" + "\n" + "namespace com.foo\n" + "\n" + "// adding the missing trait\n" + "@trait\n" - + "structure foo {}\n"; + + "structure foo {}\n"); workspace.addModel(filename2, modelText2); String uri2 = workspace.getUri(filename2); @@ -1343,10 +1346,10 @@ public void updatesDiagnosticsAfterReload() throws Exception { @Test public void invalidSyntaxModelPartiallyLoads() { - String modelText1 = "$version: \"2\"\n" + String modelText1 = safeString("$version: \"2\"\n" + "namespace com.foo\n" - + "string Foo\n"; - String modelText2 = "string Bar\n"; + + "string Foo\n"); + String modelText2 = safeString("string Bar\n"); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1364,7 +1367,7 @@ public void invalidSyntaxDetachedProjectBecomesValid() throws Exception { SmithyLanguageServer server = initFromWorkspace(workspace); String filename = "main.smithy"; - String modelText = "string Foo\n"; + String modelText = safeString("string Foo\n"); workspace.addModel(filename, modelText); String uri = workspace.getUri(filename); @@ -1384,7 +1387,7 @@ public void invalidSyntaxDetachedProjectBecomesValid() throws Exception { server.didChange(RequestBuilders.didChange() .uri(uri) .range(RangeAdapter.origin()) - .text("$version: \"2\"\nnamespace com.foo\n") + .text(safeString("$version: \"2\"\nnamespace com.foo\n")) .build()); server.getLifecycleManager().waitForAllTasks(); @@ -1432,17 +1435,17 @@ public void addingDetachedFileWithInvalidSyntax() throws Exception { server.didChange(RequestBuilders.didChange() .uri(uri) - .text("$version: \"2\"\n") + .text(safeString("$version: \"2\"\n")) .range(RangeAdapter.origin()) .build()); server.didChange(RequestBuilders.didChange() .uri(uri) - .text("namespace com.foo\n") + .text(safeString("namespace com.foo\n")) .range(RangeAdapter.point(1, 0)) .build()); server.didChange(RequestBuilders.didChange() .uri(uri) - .text("string Foo\n") + .text(safeString("string Foo\n")) .range(RangeAdapter.point(2, 0)) .build()); @@ -1456,13 +1459,13 @@ public void addingDetachedFileWithInvalidSyntax() throws Exception { @Test public void appliedTraitsAreMaintainedInPartialLoad() throws Exception { - String modelText1 = "$version: \"2\"\n" + String modelText1 = safeString("$version: \"2\"\n" + "namespace com.foo\n" - + "string Foo\n"; - String modelText2 = "$version: \"2\"\n" + + "string Foo\n"); + String modelText2 = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "string Bar\n" - + "apply Foo @length(min: 1)\n"; + + "apply Foo @length(min: 1)\n"); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1494,7 +1497,7 @@ public void appliedTraitsAreMaintainedInPartialLoad() throws Exception { server.didChange(RequestBuilders.didChange() .uri(uri1) .range(RangeAdapter.point(3, 0)) - .text("string Another\n") + .text(safeString("string Another\n")) .build()); server.getLifecycleManager().waitForAllTasks(); @@ -1543,7 +1546,7 @@ public void brokenBuildFileEventuallyConsistent() throws Exception { server.didChange(RequestBuilders.didChange() .uri(uri) - .text("$version: \"2\"\nnamespace com.foo\nstring Foo\n") + .text(safeString("$version: \"2\"\nnamespace com.foo\nstring Foo\n")) .range(RangeAdapter.origin()) .build()); server.getLifecycleManager().waitForAllTasks(); @@ -1556,19 +1559,19 @@ public void brokenBuildFileEventuallyConsistent() throws Exception { @Test public void completionHoverDefinitionWithAbsoluteIds() throws Exception { - String modelText1 = "$version: \"2\"\n" + String modelText1 = safeString("$version: \"2\"\n" + "namespace com.foo\n" + "use com.bar#Bar\n" + "@com.bar#baz\n" + "structure Foo {\n" + " bar: com.bar#Bar\n" - + "}\n"; - String modelText2 = "$version: \"2\"\n" + + "}\n"); + String modelText2 = safeString("$version: \"2\"\n" + "namespace com.bar\n" + "string Bar\n" + "string Bar2\n" + "@trait\n" - + "structure baz {}\n"; + + "structure baz {}\n"); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1627,11 +1630,11 @@ public void completionHoverDefinitionWithAbsoluteIds() throws Exception { @Test public void useCompletionDoesntAutoImport() throws Exception { - String modelText1 = "$version: \"2\"\n" - + "namespace com.foo\n" ; - String modelText2 = "$version: \"2\"\n" + String modelText1 = safeString("$version: \"2\"\n" + + "namespace com.foo\n"); + String modelText2 = safeString("$version: \"2\"\n" + "namespace com.bar\n" - + "string Bar\n"; + + "string Bar\n"); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); diff --git a/src/test/java/software/amazon/smithy/lsp/document/DocumentParserTest.java b/src/test/java/software/amazon/smithy/lsp/document/DocumentParserTest.java index 5fccfca..2bda15b 100644 --- a/src/test/java/software/amazon/smithy/lsp/document/DocumentParserTest.java +++ b/src/test/java/software/amazon/smithy/lsp/document/DocumentParserTest.java @@ -6,11 +6,13 @@ package software.amazon.smithy.lsp.document; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.junit.jupiter.api.Assertions.assertEquals; +import static software.amazon.smithy.lsp.document.DocumentTest.safeIndex; +import static software.amazon.smithy.lsp.document.DocumentTest.safeString; import static software.amazon.smithy.lsp.document.DocumentTest.string; import java.util.Map; @@ -32,7 +34,7 @@ public void jumpsToLines() { "ghi\n" + "\n" + "\n"; - DocumentParser parser = DocumentParser.forDocument(Document.of(text)); + DocumentParser parser = DocumentParser.of(safeString(text)); assertEquals(0, parser.position()); assertEquals(1, parser.line()); assertEquals(1, parser.column()); @@ -43,22 +45,22 @@ public void jumpsToLines() { assertEquals(1, parser.column()); parser.jumpToLine(1); - assertEquals(4, parser.position()); + assertEquals(safeIndex(4, 1), parser.position()); assertEquals(2, parser.line()); assertEquals(1, parser.column()); parser.jumpToLine(2); - assertEquals(8, parser.position()); + assertEquals(safeIndex(8, 2), parser.position()); assertEquals(3, parser.line()); assertEquals(1, parser.column()); parser.jumpToLine(3); - assertEquals(12, parser.position()); + assertEquals(safeIndex(12, 3), parser.position()); assertEquals(4, parser.line()); assertEquals(1, parser.column()); parser.jumpToLine(4); - assertEquals(13, parser.position()); + assertEquals(safeIndex(13, 4), parser.position()); assertEquals(5, parser.line()); assertEquals(1, parser.column()); } @@ -66,7 +68,7 @@ public void jumpsToLines() { @Test public void jumpsToSource() { String text = "abc\ndef\nghi\n"; - DocumentParser parser = DocumentParser.of(text); + DocumentParser parser = DocumentParser.of(safeString(text)); assertThat(parser.position(), is(0)); assertThat(parser.line(), is(1)); assertThat(parser.column(), is(1)); @@ -86,7 +88,7 @@ public void jumpsToSource() { assertThat(parser.column(), is(4)); assertThat(parser.currentPosition(), equalTo(new Position(0, 3))); - ok = parser.jumpToSource(new SourceLocation("", 1, 5)); + ok = parser.jumpToSource(new SourceLocation("", 1, 6)); assertThat(ok, is(false)); assertThat(parser.position(), is(3)); assertThat(parser.line(), is(1)); @@ -95,7 +97,7 @@ public void jumpsToSource() { ok = parser.jumpToSource(new SourceLocation("", 2, 1)); assertThat(ok, is(true)); - assertThat(parser.position(), is(4)); + assertThat(parser.position(), is(safeIndex(4, 1))); assertThat(parser.line(), is(2)); assertThat(parser.column(), is(1)); assertThat(parser.currentPosition(), equalTo(new Position(1, 0))); @@ -105,7 +107,7 @@ public void jumpsToSource() { ok = parser.jumpToSource(new SourceLocation("", 3, 4)); assertThat(ok, is(true)); - assertThat(parser.position(), is(11)); + assertThat(parser.position(), is(safeIndex(11, 2))); assertThat(parser.line(), is(3)); assertThat(parser.column(), is(4)); assertThat(parser.currentPosition(), equalTo(new Position(2, 3))); @@ -113,17 +115,17 @@ public void jumpsToSource() { @Test public void getsDocumentNamespace() { - DocumentParser noNamespace = DocumentParser.of("abc\ndef\n"); - DocumentParser incompleteNamespace = DocumentParser.of("abc\nnamespac"); - DocumentParser incompleteNamespaceValue = DocumentParser.of("namespace "); - DocumentParser likeNamespace = DocumentParser.of("anamespace com.foo\n"); - DocumentParser otherLikeNamespace = DocumentParser.of("namespacea com.foo"); - DocumentParser namespaceAtEnd = DocumentParser.of("\n\nnamespace com.foo"); - DocumentParser brokenNamespace = DocumentParser.of("\nname space com.foo\n"); - DocumentParser commentedNamespace = DocumentParser.of("abc\n//namespace com.foo\n"); - DocumentParser wsPrefixedNamespace = DocumentParser.of("abc\n namespace com.foo\n"); - DocumentParser notNamespace = DocumentParser.of("namespace !foo"); - DocumentParser trailingComment = DocumentParser.of("namespace com.foo//foo\n"); + DocumentParser noNamespace = DocumentParser.of(safeString("abc\ndef\n")); + DocumentParser incompleteNamespace = DocumentParser.of(safeString("abc\nnamespac")); + DocumentParser incompleteNamespaceValue = DocumentParser.of(safeString("namespace ")); + DocumentParser likeNamespace = DocumentParser.of(safeString("anamespace com.foo\n")); + DocumentParser otherLikeNamespace = DocumentParser.of(safeString("namespacea com.foo")); + DocumentParser namespaceAtEnd = DocumentParser.of(safeString("\n\nnamespace com.foo")); + DocumentParser brokenNamespace = DocumentParser.of(safeString("\nname space com.foo\n")); + DocumentParser commentedNamespace = DocumentParser.of(safeString("abc\n//namespace com.foo\n")); + DocumentParser wsPrefixedNamespace = DocumentParser.of(safeString("abc\n namespace com.foo\n")); + DocumentParser notNamespace = DocumentParser.of(safeString("namespace !foo")); + DocumentParser trailingComment = DocumentParser.of(safeString("namespace com.foo//foo\n")); assertThat(noNamespace.documentNamespace(), nullValue()); assertThat(incompleteNamespace.documentNamespace(), nullValue()); @@ -143,15 +145,15 @@ public void getsDocumentNamespace() { @Test public void getsDocumentImports() { - DocumentParser noImports = DocumentParser.of("abc\ndef\n"); - DocumentParser incompleteImport = DocumentParser.of("abc\nus"); - DocumentParser incompleteImportValue = DocumentParser.of("use "); - DocumentParser oneImport = DocumentParser.of("use com.foo#bar"); - DocumentParser leadingWsImport = DocumentParser.of(" use com.foo#bar"); - DocumentParser trailingCommentImport = DocumentParser.of("use com.foo#bar//foo"); - DocumentParser commentedImport = DocumentParser.of("//use com.foo#bar"); - DocumentParser multiImports = DocumentParser.of("use com.foo#bar\nuse com.foo#baz"); - DocumentParser notImport = DocumentParser.of("usea com.foo#bar"); + DocumentParser noImports = DocumentParser.of(safeString("abc\ndef\n")); + DocumentParser incompleteImport = DocumentParser.of(safeString("abc\nus")); + DocumentParser incompleteImportValue = DocumentParser.of(safeString("use ")); + DocumentParser oneImport = DocumentParser.of(safeString("use com.foo#bar")); + DocumentParser leadingWsImport = DocumentParser.of(safeString(" use com.foo#bar")); + DocumentParser trailingCommentImport = DocumentParser.of(safeString("use com.foo#bar//foo")); + DocumentParser commentedImport = DocumentParser.of(safeString("//use com.foo#bar")); + DocumentParser multiImports = DocumentParser.of(safeString("use com.foo#bar\nuse com.foo#baz")); + DocumentParser notImport = DocumentParser.of(safeString("usea com.foo#bar")); assertThat(noImports.documentImports(), nullValue()); assertThat(incompleteImport.documentImports(), nullValue()); @@ -164,11 +166,11 @@ public void getsDocumentImports() { assertThat(notImport.documentImports(), nullValue()); // Some of these aren't shape ids, but its ok - DocumentParser brokenImport = DocumentParser.of("use com.foo"); - DocumentParser commentSeparatedImports = DocumentParser.of("use com.foo#bar //foo\nuse com.foo#baz\n//abc\nuse com.foo#foo"); - DocumentParser oneBrokenImport = DocumentParser.of("use com.foo\nuse com.foo#bar"); - DocumentParser innerBrokenImport = DocumentParser.of("use com.foo#bar\nuse com.foo\nuse com.foo#baz"); - DocumentParser innerNotImport = DocumentParser.of("use com.foo#bar\nstring Foo\nuse com.foo#baz"); + DocumentParser brokenImport = DocumentParser.of(safeString("use com.foo")); + DocumentParser commentSeparatedImports = DocumentParser.of(safeString("use com.foo#bar //foo\nuse com.foo#baz\n//abc\nuse com.foo#foo")); + DocumentParser oneBrokenImport = DocumentParser.of(safeString("use com.foo\nuse com.foo#bar")); + DocumentParser innerBrokenImport = DocumentParser.of(safeString("use com.foo#bar\nuse com.foo\nuse com.foo#baz")); + DocumentParser innerNotImport = DocumentParser.of(safeString("use com.foo#bar\nstring Foo\nuse com.foo#baz")); assertThat(brokenImport.documentImports().imports(), containsInAnyOrder("com.foo")); assertThat(commentSeparatedImports.documentImports().imports(), containsInAnyOrder("com.foo#bar", "com.foo#baz", "com.foo#foo")); assertThat(oneBrokenImport.documentImports().imports(), containsInAnyOrder("com.foo#bar", "com.foo")); @@ -178,20 +180,20 @@ public void getsDocumentImports() { @Test public void getsDocumentVersion() { - DocumentParser noVersion = DocumentParser.of("abc\ndef"); - DocumentParser notVersion = DocumentParser.of("$versionNot: \"2\""); - DocumentParser noDollar = DocumentParser.of("version: \"2\""); - DocumentParser noColon = DocumentParser.of("$version \"2\""); - DocumentParser commented = DocumentParser.of("//$version: \"2\""); - DocumentParser leadingWs = DocumentParser.of(" $version: \"2\""); - DocumentParser leadingLines = DocumentParser.of("\n\n//abc\n$version: \"2\""); - DocumentParser notStringNode = DocumentParser.of("$version: 2"); - DocumentParser trailingComment = DocumentParser.of("$version: \"2\"//abc"); - DocumentParser trailingLine = DocumentParser.of("$version: \"2\"\n"); - DocumentParser invalidNode = DocumentParser.of("$version: \"2"); - DocumentParser notFirst = DocumentParser.of("$foo: \"bar\"\n// abc\n$version: \"2\""); - DocumentParser notSecond = DocumentParser.of("$foo: \"bar\"\n$bar: 1\n// abc\n$baz: 2\n $version: \"2\""); - DocumentParser notFirstNoVersion = DocumentParser.of("$foo: \"bar\"\nfoo\n"); + DocumentParser noVersion = DocumentParser.of(safeString("abc\ndef")); + DocumentParser notVersion = DocumentParser.of(safeString("$versionNot: \"2\"")); + DocumentParser noDollar = DocumentParser.of(safeString("version: \"2\"")); + DocumentParser noColon = DocumentParser.of(safeString("$version \"2\"")); + DocumentParser commented = DocumentParser.of(safeString("//$version: \"2\"")); + DocumentParser leadingWs = DocumentParser.of(safeString(" $version: \"2\"")); + DocumentParser leadingLines = DocumentParser.of(safeString("\n\n//abc\n$version: \"2\"")); + DocumentParser notStringNode = DocumentParser.of(safeString("$version: 2")); + DocumentParser trailingComment = DocumentParser.of(safeString("$version: \"2\"//abc")); + DocumentParser trailingLine = DocumentParser.of(safeString("$version: \"2\"\n")); + DocumentParser invalidNode = DocumentParser.of(safeString("$version: \"2")); + DocumentParser notFirst = DocumentParser.of(safeString("$foo: \"bar\"\n// abc\n$version: \"2\"")); + DocumentParser notSecond = DocumentParser.of(safeString("$foo: \"bar\"\n$bar: 1\n// abc\n$baz: 2\n $version: \"2\"")); + DocumentParser notFirstNoVersion = DocumentParser.of(safeString("$foo: \"bar\"\nfoo\n")); assertThat(noVersion.documentVersion(), nullValue()); assertThat(notVersion.documentVersion(), nullValue()); @@ -255,7 +257,7 @@ public void getsDocumentShapes() { .filter(shape -> shape.getId().getNamespace().equals("com.foo")) .collect(Collectors.toSet()); - DocumentParser parser = DocumentParser.of(text); + DocumentParser parser = DocumentParser.of(safeString(text)); Map documentShapes = parser.documentShapes(shapes); DocumentShape fooDef = documentShapes.get(new Position(2, 7)); diff --git a/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java b/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java index edcc19e..beae156 100644 --- a/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java +++ b/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java @@ -13,6 +13,7 @@ import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.hamcrest.CustomTypeSafeMatcher; +import org.hamcrest.Description; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; import software.amazon.smithy.lsp.protocol.RangeAdapter; @@ -22,7 +23,7 @@ public class DocumentTest { public void appliesTrailingReplacementEdit() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); Range editRange = new RangeAdapter() .startLine(1) @@ -34,17 +35,17 @@ public void appliesTrailingReplacementEdit() { document.applyEdit(editRange, editText); - assertThat(document.copyText(), equalTo("abc\n" + - "deg")); + assertThat(document.copyText(), equalTo(safeString("abc\n" + + "deg"))); assertThat(document.indexOfLine(0), equalTo(0)); - assertThat(document.indexOfLine(1), equalTo(4)); + assertThat(document.indexOfLine(1), equalTo(safeIndex(4, 1))); } @Test public void appliesAppendingEdit() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); Range editRange = new RangeAdapter() .startLine(1) @@ -56,17 +57,17 @@ public void appliesAppendingEdit() { document.applyEdit(editRange, editText); - assertThat(document.copyText(), equalTo("abc\n" + - "defg")); - assertThat(document.indexOfLine(0), equalTo(0)); - assertThat(document.indexOfLine(1), equalTo(4)); + assertThat(document.copyText(), equalTo(safeString("abc\n" + + "defg"))); + assertThat(document.indexOfLine(0), equalTo(safeIndex(0, 0))); + assertThat(document.indexOfLine(1), equalTo(safeIndex(4, 1))); } @Test public void appliesLeadingReplacementEdit() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); Range editRange = new RangeAdapter() .startLine(0) @@ -78,17 +79,17 @@ public void appliesLeadingReplacementEdit() { document.applyEdit(editRange, editText); - assertThat(document.copyText(), equalTo("zbc\n" + - "def")); + assertThat(document.copyText(), equalTo(safeString("zbc\n" + + "def"))); assertThat(document.indexOfLine(0), equalTo(0)); - assertThat(document.indexOfLine(1), equalTo(4)); + assertThat(document.indexOfLine(1), equalTo(safeIndex(4, 1))); } @Test public void appliesPrependingEdit() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); Range editRange = new RangeAdapter() .startLine(0) @@ -100,17 +101,17 @@ public void appliesPrependingEdit() { document.applyEdit(editRange, editText); - assertThat(document.copyText(), equalTo("zabc\n" + - "def")); + assertThat(document.copyText(), equalTo(safeString("zabc\n" + + "def"))); assertThat(document.indexOfLine(0), equalTo(0)); - assertThat(document.indexOfLine(1), equalTo(5)); + assertThat(document.indexOfLine(1), equalTo(safeIndex(5, 1))); } @Test public void appliesInnerReplacementEdit() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); Range editRange = new RangeAdapter() .startLine(0) @@ -118,21 +119,21 @@ public void appliesInnerReplacementEdit() { .endLine(1) .endCharacter(1) .build(); - String editText = "zy\n" + - "x"; + String editText = safeString("zy\n" + + "x"); document.applyEdit(editRange, editText); - assertThat(document.copyText(), equalTo("azy\n" + - "xef")); + assertThat(document.copyText(), equalTo(safeString("azy\n" + + "xef"))); assertThat(document.indexOfLine(0), equalTo(0)); - assertThat(document.indexOfLine(1), equalTo(4)); + assertThat(document.indexOfLine(1), equalTo(safeIndex(4, 1))); } @Test public void appliesPrependingAndReplacingEdit() { String s = "abc"; - Document document = Document.of(s); + Document document = makeDocument(s); Range editRange = new RangeAdapter() .startLine(0) @@ -152,7 +153,7 @@ public void appliesPrependingAndReplacingEdit() { public void appliesInsertionEdit() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); Range editRange = new RangeAdapter() .startLine(0) @@ -160,24 +161,24 @@ public void appliesInsertionEdit() { .endLine(0) .endCharacter(2) .build(); - String editText = "zx\n" + - "y"; + String editText = safeString("zx\n" + + "y"); document.applyEdit(editRange, editText); - assertThat(document.copyText(), equalTo("abzx\n" + + assertThat(document.copyText(), equalTo(safeString("abzx\n" + "yc\n" + - "def")); + "def"))); assertThat(document.indexOfLine(0), equalTo(0)); - assertThat(document.indexOfLine(1), equalTo(5)); - assertThat(document.indexOfLine(2), equalTo(8)); + assertThat(document.indexOfLine(1), equalTo(safeIndex(5, 1))); + assertThat(document.indexOfLine(2), equalTo(safeIndex(8, 2))); } @Test public void appliesDeletionEdit() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); Range editRange = new RangeAdapter() .startLine(0) @@ -189,10 +190,10 @@ public void appliesDeletionEdit() { document.applyEdit(editRange, editText); - assertThat(document.copyText(), equalTo("bc\n" + - "def")); + assertThat(document.copyText(), equalTo(safeString("bc\n" + + "def"))); assertThat(document.indexOfLine(0), equalTo(0)); - assertThat(document.indexOfLine(1), equalTo(3)); + assertThat(document.indexOfLine(1), equalTo(safeIndex(3, 1))); } @Test @@ -200,49 +201,49 @@ public void getsIndexOfLine() { String s = "abc\n" + "def\n" + "hij\n"; - Document document = Document.of(s); + Document document = makeDocument(s); assertThat(document.indexOfLine(0), equalTo(0)); assertThat(document.indexOfLine(-1), equalTo(-1)); - assertThat(document.indexOfLine(1), equalTo(4)); - assertThat(document.indexOfLine(2), equalTo(8)); - assertThat(document.indexOfLine(3), equalTo(12)); + assertThat(document.indexOfLine(1), equalTo(safeIndex(4, 1))); + assertThat(document.indexOfLine(2), equalTo(safeIndex(8, 2))); + assertThat(document.indexOfLine(3), equalTo(safeIndex(12, 3))); assertThat(document.indexOfLine(4), equalTo(-1)); } @Test public void getsIndexOfPosition() { - Document document = Document.of("abc\ndef"); + Document document = makeDocument("abc\ndef"); - assertThat(Document.of("").indexOfPosition(new Position(0, 0)), is(-1)); - assertThat(Document.of("").indexOfPosition(new Position(-1, 0)), is(-1)); + assertThat(makeDocument("").indexOfPosition(new Position(0, 0)), is(-1)); + assertThat(makeDocument("").indexOfPosition(new Position(-1, 0)), is(-1)); assertThat(document.indexOfPosition(new Position(0, 0)), is(0)); assertThat(document.indexOfPosition(new Position(0, 3)), is(3)); - assertThat(document.indexOfPosition(new Position(1, 0)), is(4)); - assertThat(document.indexOfPosition(new Position(1, 2)), is(6)); + assertThat(document.indexOfPosition(new Position(1, 0)), is(safeIndex(4, 1))); + assertThat(document.indexOfPosition(new Position(1, 2)), is(safeIndex(6, 1))); assertThat(document.indexOfPosition(new Position(1, 3)), is(-1)); - assertThat(document.indexOfPosition(new Position(0, 4)), is(-1)); + assertThat(document.indexOfPosition(new Position(0, 6)), is(-1)); assertThat(document.indexOfPosition(new Position(2, 0)), is(-1)); } @Test public void getsPositionAtIndex() { - Document document = Document.of("abc\ndef\nhij\n"); + Document document = makeDocument("abc\ndef\nhij\n"); - assertThat(Document.of("").positionAtIndex(0), nullValue()); - assertThat(Document.of("").positionAtIndex(-1), nullValue()); + assertThat(makeDocument("").positionAtIndex(0), nullValue()); + assertThat(makeDocument("").positionAtIndex(-1), nullValue()); assertThat(document.positionAtIndex(0), equalTo(new Position(0, 0))); assertThat(document.positionAtIndex(3), equalTo(new Position(0, 3))); - assertThat(document.positionAtIndex(4), equalTo(new Position(1, 0))); - assertThat(document.positionAtIndex(11), equalTo(new Position(2, 3))); - assertThat(document.positionAtIndex(12), nullValue()); + assertThat(document.positionAtIndex(safeIndex(4, 1)), equalTo(new Position(1, 0))); + assertThat(document.positionAtIndex(safeIndex(11, 2)), equalTo(new Position(2, 3))); + assertThat(document.positionAtIndex(safeIndex(12, 3)), nullValue()); } @Test public void getsEnd() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); Position end = document.end(); @@ -254,7 +255,7 @@ public void getsEnd() { public void borrowsToken() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); CharSequence token = document.borrowToken(new Position(0, 2)); @@ -264,7 +265,7 @@ public void borrowsToken() { @Test public void borrowsTokenWithNoWs() { String s = "abc"; - Document document = Document.of(s); + Document document = makeDocument(s); CharSequence token = document.borrowToken(new Position(0, 1)); @@ -275,7 +276,7 @@ public void borrowsTokenWithNoWs() { public void borrowsTokenAtStart() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); CharSequence token = document.borrowToken(new Position(0, 0)); @@ -286,7 +287,7 @@ public void borrowsTokenAtStart() { public void borrowsTokenAtEnd() { String s = "abc\n" + "def"; - Document document = Document.of(s); + Document document = makeDocument(s); CharSequence token = document.borrowToken(new Position(1, 2)); @@ -296,7 +297,7 @@ public void borrowsTokenAtEnd() { @Test public void borrowsTokenAtBoundaryStart() { String s = "a bc d"; - Document document = Document.of(s); + Document document = makeDocument(s); CharSequence token = document.borrowToken(new Position(0, 2)); @@ -306,7 +307,7 @@ public void borrowsTokenAtBoundaryStart() { @Test public void borrowsTokenAtBoundaryEnd() { String s = "a bc d"; - Document document = Document.of(s); + Document document = makeDocument(s); CharSequence token = document.borrowToken(new Position(0, 3)); @@ -316,7 +317,7 @@ public void borrowsTokenAtBoundaryEnd() { @Test public void doesntBorrowNonToken() { String s = "abc def"; - Document document = Document.of(s); + Document document = makeDocument(s); CharSequence token = document.borrowToken(new Position(0, 3)); @@ -325,11 +326,11 @@ public void doesntBorrowNonToken() { @Test public void borrowsLine() { - Document document = Document.of("abc\n\ndef"); + Document document = makeDocument("abc\n\ndef"); - assertThat(Document.of("").borrowLine(0), string("")); - assertThat(document.borrowLine(0), string("abc\n")); - assertThat(document.borrowLine(1), string("\n")); + assertThat(makeDocument("").borrowLine(0), string("")); + assertThat(document.borrowLine(0), string(safeString("abc\n"))); + assertThat(document.borrowLine(1), string(safeString("\n"))); assertThat(document.borrowLine(2), string("def")); assertThat(document.borrowLine(-1), nullValue()); assertThat(document.borrowLine(3), nullValue()); @@ -337,40 +338,40 @@ public void borrowsLine() { @Test public void getsNextIndexOf() { - Document document = Document.of("abc\ndef"); + Document document = makeDocument("abc\ndef"); - assertThat(Document.of("").nextIndexOf("a", 0), is(-1)); + assertThat(makeDocument("").nextIndexOf("a", 0), is(-1)); assertThat(document.nextIndexOf("a", 0), is(0)); assertThat(document.nextIndexOf("a", 1), is(-1)); assertThat(document.nextIndexOf("abc", 0), is(0)); assertThat(document.nextIndexOf("abc", 1), is(-1)); // doesn't match if match goes out of boundary - assertThat(document.nextIndexOf("\n", 3), is(3)); - assertThat(document.nextIndexOf("f", 6), is(6)); - assertThat(document.nextIndexOf("f", 7), is(-1)); // oob + assertThat(document.nextIndexOf(System.lineSeparator(), 3), is(3)); + assertThat(document.nextIndexOf("f", safeIndex(6, 1)), is(safeIndex(6, 1))); + assertThat(document.nextIndexOf("f", safeIndex(7, 1)), is(-1)); // oob } @Test public void getsLastIndexOf() { - Document document = Document.of("abc\ndef"); + Document document = makeDocument("abc\ndef"); - assertThat(Document.of("").lastIndexOf("a", 1), is(-1)); + assertThat(makeDocument("").lastIndexOf("a", 1), is(-1)); assertThat(document.lastIndexOf("a", 0), is(0)); // start assertThat(document.lastIndexOf("a", 1), is(0)); - assertThat(document.lastIndexOf("a", 6), is(0)); - assertThat(document.lastIndexOf("f", 6), is(6)); - assertThat(document.lastIndexOf("f", 7), is(6)); // oob - assertThat(document.lastIndexOf("\n", 3), is(3)); + assertThat(document.lastIndexOf("a", safeIndex(6, 1)), is(0)); + assertThat(document.lastIndexOf("f", safeIndex(6, 1)), is(safeIndex(6, 1))); + assertThat(document.lastIndexOf("f", safeIndex(7, 1)), is(safeIndex(6, 1))); // oob + assertThat(document.lastIndexOf(System.lineSeparator(), 3), is(3)); assertThat(document.lastIndexOf("ab", 1), is(0)); assertThat(document.lastIndexOf("ab", 0), is(0)); // can match even if match goes out of boundary assertThat(document.lastIndexOf("ab", -1), is(-1)); - assertThat(document.lastIndexOf(" ", 8), is(-1)); // not found + assertThat(document.lastIndexOf(" ", safeIndex(8, 1)), is(-1)); // not found } @Test public void borrowsSpan() { - Document empty = Document.of(""); - Document line = Document.of("abc"); - Document multi = Document.of("abc\ndef\n\n"); + Document empty = makeDocument(""); + Document line = makeDocument("abc"); + Document multi = makeDocument("abc\ndef\n\n"); assertThat(empty.borrowSpan(0, 1), nullValue()); // empty assertThat(line.borrowSpan(-1, 1), nullValue()); // negative @@ -378,43 +379,43 @@ public void borrowsSpan() { assertThat(line.borrowSpan(0, 1), string("a")); // one assertThat(line.borrowSpan(0, 3), string("abc")); // all assertThat(line.borrowSpan(0, 4), nullValue()); // oob - assertThat(multi.borrowSpan(0, 4), string("abc\n")); // with newline - assertThat(multi.borrowSpan(3, 5), string("\nd")); // inner - assertThat(multi.borrowSpan(5, 9), string("ef\n\n")); // up to end + assertThat(multi.borrowSpan(0, safeIndex(4, 1)), string(safeString("abc\n"))); // with newline + assertThat(multi.borrowSpan(3, safeIndex(5, 1)), string(safeString("\nd"))); // inner + assertThat(multi.borrowSpan(safeIndex(5, 1), safeIndex(9, 3)), string(safeString("ef\n\n"))); // up to end } @Test public void getsLineOfIndex() { - Document empty = Document.of(""); - Document single = Document.of("abc"); - Document twoLine = Document.of("abc\ndef"); - Document leadingAndTrailingWs = Document.of("\nabc\n"); - Document threeLine = Document.of("abc\ndef\nhij\n"); + Document empty = makeDocument(""); + Document single = makeDocument("abc"); + Document twoLine = makeDocument("abc\ndef"); + Document leadingAndTrailingWs = makeDocument("\nabc\n"); + Document threeLine = makeDocument("abc\ndef\nhij\n"); assertThat(empty.lineOfIndex(1), is(-1)); // oob assertThat(single.lineOfIndex(0), is(0)); // start assertThat(single.lineOfIndex(2), is(0)); // end assertThat(single.lineOfIndex(3), is(-1)); // oob assertThat(twoLine.lineOfIndex(1), is(0)); // first line - assertThat(twoLine.lineOfIndex(4), is(1)); // second line start + assertThat(twoLine.lineOfIndex(safeIndex(4, 1)), is(1)); // second line start assertThat(twoLine.lineOfIndex(3), is(0)); // new line - assertThat(twoLine.lineOfIndex(6), is(1)); // end - assertThat(twoLine.lineOfIndex(7), is(-1)); // oob + assertThat(twoLine.lineOfIndex(safeIndex(6, 1)), is(1)); // end + assertThat(twoLine.lineOfIndex(safeIndex(7, 1)), is(-1)); // oob assertThat(leadingAndTrailingWs.lineOfIndex(0), is(0)); // new line - assertThat(leadingAndTrailingWs.lineOfIndex(1), is(1)); // start of line - assertThat(leadingAndTrailingWs.lineOfIndex(4), is(1)); // new line - assertThat(threeLine.lineOfIndex(12), is(-1)); - assertThat(threeLine.lineOfIndex(11), is(2)); + assertThat(leadingAndTrailingWs.lineOfIndex(safeIndex(1, 1)), is(1)); // start of line + assertThat(leadingAndTrailingWs.lineOfIndex(safeIndex(4, 1)), is(1)); // new line + assertThat(threeLine.lineOfIndex(safeIndex(12, 3)), is(-1)); + assertThat(threeLine.lineOfIndex(safeIndex(11, 2)), is(2)); } @Test public void borrowsDocumentShapeId() { - Document empty = Document.of(""); - Document notId = Document.of("?!&"); - Document onlyId = Document.of("abc"); - Document split = Document.of("abc.def hij"); - Document technicallyBroken = Document.of("com.foo# com.foo$ com.foo. com$foo$bar com...foo $foo .foo #foo"); - Document technicallyValid = Document.of("com.foo#bar com.foo#bar$baz com.foo foo#bar foo#bar$baz foo$bar"); + Document empty = makeDocument(""); + Document notId = makeDocument("?!&"); + Document onlyId = makeDocument("abc"); + Document split = makeDocument("abc.def hij"); + Document technicallyBroken = makeDocument("com.foo# com.foo$ com.foo. com$foo$bar com...foo $foo .foo #foo"); + Document technicallyValid = makeDocument("com.foo#bar com.foo#bar$baz com.foo foo#bar foo#bar$baz foo$bar"); assertThat(empty.getDocumentIdAt(new Position(0, 0)), nullValue()); assertThat(notId.getDocumentIdAt(new Position(0, 0)), nullValue()); @@ -449,11 +450,37 @@ public void borrowsDocumentShapeId() { assertThat(technicallyValid.getDocumentIdAt(new Position(0, 56)), documentShapeId("foo$bar", DocumentId.Type.RELATIVE_WITH_MEMBER)); } + // This is used to convert the character offset in a file that assumes a single character + // line break, and make that same offset safe with multi character line breaks. + // + // This is preferable to simply adjusting how we test Document because bugs in these low-level + // primitive methods will break a lot of stuff, so it's good to be exact. + public static int safeIndex(int standardOffset, int line) { + return standardOffset + (line * (System.lineSeparator().length() - 1)); + } + + // Makes a string literal with '\n' newline characters use the actual OS line separator. + // Don't use this if you didn't manually type out the '\n's. + // TODO: Remove this for textblocks + public static String safeString(String s) { + return s.replace("\n", System.lineSeparator()); + } + + private static Document makeDocument(String s) { + return Document.of(safeString(s)); + } + public static Matcher string(String other) { return new CustomTypeSafeMatcher(other) { @Override protected boolean matchesSafely(CharSequence item) { - return other.equals(item.toString()); + return other.replace("\n", "\\n").replace("\r", "\\r").equals(item.toString().replace("\n", "\\n").replace("\r", "\\r")); + } + @Override + public void describeMismatchSafely(CharSequence item, Description description) { + String o = other.replace("\n", "\\n").replace("\r", "\\r"); + String it = item.toString().replace("\n", "\\n").replace("\r", "\\r"); + equalTo(o).describeMismatch(it, description); } }; } diff --git a/src/test/java/software/amazon/smithy/lsp/project/ProjectConfigLoaderTest.java b/src/test/java/software/amazon/smithy/lsp/project/ProjectConfigLoaderTest.java index 5313bee..42534d7 100644 --- a/src/test/java/software/amazon/smithy/lsp/project/ProjectConfigLoaderTest.java +++ b/src/test/java/software/amazon/smithy/lsp/project/ProjectConfigLoaderTest.java @@ -6,13 +6,13 @@ package software.amazon.smithy.lsp.project; import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.hasSize; +import static software.amazon.smithy.lsp.project.ProjectTest.toPath; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; @@ -24,7 +24,7 @@ public class ProjectConfigLoaderTest { @Test public void loadsConfigWithEnvVariable() { System.setProperty("FOO", "bar"); - Path root = Paths.get(getClass().getResource("env-config").getPath()); + Path root = toPath(getClass().getResource("env-config")); Result> result = ProjectConfigLoader.loadFromRoot(root); assertThat(result.isOk(), is(true)); @@ -40,7 +40,7 @@ public void loadsConfigWithEnvVariable() { @Test public void loadsLegacyConfig() { - Path root = Paths.get(getClass().getResource("legacy-config").getPath()); + Path root = toPath(getClass().getResource("legacy-config")); Result> result = ProjectConfigLoader.loadFromRoot(root); assertThat(result.isOk(), is(true)); @@ -55,7 +55,7 @@ public void loadsLegacyConfig() { @Test public void prefersNonLegacyConfig() { - Path root = Paths.get(getClass().getResource("legacy-config-with-conflicts").getPath()); + Path root = toPath(getClass().getResource("legacy-config-with-conflicts")); Result> result = ProjectConfigLoader.loadFromRoot(root); assertThat(result.isOk(), is(true)); @@ -70,7 +70,7 @@ public void prefersNonLegacyConfig() { @Test public void mergesBuildExts() { - Path root = Paths.get(getClass().getResource("build-exts").getPath()); + Path root = toPath(getClass().getResource("build-exts")); Result> result = ProjectConfigLoader.loadFromRoot(root); assertThat(result.isOk(), is(true)); diff --git a/src/test/java/software/amazon/smithy/lsp/project/ProjectTest.java b/src/test/java/software/amazon/smithy/lsp/project/ProjectTest.java index 4885782..93d92b0 100644 --- a/src/test/java/software/amazon/smithy/lsp/project/ProjectTest.java +++ b/src/test/java/software/amazon/smithy/lsp/project/ProjectTest.java @@ -21,9 +21,12 @@ import static software.amazon.smithy.lsp.UtilMatchers.anOptionalOf; import static software.amazon.smithy.lsp.document.DocumentTest.string; +import java.net.URISyntaxException; +import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; +import java.util.logging.Logger; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import software.amazon.smithy.lsp.TestWorkspace; @@ -43,7 +46,7 @@ public class ProjectTest { @Test public void loadsFlatProject() { - Path root = Paths.get(getClass().getResource("flat").getPath()); + Path root = toPath(getClass().getResource("flat")); Project project = ProjectLoader.load(root).unwrap(); assertThat(project.getRoot(), equalTo(root)); @@ -56,7 +59,7 @@ public void loadsFlatProject() { @Test public void loadsProjectWithMavenDep() { - Path root = Paths.get(getClass().getResource("maven-dep").getPath()); + Path root = toPath(getClass().getResource("maven-dep")); Project project = ProjectLoader.load(root).unwrap(); assertThat(project.getRoot(), equalTo(root)); @@ -69,7 +72,7 @@ public void loadsProjectWithMavenDep() { @Test public void loadsProjectWithSubdir() { - Path root = Paths.get(getClass().getResource("subdirs").getPath()); + Path root = toPath(getClass().getResource("subdirs")); Project project = ProjectLoader.load(root).unwrap(); assertThat(project.getRoot(), equalTo(root)); @@ -77,10 +80,10 @@ public void loadsProjectWithSubdir() { root.resolve("model"), root.resolve("model2"))); assertThat(project.getSmithyFiles().keySet(), hasItems( - containsString("model/main.smithy"), - containsString("model/subdir/sub.smithy"), - containsString("model2/subdir2/sub2.smithy"), - containsString("model2/subdir2/subsubdir/subsub.smithy"))); + equalTo(root.resolve("model/main.smithy").toString()), + equalTo(root.resolve("model/subdir/sub.smithy").toString()), + equalTo(root.resolve("model2/subdir2/sub2.smithy").toString()), + equalTo(root.resolve("model2/subdir2/subsubdir/subsub.smithy").toString()))); assertThat(project.getModelResult().isBroken(), is(false)); assertThat(project.getModelResult().unwrap(), hasShapeWithId("com.foo#Foo")); assertThat(project.getModelResult().unwrap(), hasShapeWithId("com.foo#Bar")); @@ -89,7 +92,7 @@ public void loadsProjectWithSubdir() { @Test public void loadsModelWithUnknownTrait() { - Path root = Paths.get(getClass().getResource("unknown-trait").getPath()); + Path root = toPath(getClass().getResource("unknown-trait")); Project project = ProjectLoader.load(root).unwrap(); assertThat(project.getRoot(), equalTo(root)); @@ -106,7 +109,7 @@ public void loadsModelWithUnknownTrait() { @Test public void loadsWhenModelHasInvalidSyntax() { - Path root = Paths.get(getClass().getResource("invalid-syntax").getPath()); + Path root = toPath(getClass().getResource("invalid-syntax")); Project project = ProjectLoader.load(root).unwrap(); assertThat(project.getRoot(), equalTo(root)); @@ -140,7 +143,7 @@ public void loadsWhenModelHasInvalidSyntax() { @Test public void loadsProjectWithMultipleNamespaces() { - Path root = Paths.get(getClass().getResource("multiple-namespaces").getPath()); + Path root = toPath(getClass().getResource("multiple-namespaces")); Project project = ProjectLoader.load(root).unwrap(); assertThat(project.getSources(), hasItem(root.resolve("model"))); @@ -176,7 +179,7 @@ public void loadsProjectWithMultipleNamespaces() { @Test public void loadsProjectWithExternalJars() { - Path root = Paths.get(getClass().getResource("external-jars").getPath()); + Path root = toPath(getClass().getResource("external-jars")); Result> result = ProjectLoader.load(root); assertThat(result.isOk(), is(true)); @@ -200,7 +203,7 @@ public void loadsProjectWithExternalJars() { @Test public void failsLoadingInvalidSmithyBuildJson() { - Path root = Paths.get(getClass().getResource("broken/missing-version").getPath()); + Path root = toPath(getClass().getResource("broken/missing-version")); Result> result = ProjectLoader.load(root); assertThat(result.isErr(), is(true)); @@ -208,7 +211,7 @@ public void failsLoadingInvalidSmithyBuildJson() { @Test public void failsLoadingUnparseableSmithyBuildJson() { - Path root = Paths.get(getClass().getResource("broken/parse-failure").getPath()); + Path root = toPath(getClass().getResource("broken/parse-failure")); Result> result = ProjectLoader.load(root); assertThat(result.isErr(), is(true)); @@ -216,7 +219,7 @@ public void failsLoadingUnparseableSmithyBuildJson() { @Test public void doesntFailLoadingProjectWithNonExistingSource() { - Path root = Paths.get(getClass().getResource("broken/source-doesnt-exist").getPath()); + Path root = toPath(getClass().getResource("broken/source-doesnt-exist")); Result> result = ProjectLoader.load(root); assertThat(result.isErr(), is(false)); @@ -226,7 +229,7 @@ public void doesntFailLoadingProjectWithNonExistingSource() { @Test public void failsLoadingUnresolvableMavenDependency() { - Path root = Paths.get(getClass().getResource("broken/unresolvable-maven-dependency").getPath()); + Path root = toPath(getClass().getResource("broken/unresolvable-maven-dependency")); Result> result = ProjectLoader.load(root); assertThat(result.isErr(), is(true)); @@ -234,7 +237,7 @@ public void failsLoadingUnresolvableMavenDependency() { @Test public void failsLoadingUnresolvableProjectDependency() { - Path root = Paths.get(getClass().getResource("broken/unresolvable-maven-dependency").getPath()); + Path root = toPath(getClass().getResource("broken/unresolvable-maven-dependency")); Result> result = ProjectLoader.load(root); assertThat(result.isErr(), is(true)); @@ -242,7 +245,7 @@ public void failsLoadingUnresolvableProjectDependency() { @Test public void loadsProjectWithUnNormalizedDirs() { - Path root = Paths.get(getClass().getResource("unnormalized-dirs").getPath()); + Path root = toPath(getClass().getResource("unnormalized-dirs")); Project project = ProjectLoader.load(root).unwrap(); assertThat(project.getRoot(), equalTo(root)); @@ -255,7 +258,7 @@ public void loadsProjectWithUnNormalizedDirs() { equalTo(root.resolve("model/one.smithy").toString()), equalTo(root.resolve("model2/two.smithy").toString()), equalTo(root.resolve("model3/three.smithy").toString()), - containsString(root.resolve("smithy-test-traits.jar") + "!/META-INF/smithy/smithy.test.json"))); + containsString("smithy-test-traits.jar!/META-INF/smithy/smithy.test.json"))); assertThat(project.getDependencies(), hasItem(root.resolve("smithy-test-traits.jar"))); } @@ -520,6 +523,17 @@ public void changingFileWithArrayDependenciesWithDependencies() { String uri = workspace.getUri("model-0.smithy"); Document document = project.getDocument(uri); + if (document == null) { + String smithyFilesPaths = String.join(System.lineSeparator(), project.getSmithyFiles().keySet()); + String smithyFilesUris = project.getSmithyFiles().keySet().stream() + .map(UriAdapter::toUri) + .collect(Collectors.joining(System.lineSeparator())); + Logger logger = Logger.getLogger(getClass().getName()); + logger.severe("Not found uri: " + uri); + logger.severe("Not found path: " + UriAdapter.toPath(uri)); + logger.severe("PATHS: " + smithyFilesPaths); + logger.severe("URIS: " + smithyFilesUris); + } document.applyEdit(RangeAdapter.point(document.end()), "\n"); project.updateModelWithoutValidating(uri); @@ -592,4 +606,12 @@ public void removingArrayApply() { assertThat(bar.hasTrait("tags"), is(true)); assertThat(bar.expectTrait(TagsTrait.class).getTags(), containsInAnyOrder("bar")); } + + public static Path toPath(URL url) { + try { + return Paths.get(url.toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } }