diff --git a/pom.xml b/pom.xml index 8c25f0cae..1a13d2fab 100644 --- a/pom.xml +++ b/pom.xml @@ -359,7 +359,7 @@ org.eolang.lints.PkMonoTest org.eolang.lints.LtByXslTest org.eolang.lints.PkWpaTest - org.eolang.lints.ProgramTest + org.eolang.lints.EoPackageTest org.eolang.lints.LtUnlintNonExistingDefectWpaTest org.eolang.lints.LtTestNotVerbTest org.eolang.lints.WpaLintsTest diff --git a/src/it/lints-it/src/test/java/org/eolang/lints/it/LintsItTest.java b/src/it/lints-it/src/test/java/org/eolang/lints/it/LintsItTest.java index 12f68d8a7..72c823519 100644 --- a/src/it/lints-it/src/test/java/org/eolang/lints/it/LintsItTest.java +++ b/src/it/lints-it/src/test/java/org/eolang/lints/it/LintsItTest.java @@ -6,7 +6,8 @@ import com.jcabi.xml.XMLDocument; import java.io.IOException; -import org.eolang.lints.Source; +import java.util.Map; +import org.eolang.lints.Program; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; @@ -22,7 +23,12 @@ final class LintsItTest { void lintsSource() throws IOException { MatcherAssert.assertThat( "passes with no exceptions", - new Source(new XMLDocument("")).defects(), + new Program( + Map.of( + "main.eo", + new XMLDocument("") + ) + ).defects(), Matchers.notNullValue() ); } diff --git a/src/main/java/org/eolang/lints/EoPackage.java b/src/main/java/org/eolang/lints/EoPackage.java new file mode 100644 index 000000000..f78e8684a --- /dev/null +++ b/src/main/java/org/eolang/lints/EoPackage.java @@ -0,0 +1,163 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com + * SPDX-License-Identifier: MIT + */ +package org.eolang.lints; + +import com.jcabi.xml.XML; +import com.jcabi.xml.XMLDocument; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.cactoos.iterable.Sticky; +import org.cactoos.list.ListOf; +import org.cactoos.list.Synced; + +/** + * Whole EO package, as collection of XMIR sources to analyze. + * @since 0.1.0 + */ +final class EoPackage { + + /** + * Collection of wpa lints, preloaded on JVM start. + */ + private static final Iterable>> WPA = new Synced<>( + new ListOf<>( + new Sticky<>( + new PkWpa() + ) + ) + ); + + /** + * Lints to use. + */ + private final Iterable>> lints; + + /** + * The package of XMIR files. + */ + private final Map pkg; + + /** + * Ctor. + * @param dirs The directory + * @throws IOException If fails + */ + EoPackage(final Path... dirs) throws IOException { + this(Arrays.asList(dirs)); + } + + /** + * Ctor. + * + *

Pay attention, it's important to use {@link Collection} as a type + * of argument, because {@link Path} implements {@link Iterable}.

+ * + * @param dirs The directory + * @throws IOException If fails + */ + EoPackage(final Collection dirs) throws IOException { + this(EoPackage.discover(dirs)); + } + + /** + * Ctor. + * @param map The map with them + */ + EoPackage(final Map map) { + this(map, EoPackage.WPA); + } + + /** + * Ctor. + * @param map The map with them + * @param list The lints + */ + EoPackage(final Map map, final Iterable>> list) { + this.pkg = Collections.unmodifiableMap(map); + this.lints = list; + } + + /** + * Package with disabled lints. + * @param names Lint names + * @return Package analysis without specifics names + */ + public EoPackage without(final String... names) { + return new EoPackage(this.pkg, new WpaWithout(names)); + } + + /** + * Find all possible defects in the EO package. + * @return All defects found + */ + public Collection defects() { + final Collection messages = new ArrayList<>(0); + for (final Lint> lint : this.lints) { + try { + messages.addAll(new ScopedDefects(lint.defects(this.pkg), "WPA")); + } catch (final IOException exception) { + throw new IllegalStateException( + String.format( + "Failed to find defects in the '%s' package with '%s' lint", + this.pkg, + lint + ), + exception + ); + } + } + return messages; + } + + /** + * Discover all XMIR files in the directory. + * @param dirs The directories to search for XMIR files in (recursively) + * @return Map of XMIR files + * @throws IOException If fails + */ + private static Map discover(final Iterable dirs) throws IOException { + final Map map = new HashMap<>(0); + for (final Path dir : dirs) { + map.putAll(EoPackage.discover(dir)); + } + return map; + } + + /** + * Discover all XMIR files in the directory. + * @param dir The directories to search for XMIR files in (recursively) + * @return Map of XMIR files + * @throws IOException If fails + */ + private static Map discover(final Path dir) throws IOException { + try (Stream walk = Files.walk(dir)) { + return walk + .filter(Files::isRegularFile) + .collect( + Collectors.toMap( + path -> new XmirKey(path, dir).asString(), + path -> { + try { + return new XMLDocument(path); + } catch (final FileNotFoundException ex) { + throw new IllegalArgumentException(ex); + } + } + ) + ); + } + } + +} diff --git a/src/main/java/org/eolang/lints/PkWpa.java b/src/main/java/org/eolang/lints/PkWpa.java index f8834bc07..f03ab2b2f 100644 --- a/src/main/java/org/eolang/lints/PkWpa.java +++ b/src/main/java/org/eolang/lints/PkWpa.java @@ -13,8 +13,8 @@ import org.cactoos.list.ListOf; /** - * A collection of lints for Whole Program Analysis (WPA), - * provided by the {@link Program} class. + * A collection of lints for Whole Package Analysis (WPA), + * provided by the {@link EoPackage} class. * *

This class is thread-safe.

* diff --git a/src/main/java/org/eolang/lints/Program.java b/src/main/java/org/eolang/lints/Program.java index 3d5fbfec8..bfda076fc 100644 --- a/src/main/java/org/eolang/lints/Program.java +++ b/src/main/java/org/eolang/lints/Program.java @@ -5,22 +5,15 @@ package org.eolang.lints; import com.jcabi.xml.XML; -import com.jcabi.xml.XMLDocument; -import java.io.FileNotFoundException; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.cactoos.iterable.Sticky; -import org.cactoos.list.ListOf; -import org.cactoos.list.Synced; +import org.cactoos.func.CheckedFunc; /** * Whole EO program, as collection of XMIR sources to analyze. @@ -29,43 +22,38 @@ *
  * {@code
  * import com.jcabi.manifests.Manifests;
- *
  * final String version = Manifests.read("Lints-Version");
  * }
  * 
+ * * @see XMIR - * @since 0.1.0 + * @since 0.0.49 */ -public final class Program { - - /** - * Collection of mono lints, preloaded on JVM start. - */ - private static final Iterable>> WPA = new Synced<>( - new ListOf<>( - new Sticky<>( - new PkWpa() - ) - ) - ); - +public class Program { /** - * Lints to use. + * EO package. */ - private final Iterable>> lints; + private final EoPackage pkg; /** - * The program package of XMIR files. + * All sources of EO package {@link #pkg}. */ - private final Map pkg; + private final Collection srcs; /** * Ctor. + * * @param dirs The directory * @throws IOException If fails */ public Program(final Path... dirs) throws IOException { - this(Arrays.asList(dirs)); + this( + new EoPackage(dirs), + Program.sources( + Arrays.asList(dirs), + new CheckedFunc<>(Source::new, IOException.class::cast) + ) + ); } /** @@ -78,103 +66,68 @@ public Program(final Path... dirs) throws IOException { * @throws IOException If fails */ public Program(final Collection dirs) throws IOException { - this(Program.discover(dirs)); + this( + new EoPackage(dirs), + Program.sources(dirs, new CheckedFunc<>(Source::new, IOException.class::cast)) + ); } /** * Ctor. + * * @param map The map with them */ public Program(final Map map) { - this(map, Program.WPA); + this( + new EoPackage(map), + Program.sources( + map.values(), + new CheckedFunc<>(Source::new, RuntimeException.class::cast) + ) + ); } - /** - * Ctor. - * - *

This constructor is for internal use only. It is not supposed - * to be visible by end-users. Keep it this way!

- * - * @param map The map with them - * @param list The lints - */ - Program(final Map map, final Iterable>> list) { - this.pkg = Collections.unmodifiableMap(map); - this.lints = list; + Program(final EoPackage pkg, final Collection srcs) { + this.pkg = pkg; + this.srcs = srcs; } /** * Program with disabled lints. + * * @param names Lint names * @return Program analysis without specifics names */ public Program without(final String... names) { - return new Program(this.pkg, new WpaWithout(names)); + return new Program( + this.pkg.without(names), + this.srcs.stream() + .map(source -> source.without(names)) + .collect(Collectors.toList()) + ); } /** * Find all possible defects in the EO program. + * * @return All defects found * @see XMIR guide * @see XMIR specification * @see XMIR schema */ public Collection defects() { - final Collection messages = new ArrayList<>(0); - for (final Lint> lint : this.lints) { - try { - messages.addAll(new ScopedDefects(lint.defects(this.pkg), "WPA")); - } catch (final IOException exception) { - throw new IllegalStateException( - String.format( - "Failed to find defects in the '%s' package with '%s' lint", - this.pkg, - lint - ), - exception - ); - } - } - return messages; + return Stream.concat( + this.pkg.defects().stream(), + this.srcs.stream().map(Source::defects).flatMap(Collection::stream) + ).collect(Collectors.toList()); } - /** - * Discover all XMIR files in the directory. - * @param dirs The directories to search for XMIR files in (recursively) - * @return Map of XMIR files - * @throws IOException If fails - */ - private static Map discover(final Iterable dirs) throws IOException { - final Map map = new HashMap<>(0); - for (final Path dir : dirs) { - map.putAll(Program.discover(dir)); + private static Collection sources(final Collection elements, + final CheckedFunc ctor) throws E { + final ArrayList sources = new ArrayList<>(elements.size()); + for (final T element : elements) { + sources.add(ctor.apply(element)); } - return map; + return sources; } - - /** - * Discover all XMIR files in the directory. - * @param dir The directories to search for XMIR files in (recursively) - * @return Map of XMIR files - * @throws IOException If fails - */ - private static Map discover(final Path dir) throws IOException { - try (Stream walk = Files.walk(dir)) { - return walk - .filter(Files::isRegularFile) - .collect( - Collectors.toMap( - path -> new XmirKey(path, dir).asString(), - path -> { - try { - return new XMLDocument(path); - } catch (final FileNotFoundException ex) { - throw new IllegalArgumentException(ex); - } - } - ) - ); - } - } - } diff --git a/src/main/java/org/eolang/lints/Source.java b/src/main/java/org/eolang/lints/Source.java index 3c92f98e0..bef801512 100644 --- a/src/main/java/org/eolang/lints/Source.java +++ b/src/main/java/org/eolang/lints/Source.java @@ -16,11 +16,9 @@ /** * A single source XMIR to analyze. - * - * @see XMIR * @since 0.1.0 */ -public final class Source { +final class Source { /** * Collection of mono lints, preloaded on JVM start. @@ -46,7 +44,7 @@ public final class Source { * @param file The absolute path of the XMIR file * @throws FileNotFoundException If file isn't found */ - public Source(final Path file) throws FileNotFoundException { + Source(final Path file) throws FileNotFoundException { this(new XMLDocument(file)); } @@ -54,16 +52,12 @@ public Source(final Path file) throws FileNotFoundException { * Ctor. * @param xml The XMIR */ - public Source(final XML xml) { + Source(final XML xml) { this(xml, Source.MONO); } /** * Ctor. - * - *

This constructor is for internal use only. It is not supposed - * to be visible by end-users. Keep it this way!

- * * @param xml The XMIR * @param list The lints */ @@ -77,18 +71,15 @@ public Source(final XML xml) { * @param names Lint names * @return Program analysis without specific name */ - public Source without(final String... names) { + Source without(final String... names) { return new Source(this.xmir, new MonoWithout(names)); } /** * Find defects possible defects in the XMIR file. * @return All defects found - * @see XMIR guide - * @see XMIR specification - * @see XMIR schema */ - public Collection defects() { + Collection defects() { try { final Collection messages = new ArrayList<>(0); for (final Lint lint : this.lints) { diff --git a/src/test/java/benchmarks/package-info.java b/src/test/java/benchmarks/package-info.java deleted file mode 100644 index 1b69d9790..000000000 --- a/src/test/java/benchmarks/package-info.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com - * SPDX-License-Identifier: MIT - */ - -/** - * Benchmarks. - * - * @since 0.0.1 - */ -package benchmarks; diff --git a/src/test/java/org/eolang/lints/ProgramTest.java b/src/test/java/org/eolang/lints/EoPackageTest.java similarity index 94% rename from src/test/java/org/eolang/lints/ProgramTest.java rename to src/test/java/org/eolang/lints/EoPackageTest.java index 695617f8e..d5f125003 100644 --- a/src/test/java/org/eolang/lints/ProgramTest.java +++ b/src/test/java/org/eolang/lints/EoPackageTest.java @@ -28,18 +28,18 @@ import org.junit.jupiter.params.provider.ValueSource; /** - * Test for {@link Program}. + * Test for {@link EoPackage}. * * @since 0.1.0 */ @ExtendWith(MktmpResolver.class) -final class ProgramTest { +final class EoPackageTest { @Test void checksSimple(@Mktmp final Path dir) throws IOException { MatcherAssert.assertThat( "the defect is found", - new Program( + new EoPackage( this.withSource( dir, "a/b/c/foo.xmir", @@ -57,7 +57,7 @@ void checksSimple(@Mktmp final Path dir) throws IOException { void skipsAllWarnings(@Mktmp final Path dir) throws IOException { MatcherAssert.assertThat( "the defect is found", - new Program( + new EoPackage( this.withSource( dir, "bar.xmir", @@ -86,7 +86,7 @@ void checksInParallel(@Mktmp final Path dir) throws IOException { "", new SetOf<>( new Together<>( - thread -> new Program(source).defects().size() + thread -> new EoPackage(source).defects().size() ) ).size(), Matchers.equalTo(1) @@ -96,7 +96,7 @@ void checksInParallel(@Mktmp final Path dir) throws IOException { @Test void doesNotThrowIoException() { Assertions.assertDoesNotThrow( - () -> new Program(new ListOf<>()).defects(), + () -> new EoPackage(new ListOf<>()).defects(), "Exception was thrown, but it should not be" ); } @@ -106,7 +106,7 @@ void createsProgramWithoutOneLint(@Mktmp final Path dir) throws IOException { final String disabled = "unit-test-missing"; MatcherAssert.assertThat( "Defects for disabled lint are not empty, but should be", - new Program( + new EoPackage( this.withSource( dir, "bar.xmir", @@ -123,7 +123,7 @@ void createsProgramWithoutOneLint(@Mktmp final Path dir) throws IOException { void createsProgramWithoutMultipleLints(@Mktmp final Path dir) throws IOException { MatcherAssert.assertThat( "Defects for disabled lint are not empty, but should be", - new Program( + new EoPackage( this.withSource( dir, "bar.xmir", @@ -146,7 +146,7 @@ void createsProgramWithoutMultipleLints(@Mktmp final Path dir) throws IOExceptio void catchesBrokenUnlintAfterLintWasRemoved(final String lid) throws IOException { MatcherAssert.assertThat( "Found defect does not match with expected", - new Program( + new EoPackage( new MapOf<>( "f", new EoSyntax( @@ -181,7 +181,7 @@ void catchesBrokenUnlintAfterLintWasRemoved(final String lid) throws IOException void outputsInformationAboutWpaScope() throws IOException { MatcherAssert.assertThat( "Found defects don't contain information about WPA scope, but they should", - new Program( + new EoPackage( new MapOf<>( "foo", new EoSyntax( diff --git a/src/test/java/org/eolang/lints/LtIncorrectAliasTest.java b/src/test/java/org/eolang/lints/LtIncorrectAliasTest.java index 7ea210a84..3c03ef6c2 100644 --- a/src/test/java/org/eolang/lints/LtIncorrectAliasTest.java +++ b/src/test/java/org/eolang/lints/LtIncorrectAliasTest.java @@ -156,7 +156,7 @@ void acceptsValidDirectory(@Mktmp final Path dir) throws Exception { ); MatcherAssert.assertThat( "Defects are not empty, but should be", - new Program(dir).defects(), + new EoPackage(dir).defects(), Matchers.emptyIterable() ); } @@ -199,7 +199,7 @@ void acceptsValidDirectoryWithLongerAlias(@Mktmp final Path dir) throws Exceptio ); MatcherAssert.assertThat( "Defects are not empty, but should be", - new Program(dir).defects(), + new EoPackage(dir).defects(), Matchers.emptyIterable() ); } diff --git a/src/test/java/org/eolang/lints/LtUnitTestMissingTest.java b/src/test/java/org/eolang/lints/LtUnitTestMissingTest.java index 5d66dc320..cfb7e6c85 100644 --- a/src/test/java/org/eolang/lints/LtUnitTestMissingTest.java +++ b/src/test/java/org/eolang/lints/LtUnitTestMissingTest.java @@ -56,7 +56,7 @@ void acceptsValidDirectory(@Mktmp final Path dir) throws IOException { ); MatcherAssert.assertThat( "some defects found by mistake", - new Program(dir).defects(), + new EoPackage(dir).defects(), Matchers.emptyIterable() ); } @@ -70,7 +70,7 @@ void issuesDetectsOnMissingTest(@Mktmp final Path dir) throws IOException { ); MatcherAssert.assertThat( " defects found", - new Program(dir).defects(), + new EoPackage(dir).defects(), Matchers.allOf( Matchers.iterableWithSize(Matchers.greaterThan(0)), Matchers.everyItem(new DefectMatcher()) diff --git a/src/test/java/benchmarks/ProgramBench.java b/src/test/java/org/eolang/lints/ProgramBench.java similarity index 94% rename from src/test/java/benchmarks/ProgramBench.java rename to src/test/java/org/eolang/lints/ProgramBench.java index 5056c74d6..a063979ca 100644 --- a/src/test/java/benchmarks/ProgramBench.java +++ b/src/test/java/org/eolang/lints/ProgramBench.java @@ -2,7 +2,7 @@ * SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com * SPDX-License-Identifier: MIT */ -package benchmarks; +package org.eolang.lints; import fixtures.BytecodeClass; import fixtures.SourceSize; @@ -12,8 +12,6 @@ import java.nio.file.Path; import java.util.concurrent.TimeUnit; import org.cactoos.scalar.IoChecked; -import org.eolang.lints.Program; -import org.eolang.lints.Source; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -63,6 +61,6 @@ public ProgramBench() { @Benchmark public final void scansLargeProgram() throws IOException { - new Program(this.home).defects(); + new EoPackage(this.home).defects(); } } diff --git a/src/test/java/benchmarks/SourceBench.java b/src/test/java/org/eolang/lints/SourceBench.java similarity index 97% rename from src/test/java/benchmarks/SourceBench.java rename to src/test/java/org/eolang/lints/SourceBench.java index 97b8ecc1e..2346e65a3 100644 --- a/src/test/java/benchmarks/SourceBench.java +++ b/src/test/java/org/eolang/lints/SourceBench.java @@ -2,14 +2,13 @@ * SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com * SPDX-License-Identifier: MIT */ -package benchmarks; +package org.eolang.lints; import com.jcabi.xml.XML; import fixtures.BytecodeClass; import fixtures.SourceSize; import java.util.concurrent.TimeUnit; import org.cactoos.scalar.Unchecked; -import org.eolang.lints.Source; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork;