diff --git a/src/main/java/org/eolang/lints/Fix.java b/src/main/java/org/eolang/lints/Fix.java new file mode 100644 index 000000000..8bdcd6957 --- /dev/null +++ b/src/main/java/org/eolang/lints/Fix.java @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com + * SPDX-License-Identifier: MIT + */ +package org.eolang.lints; + +import com.jcabi.xml.XML; +import java.io.IOException; + +/** + * A fix for a lint defect. + * @since 0.2.1 + */ +@FunctionalInterface +public interface Fix { + + /** + * Apply the fix and return the corrected XMIR. + * @param xmir The XMIR to fix + * @return Fixed XMIR + * @throws IOException If something goes wrong + */ + XML apply(XML xmir) throws IOException; +} diff --git a/src/main/java/org/eolang/lints/FxUnsortedMetas.java b/src/main/java/org/eolang/lints/FxUnsortedMetas.java new file mode 100644 index 000000000..1f04221ee --- /dev/null +++ b/src/main/java/org/eolang/lints/FxUnsortedMetas.java @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com + * SPDX-License-Identifier: MIT + */ +package org.eolang.lints; + +import com.jcabi.xml.ClasspathSources; +import com.jcabi.xml.XML; +import com.jcabi.xml.XSL; +import com.jcabi.xml.XSLDocument; +import java.io.IOException; +import org.cactoos.io.ResourceOf; +import org.cactoos.scalar.Sticky; +import org.cactoos.scalar.Unchecked; +import org.cactoos.text.IoCheckedText; +import org.cactoos.text.TextOf; + +/** + * Fix for the {@code unsorted-metas} lint. + * Sorts {@code meta} elements inside {@code metas} alphabetically + * by their {@code head} and {@code tail} content. + * @since 0.2.1 + */ +public final class FxUnsortedMetas implements Fix { + + /** + * The XSL stylesheet. + */ + private final Unchecked sheet; + + /** + * Ctor. + */ + public FxUnsortedMetas() { + this.sheet = new Unchecked<>( + new Sticky<>( + () -> new XSLDocument( + new IoCheckedText( + new TextOf( + new ResourceOf("org/eolang/fixes/metas/unsorted-metas.xsl") + ) + ).asString() + ).with(new ClasspathSources()) + ) + ); + } + + @Override + public XML apply(final XML xmir) throws IOException { + return this.sheet.value().transform(xmir); + } +} diff --git a/src/main/resources/org/eolang/fixes/metas/unsorted-metas.xsl b/src/main/resources/org/eolang/fixes/metas/unsorted-metas.xsl new file mode 100644 index 000000000..e6ea66644 --- /dev/null +++ b/src/main/resources/org/eolang/fixes/metas/unsorted-metas.xsl @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/eolang/lints/metas/unsorted-metas.xsl b/src/main/resources/org/eolang/lints/metas/unsorted-metas.xsl index d8f836ca5..94a74365c 100644 --- a/src/main/resources/org/eolang/lints/metas/unsorted-metas.xsl +++ b/src/main/resources/org/eolang/lints/metas/unsorted-metas.xsl @@ -13,8 +13,8 @@ - - + + diff --git a/src/test/java/org/eolang/lints/FxUnsortedMetasTest.java b/src/test/java/org/eolang/lints/FxUnsortedMetasTest.java new file mode 100644 index 000000000..31dd518e9 --- /dev/null +++ b/src/test/java/org/eolang/lints/FxUnsortedMetasTest.java @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com + * SPDX-License-Identifier: MIT + */ +package org.eolang.lints; + +import fixtures.EoProgram; +import java.util.Map; +import java.util.stream.Collectors; +import org.cactoos.io.InputOf; +import org.eolang.jucs.ClasspathSource; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.params.ParameterizedTest; +import org.yaml.snakeyaml.Yaml; + +/** + * Tests for {@link FxUnsortedMetas}. + * @since 0.2.1 + * @todo #896:60min Replace partial meta comparison with exact XMIR match. + * Currently the test only compares the ordered sequence of "head tail" + * strings extracted from the metas section. Since we have a clear 'input' + * and 'output' EO program in each YAML pack, we should compare the full + * XMIR structure of the fixed result against the expected XMIR, ignoring + * only volatile attributes such as @line numbers. + */ +final class FxUnsortedMetasTest { + + @ParameterizedTest + @ClasspathSource(value = "org/eolang/lints/fixes/unsorted-metas/", glob = "**.yaml") + void fixesUnsortedMetas(final String yaml) throws Exception { + final Map pack = new Yaml().load(yaml); + final Object input = pack.get("input"); + final Object output = pack.get("output"); + MatcherAssert.assertThat( + "Metas after fix must match the expected order", + new FxUnsortedMetas().apply( + new EoProgram( + String.valueOf(input.hashCode()), + new InputOf(input.toString()) + ).parse() + ).nodes("/object/metas/meta").stream().map( + m -> String.format( + "%s %s", + m.xpath("head/text()").get(0), + m.xpath("tail/text()").get(0) + ) + ).collect(Collectors.toList()), + Matchers.equalTo( + new EoProgram( + String.valueOf(output.hashCode()), + new InputOf(output.toString()) + ).parse().nodes("/object/metas/meta").stream().map( + m -> String.format( + "%s %s", + m.xpath("head/text()").get(0), + m.xpath("tail/text()").get(0) + ) + ).collect(Collectors.toList()) + ) + ); + } +} diff --git a/src/test/java/org/eolang/lints/LtByXslTest.java b/src/test/java/org/eolang/lints/LtByXslTest.java index b2900d2e7..cd2f60590 100644 --- a/src/test/java/org/eolang/lints/LtByXslTest.java +++ b/src/test/java/org/eolang/lints/LtByXslTest.java @@ -109,7 +109,7 @@ void checksLocationsOfYamlPacks() throws IOException { @SuppressWarnings("StreamResourceLeak") void catchesLostYamls() throws IOException { MatcherAssert.assertThat( - "All YAML files must be in allowed locations (single or wpa packs)", + "All YAML files must be in allowed locations (single, wpa packs, or fixes)", Files.walk(Paths.get("src/test/resources/org/eolang/lints")) .filter(Files::isRegularFile) .filter(LtByXslTest.yamls()) @@ -117,6 +117,7 @@ void catchesLostYamls() throws IOException { path -> path.endsWith("org/eolang/lints/packs/single") || path.endsWith("org/eolang/lints/packs/wpa") + || path.contains("org/eolang/lints/fixes") ), Matchers.equalTo(true) ); diff --git a/src/test/resources/org/eolang/lints/fixes/unsorted-metas/sorts-version-and-spdx.yaml b/src/test/resources/org/eolang/lints/fixes/unsorted-metas/sorts-version-and-spdx.yaml new file mode 100644 index 000000000..cad6b4a83 --- /dev/null +++ b/src/test/resources/org/eolang/lints/fixes/unsorted-metas/sorts-version-and-spdx.yaml @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +sheets: + - /org/eolang/fixes/metas/unsorted-metas.xsl +input: | + +version 0.0.0 + +spdx SPDX-License-Identifier: MIT + + # No comments. + [] > foo + 42 > @ +output: | + +spdx SPDX-License-Identifier: MIT + +version 0.0.0 + + # No comments. + [] > foo + 42 > @