From aff3804aa6d1f6f101cf8801f5785a4748d0587e Mon Sep 17 00:00:00 2001 From: Peter Collins Date: Tue, 30 Nov 2021 13:23:12 -0500 Subject: [PATCH] [java-source-utils] Transform XML using XSLT I've seen inconsistent XML output from java-source-utils when running on macOS vs. Windows, or JDK 8 vs. JDK 11. On Windows I've seen extra carriage returns in CDATA blocks, and when using JDK 9+ we've seen additional new lines added between XML elements. An XSL style sheet can be used to improve the formatting consistency of the XML that is produced. This should prevent us from generating inconsistent API docs across macOS and Windows. There is still an outstanding issue concerning CDATA blocks between JDK 8 and JDK 11 that I have not yet been able to sort out. This issue has seemingly been "fixed" in JDK 14. --- build-tools/automation/azure-pipelines.yaml | 1 - .../automation/templates/core-tests.yaml | 3 -- .../templates/publish-test-results.yaml | 1 - build-tools/scripts/RunNUnitTests.targets | 2 +- .../android/JavadocXmlGenerator.java | 9 ++-- .../src/main/resources/transform-style.xsl | 45 +++++++++++++++++++ .../android/JavadocXmlGeneratorTest.java | 21 ++++++--- .../android/ParameterNameGeneratorTest.java | 15 +++++-- 8 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 tools/java-source-utils/src/main/resources/transform-style.xsl diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index ea02853b2..d8c8a7237 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -179,6 +179,5 @@ jobs: - template: templates\core-tests.yaml parameters: runNativeTests: true - runJavaTests: true - template: templates\fail-on-issue.yaml diff --git a/build-tools/automation/templates/core-tests.yaml b/build-tools/automation/templates/core-tests.yaml index 9cc8e6990..e48505773 100644 --- a/build-tools/automation/templates/core-tests.yaml +++ b/build-tools/automation/templates/core-tests.yaml @@ -1,7 +1,6 @@ parameters: condition: succeeded() runNativeTests: false - runJavaTests: false steps: - task: DotNetCoreCLI@2 @@ -110,7 +109,6 @@ steps: - task: DotNetCoreCLI@2 displayName: 'Tests: java-source-utils' - condition: eq('${{ parameters.runJavaTests }}', 'true') inputs: command: build arguments: -c $(Build.Configuration) tools/java-source-utils/java-source-utils.csproj -t:RunTests @@ -118,7 +116,6 @@ steps: - task: PublishTestResults@2 displayName: Publish JUnit Test Results - condition: eq('${{ parameters.runJavaTests }}', 'true') inputs: testResultsFormat: JUnit testResultsFiles: 'tools/java-source-utils/build/test-results/**/TEST-*.xml' diff --git a/build-tools/automation/templates/publish-test-results.yaml b/build-tools/automation/templates/publish-test-results.yaml index 782c367e2..7a715c13d 100644 --- a/build-tools/automation/templates/publish-test-results.yaml +++ b/build-tools/automation/templates/publish-test-results.yaml @@ -9,7 +9,6 @@ steps: - task: PublishTestResults@2 displayName: Publish JUnit Test Results - condition: ne('$(Agent.OS)', 'Windows') inputs: testResultsFormat: JUnit testResultsFiles: '**/TEST-*.xml' diff --git a/build-tools/scripts/RunNUnitTests.targets b/build-tools/scripts/RunNUnitTests.targets index ab169fe54..c00b6c767 100644 --- a/build-tools/scripts/RunNUnitTests.targets +++ b/build-tools/scripts/RunNUnitTests.targets @@ -30,7 +30,7 @@ ContinueOnError="ErrorAndContinue" /> diff --git a/tools/java-source-utils/src/main/java/com/microsoft/android/JavadocXmlGenerator.java b/tools/java-source-utils/src/main/java/com/microsoft/android/JavadocXmlGenerator.java index d600c1fd8..690474b03 100644 --- a/tools/java-source-utils/src/main/java/com/microsoft/android/JavadocXmlGenerator.java +++ b/tools/java-source-utils/src/main/java/com/microsoft/android/JavadocXmlGenerator.java @@ -2,6 +2,8 @@ import java.io.File; import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintStream; import java.io.UnsupportedEncodingException; @@ -17,6 +19,7 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -65,10 +68,10 @@ private void startApi() throws ParserConfigurationException { } public void close() throws TransformerException { + InputStream is = getClass().getClassLoader().getResourceAsStream("transform-style.xsl"); + InputStreamReader isr = new InputStreamReader(is); Transformer transformer = TransformerFactory.newInstance() - .newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + .newTransformer(new StreamSource (isr)); transformer.transform(new DOMSource(document), new StreamResult(output)); if (output != System.out) { diff --git a/tools/java-source-utils/src/main/resources/transform-style.xsl b/tools/java-source-utils/src/main/resources/transform-style.xsl new file mode 100644 index 000000000..2f7e4157d --- /dev/null +++ b/tools/java-source-utils/src/main/resources/transform-style.xsl @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/java-source-utils/src/test/java/com/microsoft/android/JavadocXmlGeneratorTest.java b/tools/java-source-utils/src/test/java/com/microsoft/android/JavadocXmlGeneratorTest.java index 11c4c5e97..9665a63fe 100644 --- a/tools/java-source-utils/src/test/java/com/microsoft/android/JavadocXmlGeneratorTest.java +++ b/tools/java-source-utils/src/test/java/com/microsoft/android/JavadocXmlGeneratorTest.java @@ -10,6 +10,7 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; +import org.junit.Assume; import org.junit.Test; import static org.junit.Assert.*; @@ -19,7 +20,14 @@ public final class JavadocXmlGeneratorTest { @Test(expected = FileNotFoundException.class) public void init_invalidFileThrows() throws FileNotFoundException, ParserConfigurationException, TransformerException, UnsupportedEncodingException { - try (JavadocXmlGenerator g = new JavadocXmlGenerator("/this/file/does/not/exist")) { + String invalidFilePath = "/this/file/does/not/exist"; + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows")) { + invalidFilePath = System.getenv("ProgramFiles") + "\\this\\file\\does\\not\\exist"; + // Ignore if running on an Azure Pipelines Microsoft hosted agent by only running when %AGENT_NAME% is not set. + Assume.assumeTrue(System.getenv("AGENT_NAME") == null); + } + try (JavadocXmlGenerator g = new JavadocXmlGenerator(invalidFilePath)) { } } @@ -40,9 +48,11 @@ public void testWritePackages_noPackages() throws ParserConfigurationException, generator.writePackages(packages); generator.close(); - final String expected = + final String expected = ( "\n" + - "\n"; + "\n" + ).replace("\n", System.lineSeparator()); + assertEquals("no packages", expected, bytes.toString()); } @@ -53,7 +63,7 @@ public void testWritePackages_demo() throws ParserConfigurationException, Transf final JavadocXmlGenerator generator = new JavadocXmlGenerator(new PrintStream(bytes)); final JniPackagesInfo packages = JniPackagesInfoTest.createDemoInfo(); - final String expected = + final String expected = ( "\n" + "\n" + " \n" + @@ -94,7 +104,8 @@ public void testWritePackages_demo() throws ParserConfigurationException, Transf " \n" + " \n" + " \n" + - "\n"; + "\n" + ).replace("\n", System.lineSeparator()); generator.writePackages(packages); generator.close(); diff --git a/tools/java-source-utils/src/test/java/com/microsoft/android/ParameterNameGeneratorTest.java b/tools/java-source-utils/src/test/java/com/microsoft/android/ParameterNameGeneratorTest.java index 99b7ea4ca..5235ab7e7 100644 --- a/tools/java-source-utils/src/test/java/com/microsoft/android/ParameterNameGeneratorTest.java +++ b/tools/java-source-utils/src/test/java/com/microsoft/android/ParameterNameGeneratorTest.java @@ -7,6 +7,7 @@ import java.io.UnsupportedEncodingException; import java.util.Arrays; +import org.junit.Assume; import org.junit.Test; import static org.junit.Assert.*; @@ -17,7 +18,14 @@ public class ParameterNameGeneratorTest { @Test(expected = FileNotFoundException.class) public void init_invalidFileThrows() throws FileNotFoundException, UnsupportedEncodingException { - new ParameterNameGenerator("/this/file/does/not/exist"); + String invalidFilePath = "/this/file/does/not/exist"; + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows")) { + invalidFilePath = System.getenv("ProgramFiles") + "\\this\\file\\does\\not\\exist"; + // Ignore if running on an Azure Pipelines Microsoft hosted agent by only running when %AGENT_NAME% is not set. + Assume.assumeTrue(System.getenv("AGENT_NAME") == null); + } + new ParameterNameGenerator(invalidFilePath); } @Test(expected = IllegalArgumentException.class) @@ -45,7 +53,7 @@ public void testWritePackages_demo() { ParameterNameGenerator generator = new ParameterNameGenerator(new PrintStream(bytes)); JniPackagesInfo packages = JniPackagesInfoTest.createDemoInfo(); - final String expected = + final String expected = ( ";---------------------------------------\n" + " class A\n" + " #ctor(int one, java.lang.String two)\n" + @@ -60,7 +68,8 @@ public void testWritePackages_demo() { ";---------------------------------------\n" + " interface Exampleable\n" + " example(java.lang.String e)\n" + - ""; + "" + ).replace("\n", System.lineSeparator()); generator.writePackages(packages); assertEquals("global package + example packages", expected, bytes.toString());