diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java index a75b92b1..20c06744 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java @@ -95,7 +95,8 @@ void applyToProjectWithFileMergesToDotSettings() throws Exception { }).given(projectFile).setContents((InputStream) any(), anyInt(), any()); files.applyToProject(project, monitor); verify(projectFile).setContents((InputStream) any(), eq(1), eq(monitor)); - assertThat(out.toString(StandardCharsets.UTF_8)).isEqualTo("a=b\ny=z\n"); + assertThat(out.toString(StandardCharsets.UTF_8)) + .isEqualToNormalizingNewlines("a=b\ny=z\n"); } private ProjectSettingsFile createPrefsFile() throws IOException { diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java index a5554177..16d3aa4a 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java @@ -18,12 +18,11 @@ 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.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.util.Arrays; -import java.util.Collections; import java.util.stream.Stream; import org.gradle.testkit.runner.BuildResult; @@ -68,12 +67,12 @@ void whenFirstInvocationSucceedsThenSecondInvocationIsUpToDate() throws IOExcept @Test void whenFirstInvocationSucceedsAndSourceIsModifiedThenSecondInvocationSucceeds() throws IOException { - copyFolder(new File("src/test/resources/check-ok").toPath(), this.temp.toPath()); + copyNormalizedFolder(new File("src/test/resources/check-ok").toPath(), this.temp.toPath()); GradleBuild gradleBuild = this.gradleBuild.source(this.temp); BuildResult result = gradleBuild.build("check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); Files.write(new File(this.temp, "src/main/java/simple/Simple.java").toPath(), - Collections.singletonList("// A change to the file"), StandardOpenOption.APPEND); + "// A change to the file\n".getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND); result = gradleBuild.build("--debug", "check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); } @@ -129,14 +128,17 @@ void whenFirstInvocationFailsThenSecondInvocationFails() throws IOException { assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.FAILED); } - private void copyFolder(Path source, Path target) throws IOException { + private void copyNormalizedFolder(Path source, Path target) throws IOException { try (Stream stream = Files.walk(source)) { stream.forEach((child) -> { try { Path relative = source.relativize(child); Path destination = target.resolve(relative); - if (!destination.toFile().isDirectory()) { - Files.copy(child, destination, StandardCopyOption.REPLACE_EXISTING); + if (!Files.isDirectory(child)) { + String content = new String(Files.readAllBytes(child), StandardCharsets.UTF_8); + String normalized = content.replace("\n\r", "\n").replace('\r', '\n'); + Files.createDirectories(destination.getParent()); + Files.write(destination, normalized.getBytes(StandardCharsets.UTF_8)); } } catch (Exception ex) { diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java index 3707cfee..bb7871ec 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,16 +30,14 @@ */ public class VerifyApply { - private static final String LF = System.lineSeparator(); - private static final String JAVA_FILE = "src/main/java/simple/Simple.java"; public void verify(File base) throws IOException { - verify(base, LF); + verify(base, null); } public void verify(File base, boolean spaces) throws IOException { - verify(base, LF, spaces); + verify(base, null, spaces); } public void verify(File base, String lineSeparator) throws IOException { @@ -48,16 +46,14 @@ public void verify(File base, String lineSeparator) throws IOException { public void verify(File base, String lineSeparator, boolean spaces) throws IOException { String formated = new String(Files.readAllBytes(base.toPath().resolve(JAVA_FILE)), StandardCharsets.UTF_8); + if (lineSeparator == null) { + formated = formated.replace("\r\n", "\n").replace('\r', '\n'); + lineSeparator = "\n"; + } String indent = (!spaces) ? " " : " "; assertThat(formated).contains("Simple." + lineSeparator + " *" + lineSeparator + " * @author") .contains("public class Simple {") .contains(indent + "public static void main"); } - public static void main(String[] args) throws IOException { - new VerifyApply().verify(new File( - "/Users/pwebb/projects/spring-javaformat/code/spring-javaformat-maven/spring-javaformat-maven-plugin/target/it/apply-line-separator"), - "\r"); - } - } diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java index f039acfd..445daff9 100644 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,11 @@ package io.spring.javaformat.formatter; import java.io.File; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; -import java.util.Collection; +import java.util.List; import io.spring.javaformat.config.JavaBaseline; import io.spring.javaformat.config.JavaFormatConfig; @@ -47,7 +48,7 @@ protected final String read(File file) throws Exception { } protected static Item[] items(String expectedOverride) { - Collection items = new ArrayList<>(); + List items = new ArrayList<>(); File sourceDir = new File("src/test/resources/source"); File expectedDir = new File("src/test/resources/expected"); File configDir = new File("src/test/resources/config"); @@ -59,12 +60,52 @@ protected static Item[] items(String expectedOverride) { } File config = new File(configDir, source.getName()); for (JavaBaseline javaBaseline : JavaBaseline.values()) { - items.add(new Item(javaBaseline, source, expected, config)); + addItem(items, javaBaseline, source, expected, config); } } return items.toArray(new Item[0]); } + private static void addItem(List items, JavaBaseline javaBaseline, File source, File expected, File config) { + if (source.getName().contains("lineendings")) { + items.add(new Item(javaBaseline, copy(source, LineEnding.CR), copy(expected, LineEnding.CR), config)); + items.add(new Item(javaBaseline, copy(source, LineEnding.LF), copy(expected, LineEnding.LF), config)); + items.add(new Item(javaBaseline, copy(source, LineEnding.CRLF), copy(expected, LineEnding.CRLF), config)); + } + else { + items.add(new Item(javaBaseline, source, expected, config)); + } + } + + private static File copy(File file, LineEnding lineEnding) { + try { + String[] name = file.getName().split("\\."); + File result = File.createTempFile(name[0] + "_" + lineEnding + "_", "." + name[1]); + String content = Files.readString(file.toPath()); + content = content.replace("\r\n", "\n").replace('\r', '\n').replace("\n", lineEnding.ending()); + Files.writeString(result.toPath(), content); + return result; + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + enum LineEnding { + + CR("\r"), LF("\n"), CRLF("\r\n"); + + private final String ending; + + LineEnding(String ending) { + this.ending = ending; + } + + String ending() { + return this.ending; + } + }; + static class Item { private final JavaBaseline javaBaseline; diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/lineendings.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/lineendings.txt new file mode 100644 index 00000000..92ad853f --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/lineendings.txt @@ -0,0 +1,8 @@ +package correct; + +public class CorrectLf { + + public static void main(String[] args) throws Exception { + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt new file mode 100644 index 00000000..e56b3941 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt @@ -0,0 +1,7 @@ +package correct; + +public class CorrectLf { + + public static void main(String[] args) throws Exception { } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java index 83f6406c..97d20003 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,6 +123,7 @@ public TextEdit format(String source, int offset, int length, String lineSeparat public TextEdit format(int kind, String source, int offset, int length, int indentationLevel, String lineSeparator) { + lineSeparator = (lineSeparator != null) ? lineSeparator : detectLineSeparator(source); return this.delegate.format(kind, source, offset, length, indentationLevel, lineSeparator); } @@ -148,6 +149,7 @@ public TextEdit format(String source, IRegion[] regions, String lineSeparator) { } public TextEdit format(int kind, String source, IRegion[] regions, int indentationLevel, String lineSeparator) { + lineSeparator = (lineSeparator != null) ? lineSeparator : detectLineSeparator(source); return this.delegate.format(kind, source, regions, indentationLevel, lineSeparator); } @@ -159,4 +161,18 @@ public void setOptions(Map options) { this.delegate.setOptions(options); } + private String detectLineSeparator(String contents) { + int length = contents.length(); + for (int i = 0; i < length; i++) { + char ch = contents.charAt(i); + boolean isLastChar = (i + 1) == length; + if (ch == '\r') { + return (isLastChar || contents.charAt(i + 1) != '\n') ? "\r" : "\r\n"; + } + if (ch == '\n') { + return "\n"; + } + } + return null; + } }