Get the type.
+ * @return the type
+ * @since 1.0.0
+ */
+ public T getType() {
+ return type;
+ }
+
+ /**
+ * Get the identifier.
+ * @return the identifier
+ * @since 1.0.0
+ */
+ public ArtifactIdentifier getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * Get an {@link Optional} of the version.
+ * @return the {@link Optional} of the version
+ * @since 1.0.0
+ */
+ public Optional getOptionalVersion() {
+ return Optional.ofNullable(version);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifier.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifier.java
new file mode 100644
index 0000000..b194796
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifier.java
@@ -0,0 +1,124 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.Equals;
+import com.github.alexisjehan.javanilla.misc.quality.HashCode;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.javanilla.misc.tuple.Pair;
+
+/**
+ * Class that describes an artifact identifier.
+ * @since 1.0.0
+ */
+public final class ArtifactIdentifier {
+
+ /**
+ * Group identifier.
+ * @since 1.0.0
+ */
+ private final String groupId;
+
+ /**
+ * Artifact identifier.
+ * @since 1.0.0
+ */
+ private final String artifactId;
+
+ /**
+ * Constructor.
+ * @param groupId a group identifier
+ * @param artifactId an artifact identifier
+ * @throws NullPointerException if the group identifier or the artifact identifier is {@code null}
+ * @throws IllegalArgumentException if the group identifier or the artifact identifier is empty
+ * @since 1.0.0
+ */
+ public ArtifactIdentifier(final String groupId, final String artifactId) {
+ Ensure.notNullAndNotEmpty("groupId", groupId);
+ Ensure.notNullAndNotEmpty("artifactId", artifactId);
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean equals(final Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof ArtifactIdentifier)) {
+ return false;
+ }
+ final var other = (ArtifactIdentifier) object;
+ return Equals.equals(groupId, other.groupId)
+ && Equals.equals(artifactId, other.artifactId);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.of(
+ HashCode.hashCode(groupId),
+ HashCode.hashCode(artifactId)
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public String toString() {
+ return ToString.of(
+ this,
+ Pair.of("groupId", ToString.toString(groupId)),
+ Pair.of("artifactId", ToString.toString(artifactId))
+ );
+ }
+
+ /**
+ * Get the group identifier.
+ * @return the group identifier
+ * @since 1.0.0
+ */
+ public String getGroupId() {
+ return groupId;
+ }
+
+ /**
+ * Get the artifact identifier.
+ * @return the artifact identifier
+ * @since 1.0.0
+ */
+ public String getArtifactId() {
+ return artifactId;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/package-info.java
new file mode 100644
index 0000000..caa51ac
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Artifact components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/ArtifactType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/ArtifactType.java
new file mode 100644
index 0000000..eb09ca6
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/ArtifactType.java
@@ -0,0 +1,42 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.type;
+
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+
+/**
+ * Interface that describes an artifact type.
+ * @since 1.0.0
+ */
+public interface ArtifactType {
+
+ /**
+ * Get the repository type.
+ * @return the repository type
+ * @since 1.0.0
+ */
+ default RepositoryType getRepositoryType() {
+ return RepositoryType.NORMAL;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactType.java
new file mode 100644
index 0000000..ee9134a
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactType.java
@@ -0,0 +1,218 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.type;
+
+import com.github.alexisjehan.javanilla.misc.CaseStyle;
+
+import java.util.Set;
+
+/**
+ * Enumeration of Gradle artifact types.
+ * Note: Based on {@code org.gradle:gradle-tooling-api:7.6}.
+ * @see https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_plugin_and_dependency_management
+ * @see https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph
+ * @since 1.0.0
+ */
+public enum GradleArtifactType implements ArtifactType {
+
+ /**
+ * Annotation processors and their dependency artifacts.
+ * Note: Added since Gradle 4.6.
+ * @since 1.0.0
+ */
+ ANNOTATION_PROCESSOR,
+
+ /**
+ * API dependency artifacts.
+ * @since 1.0.0
+ */
+ API,
+
+ /**
+ * Dependency artifacts.
+ * Note: Deprecated since Gradle 4.7.
+ * Note: Removed since Gradle 7.0 (Superseded by {@link IMPLEMENTATION}).
+ * @since 1.0.0
+ */
+ COMPILE(Property.DEPRECATED),
+
+ /**
+ * Compile classpath artifacts.
+ * @since 1.0.0
+ */
+ COMPILE_CLASSPATH(Property.CLASSPATH),
+
+ /**
+ * Compile only dependency artifacts.
+ * @since 1.0.0
+ */
+ COMPILE_ONLY,
+
+ /**
+ * Compile only API dependency artifacts.
+ * Note: Added since Gradle 6.7.
+ * @since 1.0.0
+ */
+ COMPILE_ONLY_API,
+
+ /**
+ * Implementation only dependency artifacts.
+ * @since 1.0.0
+ */
+ IMPLEMENTATION,
+
+ /**
+ * Runtime dependency artifacts.
+ * Note: Deprecated since Gradle 4.7.
+ * Note: Removed since Gradle 7.0 (Superseded by {@link RUNTIME_ONLY}).
+ * @since 1.0.0
+ */
+ RUNTIME(Property.DEPRECATED),
+
+ /**
+ * Runtime classpath artifacts.
+ * @since 1.0.0
+ */
+ RUNTIME_CLASSPATH(Property.CLASSPATH),
+
+ /**
+ * Runtime only dependency artifacts.
+ * @since 1.0.0
+ */
+ RUNTIME_ONLY,
+
+ /**
+ * Test annotation processors and their dependency artifacts.
+ * Note: Added since Gradle 4.6.
+ * @since 1.0.0
+ */
+ TEST_ANNOTATION_PROCESSOR,
+
+ /**
+ * Test dependency artifacts.
+ * Note: Deprecated since Gradle 4.7.
+ * Note: Removed since Gradle 7.0 (Superseded by {@link TEST_IMPLEMENTATION}).
+ * @since 1.0.0
+ */
+ TEST_COMPILE(Property.DEPRECATED),
+
+ /**
+ * Test compile classpath artifacts.
+ * @since 1.0.0
+ */
+ TEST_COMPILE_CLASSPATH(Property.CLASSPATH),
+
+ /**
+ * Test compile only dependency artifacts.
+ * @since 1.0.0
+ */
+ TEST_COMPILE_ONLY,
+
+ /**
+ * Test implementation only dependency artifacts.
+ * @since 1.0.0
+ */
+ TEST_IMPLEMENTATION,
+
+ /**
+ * Test runtime dependency artifacts.
+ * Note: Deprecated since Gradle 4.7.
+ * Note: Removed since Gradle 7.0 (Superseded by {@link TEST_RUNTIME_ONLY}).
+ * @since 1.0.0
+ */
+ TEST_RUNTIME(Property.DEPRECATED),
+
+ /**
+ * Test runtime classpath artifacts.
+ * @since 1.0.0
+ */
+ TEST_RUNTIME_CLASSPATH(Property.CLASSPATH),
+
+ /**
+ * Test runtime only dependency artifacts.
+ * @since 1.0.0
+ */
+ TEST_RUNTIME_ONLY;
+
+ /**
+ * Enumeration of properties.
+ * @since 1.0.0
+ */
+ private enum Property {
+
+ /**
+ * Flagged as a classpath artifact type.
+ * @since 1.0.0
+ */
+ CLASSPATH,
+
+ /**
+ * Flagged as a deprecated artifact type.
+ * @since 1.0.0
+ */
+ DEPRECATED
+ }
+
+ /**
+ * {@link Set} of properties.
+ * @since 1.0.0
+ */
+ private final Set properties;
+
+ /**
+ * Constructor.
+ * @param properties an array of properties
+ * @since 1.0.0
+ */
+ GradleArtifactType(final Property... properties) {
+ this.properties = Set.of(properties);
+ }
+
+ /**
+ * Return the name printed by the Gradle {@code :dependencies} task.
+ * @return the name
+ * @since 1.0.0
+ */
+ public final String dependenciesTaskName() {
+ return CaseStyle.CAMEL.of(name(), CaseStyle.MACRO);
+ }
+
+ /**
+ * Get if this is a classpath artifact type.
+ * @return {@code true} if this is a classpath artifact type
+ * @since 1.0.0
+ */
+ public final boolean isClasspath() {
+ return properties.contains(Property.CLASSPATH);
+ }
+
+ /**
+ * Get if this is a deprecated artifact type.
+ * @return {@code true} if this is a deprecated artifact type
+ * @since 1.0.0
+ */
+ public final boolean isDeprecated() {
+ return properties.contains(Property.DEPRECATED);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactType.java
new file mode 100644
index 0000000..a79840f
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactType.java
@@ -0,0 +1,171 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.type;
+
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+
+/**
+ * Enumeration of Maven artifact types.
+ * Note: Based on {@code org.apache.maven:maven-core:3.8.6}.
+ * @see https://maven.apache.org/ref/current/maven-model/maven.html
+ * @since 1.0.0
+ */
+public enum MavenArtifactType implements ArtifactType {
+
+ /**
+ * The parent artifact.
+ * @since 1.0.0
+ */
+ PARENT,
+
+ /**
+ * Dependency management dependency artifacts.
+ * @since 1.0.0
+ */
+ DEPENDENCY_MANAGEMENT_DEPENDENCY,
+
+ /**
+ * Dependency artifacts.
+ * @since 1.0.0
+ */
+ DEPENDENCY,
+
+ /**
+ * Build extension artifacts.
+ * @since 1.0.0
+ */
+ BUILD_EXTENSION,
+
+ /**
+ * Build plugin management plugin artifacts.
+ * @since 1.0.0
+ */
+ BUILD_PLUGIN_MANAGEMENT_PLUGIN(true),
+
+ /**
+ * Build plugin management plugin dependency artifacts.
+ * @since 1.0.0
+ */
+ BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY,
+
+ /**
+ * Build plugin artifacts.
+ * @since 1.0.0
+ */
+ BUILD_PLUGIN(true),
+
+ /**
+ * Build plugin dependency artifacts.
+ * @since 1.0.0
+ */
+ BUILD_PLUGIN_DEPENDENCY,
+
+ /**
+ * Reporting plugin artifacts.
+ * @since 1.0.0
+ */
+ REPORTING_PLUGIN(true),
+
+ /**
+ * Profile build plugin management plugin artifacts.
+ * @since 1.0.0
+ */
+ PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN(true),
+
+ /**
+ * Profile build plugin management plugin dependency artifacts.
+ * @since 1.0.0
+ */
+ PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY,
+
+ /**
+ * Profile build plugin artifacts.
+ * @since 1.0.0
+ */
+ PROFILE_BUILD_PLUGIN(true),
+
+ /**
+ * Profile build plugin dependency artifacts.
+ * @since 1.0.0
+ */
+ PROFILE_BUILD_PLUGIN_DEPENDENCY,
+
+ /**
+ * Profile dependency management dependency artifacts.
+ * @since 1.0.0
+ */
+ PROFILE_DEPENDENCY_MANAGEMENT_DEPENDENCY,
+
+ /**
+ * Profile dependency artifacts.
+ * @since 1.0.0
+ */
+ PROFILE_DEPENDENCY,
+
+ /**
+ * Profile reporting plugin artifacts.
+ * @since 1.0.0
+ */
+ PROFILE_REPORTING_PLUGIN(true);
+
+ /**
+ * Default value depending on whether any related artifact is a plugin or not.
+ * @since 1.0.0
+ */
+ private static final boolean DEFAULT_PLUGIN = false;
+
+ /**
+ * Repository type.
+ * @since 1.0.0
+ */
+ private final RepositoryType repositoryType;
+
+ /**
+ * Constructor by default.
+ * @since 1.0.0
+ */
+ MavenArtifactType() {
+ this(DEFAULT_PLUGIN);
+ }
+
+ /**
+ * Constructor depending on whether any related artifact is a plugin or not.
+ * @param plugin {@code true} if any related artifact is a plugin
+ * @since 1.0.0
+ */
+ MavenArtifactType(final boolean plugin) {
+ repositoryType = plugin
+ ? RepositoryType.PLUGIN
+ : RepositoryType.NORMAL;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public final RepositoryType getRepositoryType() {
+ return repositoryType;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/package-info.java
new file mode 100644
index 0000000..c599239
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Artifact type components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.type;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersions.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersions.java
new file mode 100644
index 0000000..c49272b
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersions.java
@@ -0,0 +1,127 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.Equals;
+import com.github.alexisjehan.javanilla.misc.quality.HashCode;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.javanilla.misc.tuple.Pair;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+
+import java.util.List;
+
+/**
+ * Class that describes available versions for an artifact.
+ * @since 1.0.0
+ */
+public final class ArtifactAvailableVersions {
+
+ /**
+ * Artifact.
+ * @since 1.0.0
+ */
+ private final Artifact> artifact;
+
+ /**
+ * {@link List} of available versions.
+ * @since 1.0.0
+ */
+ private final List availableVersions;
+
+ /**
+ * Constructor.
+ * @param artifact an artifact
+ * @param availableVersions a {@link List} of available versions
+ * @throws NullPointerException if the artifact, the {@link List} of available versions or any of them is
+ * {@code null}
+ * @since 1.0.0
+ */
+ public ArtifactAvailableVersions(final Artifact> artifact, final List availableVersions) {
+ Ensure.notNull("artifact", artifact);
+ Ensure.notNullAndNotNullElements("availableVersions", availableVersions);
+ this.artifact = artifact;
+ this.availableVersions = List.copyOf(availableVersions);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean equals(final Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof ArtifactAvailableVersions)) {
+ return false;
+ }
+ final var other = (ArtifactAvailableVersions) object;
+ return Equals.equals(artifact, other.artifact)
+ && Equals.equals(availableVersions, other.availableVersions);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.of(
+ HashCode.hashCode(artifact),
+ HashCode.hashCode(availableVersions)
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public String toString() {
+ return ToString.of(
+ this,
+ Pair.of("artifact", ToString.toString(artifact)),
+ Pair.of("availableVersions", ToString.toString(availableVersions))
+ );
+ }
+
+ /**
+ * Get the artifact.
+ * @return the artifact
+ * @since 1.0.0
+ */
+ public Artifact> getArtifact() {
+ return artifact;
+ }
+
+ /**
+ * Get the {@link List} of available versions.
+ * @return the {@link List} of available versions
+ * @since 1.0.0
+ */
+ public List getAvailableVersions() {
+ return availableVersions;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersion.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersion.java
new file mode 100644
index 0000000..da1aa40
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersion.java
@@ -0,0 +1,125 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.Equals;
+import com.github.alexisjehan.javanilla.misc.quality.HashCode;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.javanilla.misc.tuple.Pair;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+
+/**
+ * Class that describes an update version for an artifact.
+ * @since 1.0.0
+ */
+public final class ArtifactUpdateVersion {
+
+ /**
+ * Artifact.
+ * @since 1.0.0
+ */
+ private final Artifact> artifact;
+
+ /**
+ * Update version.
+ * @since 1.0.0
+ */
+ private final String updateVersion;
+
+ /**
+ * Constructor.
+ * @param artifact an artifact
+ * @param updateVersion an update version
+ * @throws NullPointerException if the artifact or the update version is {@code null}
+ * @throws IllegalArgumentException if the update version is empty
+ * @since 1.0.0
+ */
+ public ArtifactUpdateVersion(final Artifact> artifact, final String updateVersion) {
+ Ensure.notNull("artifact", artifact);
+ Ensure.notNullAndNotEmpty("updateVersion", updateVersion);
+ this.artifact = artifact;
+ this.updateVersion = updateVersion;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean equals(final Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof ArtifactUpdateVersion)) {
+ return false;
+ }
+ final var other = (ArtifactUpdateVersion) object;
+ return Equals.equals(artifact, other.artifact)
+ && Equals.equals(updateVersion, other.updateVersion);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.of(
+ HashCode.hashCode(artifact),
+ HashCode.hashCode(updateVersion)
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public String toString() {
+ return ToString.of(
+ this,
+ Pair.of("artifact", ToString.toString(artifact)),
+ Pair.of("updateVersion", ToString.toString(updateVersion))
+ );
+ }
+
+ /**
+ * Get the artifact.
+ * @return the artifact
+ * @since 1.0.0
+ */
+ public Artifact> getArtifact() {
+ return artifact;
+ }
+
+ /**
+ * Get the update version.
+ * @return the update version
+ * @since 1.0.0
+ */
+ public String getUpdateVersion() {
+ return updateVersion;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/package-info.java
new file mode 100644
index 0000000..25327bd
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Artifact version components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/ArtifactAvailableVersionsResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/ArtifactAvailableVersionsResolver.java
new file mode 100644
index 0000000..31940c4
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/ArtifactAvailableVersionsResolver.java
@@ -0,0 +1,47 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactAvailableVersions;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+
+import java.util.List;
+
+/**
+ * Interface that describes a resolver of available versions for an artifact.
+ * @since 1.0.0
+ */
+@FunctionalInterface
+public interface ArtifactAvailableVersionsResolver {
+
+ /**
+ * Resolve available versions for an artifact.
+ * @param artifact an artifact
+ * @param repositories a {@link List} of repositories
+ * @return available versions
+ * @since 1.0.0
+ */
+ ArtifactAvailableVersions resolve(final Artifact> artifact, final List repositories);
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolver.java
new file mode 100644
index 0000000..297b916
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolver.java
@@ -0,0 +1,128 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactAvailableVersions;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import com.github.alexisjehan.mavencheck.core.component.session.MavenSession;
+import com.github.alexisjehan.mavencheck.core.util.MavenUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.resolution.VersionRangeRequest;
+import org.eclipse.aether.resolution.VersionRangeResolutionException;
+import org.eclipse.aether.resolution.VersionRangeResult;
+import org.eclipse.aether.version.Version;
+
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Class that describes a Maven resolver of available versions for an artifact.
+ * @since 1.0.0
+ */
+public final class MavenArtifactAvailableVersionsResolver implements ArtifactAvailableVersionsResolver {
+
+ /**
+ * Logger.
+ * @since 1.0.0
+ */
+ private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass());
+
+ /**
+ * Maven session.
+ * @since 1.0.0
+ */
+ private final MavenSession session;
+
+ /**
+ * Constructor.
+ * @param session a Maven session
+ * @since 1.0.0
+ */
+ public MavenArtifactAvailableVersionsResolver(final MavenSession session) {
+ Ensure.notNull("session", session);
+ this.session = session;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact, the {@link List} of repositories or any of them is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public ArtifactAvailableVersions resolve(final Artifact> artifact, final List repositories) {
+ Ensure.notNull("artifact", artifact);
+ Ensure.notNullAndNotNullElements("repositories", repositories);
+ logger.info("Resolving {} artifact available versions", () -> ToString.toString(artifact));
+ final var artifactType = artifact.getType();
+ final var artifactIdentifier = artifact.getIdentifier();
+ final var request = new VersionRangeRequest()
+ .setArtifact(
+ new DefaultArtifact(
+ artifactIdentifier.getGroupId(),
+ artifactIdentifier.getArtifactId(),
+ null,
+ "(,]"
+ )
+ )
+ .setRepositories(
+ session.resolve(
+ repositories.stream()
+ .filter(
+ repository -> RepositoryType.PLUGIN == artifactType.getRepositoryType()
+ || RepositoryType.NORMAL == repository.getType()
+ )
+ .map(
+ repository -> MavenUtils.createRemoteRepository(
+ repository.getId(),
+ repository.getUrl()
+ )
+ )
+ .collect(Collectors.toUnmodifiableList())
+ )
+ );
+ final VersionRangeResult result;
+ try {
+ result = session.request(request);
+ } catch (final VersionRangeResolutionException e) {
+ throw new AssertionError(e);
+ }
+ for (final var exception : result.getExceptions()) {
+ logger.warn(exception::getMessage);
+ }
+ return new ArtifactAvailableVersions(
+ artifact,
+ result.getVersions()
+ .stream()
+ .map(Version::toString)
+ .collect(Collectors.toUnmodifiableList())
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/package-info.java
new file mode 100644
index 0000000..195428c
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Artifact version resolving components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/Build.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/Build.java
new file mode 100644
index 0000000..48e5fc8
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/Build.java
@@ -0,0 +1,154 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.Equals;
+import com.github.alexisjehan.javanilla.misc.quality.HashCode;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.javanilla.misc.tuple.Pair;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+
+import java.util.List;
+
+/**
+ * Class that describes a build.
+ * @since 1.0.0
+ */
+public final class Build {
+
+ /**
+ * File.
+ * @since 1.0.0
+ */
+ private final BuildFile file;
+
+ /**
+ * {@link List} of repositories.
+ * @since 1.0.0
+ */
+ private final List repositories;
+
+ /**
+ * {@link List} of artifacts.
+ * @since 1.0.0
+ */
+ private final List> artifacts;
+
+ /**
+ * Constructor.
+ * @param file a file
+ * @param repositories a {@link List} of repositories
+ * @param artifacts a {@link List} of artifacts
+ * @throws NullPointerException if the file, the {@link List} of repositories, any of them, the {@link List} of
+ * artifacts or any of them is {@code null}
+ * @since 1.0.0
+ */
+ public Build(
+ final BuildFile file,
+ final List repositories,
+ final List> artifacts
+ ) {
+ Ensure.notNull("file", file);
+ Ensure.notNullAndNotNullElements("repositories", repositories);
+ Ensure.notNullAndNotNullElements("artifacts", artifacts);
+ this.file = file;
+ this.repositories = List.copyOf(repositories);
+ this.artifacts = List.copyOf(artifacts);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean equals(final Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof Build)) {
+ return false;
+ }
+ final var other = (Build) object;
+ return Equals.equals(file, other.file)
+ && Equals.equals(repositories, other.repositories)
+ && Equals.equals(artifacts, other.artifacts);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.of(
+ HashCode.hashCode(file),
+ HashCode.hashCode(repositories),
+ HashCode.hashCode(artifacts)
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public String toString() {
+ return ToString.of(
+ this,
+ Pair.of("file", ToString.toString(file)),
+ Pair.of("repositories", ToString.toString(repositories)),
+ Pair.of("artifacts", ToString.toString(artifacts))
+ );
+ }
+
+ /**
+ * Get the file.
+ * @return the file
+ * @since 1.0.0
+ */
+ public BuildFile getFile() {
+ return file;
+ }
+
+ /**
+ * Get the {@link List} of repositories.
+ * @return the {@link List} of repositories
+ * @since 1.0.0
+ */
+ public List getRepositories() {
+ return repositories;
+ }
+
+ /**
+ * Get the {@link List} of artifacts.
+ * @return the {@link List} of artifacts
+ * @since 1.0.0
+ */
+ public List> getArtifacts() {
+ return artifacts;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFile.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFile.java
new file mode 100644
index 0000000..fb8cd12
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFile.java
@@ -0,0 +1,125 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.file;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.Equals;
+import com.github.alexisjehan.javanilla.misc.quality.HashCode;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.javanilla.misc.tuple.Pair;
+
+import java.nio.file.Path;
+
+/**
+ * Class that describes a build file.
+ * @since 1.0.0
+ */
+public final class BuildFile {
+
+ /**
+ * Type.
+ * @since 1.0.0
+ */
+ private final BuildFileType type;
+
+ /**
+ * File.
+ * @since 1.0.0
+ */
+ private final Path file;
+
+ /**
+ * Constructor.
+ * @param type a type
+ * @param file a file
+ * @throws NullPointerException if the type or the file is {@code null}
+ * @since 1.0.0
+ */
+ public BuildFile(final BuildFileType type, final Path file) {
+ Ensure.notNull("type", type);
+ Ensure.notNull("file", file);
+ this.type = type;
+ this.file = file;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean equals(final Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof BuildFile)) {
+ return false;
+ }
+ final var other = (BuildFile) object;
+ return Equals.equals(type, other.type)
+ && Equals.equals(file, other.file);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.of(
+ HashCode.hashCode(type),
+ HashCode.hashCode(file)
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public String toString() {
+ return ToString.of(
+ this,
+ Pair.of("type", ToString.toString(type)),
+ Pair.of("file", ToString.toString(file))
+ );
+ }
+
+ /**
+ * Get the type.
+ * @return the type
+ * @since 1.0.0
+ */
+ public BuildFileType getType() {
+ return type;
+ }
+
+ /**
+ * Get the file.
+ * @return the file
+ * @since 1.0.0
+ */
+ public Path getFile() {
+ return file;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileType.java
new file mode 100644
index 0000000..7a72a9b
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileType.java
@@ -0,0 +1,93 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.file;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+/**
+ * Enumeration of build file types.
+ * @since 1.0.0
+ */
+public enum BuildFileType {
+
+ /**
+ * The Maven build file type.
+ * @since 1.0.0
+ */
+ MAVEN("pom.xml"),
+
+ /**
+ * The Gradle Groovy build file type.
+ * @since 1.0.0
+ */
+ GRADLE_GROOVY("build.gradle"),
+
+ /**
+ * The Gradle Kotlin build file type.
+ * @since 1.0.0
+ */
+ GRADLE_KOTLIN("build.gradle.kts");
+
+ /**
+ * File name.
+ * @since 1.0.0
+ */
+ private final String fileName;
+
+ /**
+ * Constructor.
+ * @param fileName a file name
+ * @since 1.0.0
+ */
+ BuildFileType(final String fileName) {
+ this.fileName = fileName;
+ }
+
+ /**
+ * Get the file name.
+ * @return the file name
+ * @since 1.0.0
+ */
+ public final String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Return an {@link Optional} of the value for the given file name.
+ * @param fileName a file name
+ * @return the {@link Optional} of the value
+ * @throws NullPointerException if the file name is {@code null}
+ * @throws IllegalArgumentException if the file name is empty
+ * @since 1.0.0
+ */
+ public static Optional optionalValueOf(final String fileName) {
+ Ensure.notNullAndNotEmpty("fileName", fileName);
+ return Arrays.stream(values())
+ .filter(value -> value.fileName.equals(fileName))
+ .findAny();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/package-info.java
new file mode 100644
index 0000000..7ae114f
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Build file components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.file;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/package-info.java
new file mode 100644
index 0000000..af3c8aa
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Build components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.build;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveException.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveException.java
new file mode 100644
index 0000000..3e40a77
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveException.java
@@ -0,0 +1,60 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+
+/**
+ * Unchecked {@link Exception} related to build resolving.
+ * @since 1.0.0
+ */
+public final class BuildResolveException extends RuntimeException {
+
+ /**
+ * Serial version unique identifier.
+ * @since 1.0.0
+ */
+ private static final long serialVersionUID = 2259143999947820179L;
+
+ /**
+ * Constructor with a message.
+ * @param message a message
+ * @throws NullPointerException if the message is {@code null}
+ * @throws IllegalArgumentException if the message is empty
+ * @since 1.0.0
+ */
+ BuildResolveException(final String message) {
+ super(Ensure.notNullAndNotEmpty("message", message));
+ }
+
+ /**
+ * Constructor with a cause.
+ * @param cause a cause
+ * @throws NullPointerException if the cause is {@code null}
+ * @since 1.0.0
+ */
+ BuildResolveException(final Throwable cause) {
+ super(Ensure.notNull("cause", cause));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolver.java
new file mode 100644
index 0000000..cf6ffa3
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolver.java
@@ -0,0 +1,53 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
+
+import com.github.alexisjehan.mavencheck.core.component.build.Build;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+
+import java.util.Set;
+
+/**
+ * Interface that describes a resolver of the build for a file.
+ * @since 1.0.0
+ */
+public interface BuildResolver {
+
+ /**
+ * Resolve the build for a file.
+ * @param file a file
+ * @return the build
+ * @throws BuildResolveException might occur while resolving the build
+ * @since 1.0.0
+ */
+ Build resolve(final BuildFile file) throws BuildResolveException;
+
+ /**
+ * Get the {@link Set} of file types.
+ * @return the {@link Set} of file types
+ * @since 1.0.0
+ */
+ Set getFileTypes();
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolver.java
new file mode 100644
index 0000000..89ee55b
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolver.java
@@ -0,0 +1,355 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
+
+import com.github.alexisjehan.javanilla.io.Readers;
+import com.github.alexisjehan.javanilla.lang.Strings;
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.GradleArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.build.Build;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import com.github.alexisjehan.mavencheck.core.util.GradleUtils;
+import internal.ExcludeFromJacocoGeneratedReport;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.gradle.tooling.GradleConnectionException;
+import org.gradle.tooling.GradleConnector;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.invoke.MethodHandles;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Class that describes a Gradle resolver of the build for a file.
+ * Note: Compatible starting with Gradle 4.8.
+ * @since 1.0.0
+ */
+public final class GradleBuildResolver implements BuildResolver {
+
+ /**
+ * Initialisation file name.
+ * @since 1.0.0
+ */
+ private static final String INIT_FILE_NAME = "init.gradle";
+
+ /**
+ * {@link Set} of file types.
+ * @since 1.0.0
+ */
+ private static final Set FILE_TYPES = Set.of(
+ BuildFileType.GRADLE_GROOVY,
+ BuildFileType.GRADLE_KOTLIN
+ );
+
+ /**
+ * Logger.
+ * @since 1.0.0
+ */
+ private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass());
+
+ /**
+ * Constructor by default.
+ * @since 1.0.0
+ */
+ public GradleBuildResolver() {
+ // By default
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the file is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ @ExcludeFromJacocoGeneratedReport
+ public Build resolve(final BuildFile file) {
+ Ensure.notNull("file", file);
+ try (final var outputStream = new ByteArrayOutputStream()) {
+ return resolve(file, outputStream);
+ } catch (final IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /**
+ * Resolve the build for a file using an {@link OutputStream}.
+ * @param file a file
+ * @param outputStream an {@link OutputStream}
+ * @return the build
+ * @throws IOException might occur with input/output operations
+ * @throws BuildResolveException might occur while resolving the build
+ * @since 1.0.0
+ */
+ private Build resolve(final BuildFile file, final OutputStream outputStream) throws IOException {
+ logger.info("Resolving the {} build", () -> ToString.toString(file));
+ final var connector = GradleConnector.newConnector()
+ .forProjectDirectory(file.getFile().getParent().toFile());
+ GradleUtils.retrieveOptionalHome()
+ .map(Path::of)
+ .ifPresent(installation -> {
+ logger.debug("Using the {} installation", () -> ToString.toString(installation));
+ connector.useInstallation(installation.toFile());
+ });
+ try (final var connection = connector.connect()) {
+ connection.newBuild()
+ .forTasks("repositories", "dependencies")
+ .withArguments("--init-script=" + getClass().getClassLoader().getResource(INIT_FILE_NAME))
+ .setStandardOutput(outputStream)
+ .run();
+ } catch (final GradleConnectionException e) {
+ throw new BuildResolveException(e);
+ } finally {
+ connector.disconnect();
+ }
+ try (final var reader = Readers.buffered(Readers.of(outputStream.toString()))) {
+ logger.trace("Parsing repositories");
+ final var repositories = parseRepositories(reader);
+ logger.debug("Parsed repositories:");
+ repositories.forEach(
+ repository -> logger.debug("- {}", () -> ToString.toString(repository))
+ );
+
+ logger.trace("Parsing artifacts");
+ final var artifacts = parseArtifacts(reader);
+ logger.debug("Parsed artifacts:");
+ artifacts.forEach(
+ artifact -> logger.debug("- {}", () -> ToString.toString(artifact))
+ );
+
+ logger.trace("Filtering artifacts");
+ final var filteredArtifacts = filter(artifacts);
+ logger.debug("Filtered artifacts:");
+ filteredArtifacts.forEach(
+ filteredArtifact -> logger.debug("- {}", () -> ToString.toString(filteredArtifact))
+ );
+
+ return new Build(file, repositories, filteredArtifacts);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public Set getFileTypes() {
+ return FILE_TYPES;
+ }
+
+ /**
+ * Parse a {@link List} of repositories from a {@link BufferedReader} of the Gradle {@code :repositories}
+ * task.
+ * @param bufferedReader a {@link BufferedReader}
+ * @return the {@link List} of repositories
+ * @throws IOException might occur with input/output operations
+ * @throws NullPointerException if the {@link BufferedReader} is {@code null}
+ * @throws BuildResolveException if the Gradle {@code :repositories} task output is unexpected
+ * @since 1.0.0
+ */
+ static List parseRepositories(final BufferedReader bufferedReader) throws IOException {
+ Ensure.notNull("bufferedReader", bufferedReader);
+ final var repositories = new ArrayList();
+ String line;
+ while (null != (line = bufferedReader.readLine())) {
+ if ("> Task :repositories".equals(line)) {
+ while (null != (line = bufferedReader.readLine())) {
+ if (line.isEmpty()) {
+ break;
+ }
+ if (2 > Strings.frequency(line, ':')) {
+ throw new BuildResolveException("Unexpected Gradle \":repositories\" repository format");
+ }
+ final var parts = Strings.split(':', line, 3);
+ final RepositoryType repositoryType;
+ try {
+ repositoryType = RepositoryType.valueOf(parts.get(0));
+ } catch (final IllegalArgumentException e) {
+ throw new BuildResolveException("Unexpected Gradle \":repositories\" repository type format");
+ }
+ repositories.add(new Repository(repositoryType, parts.get(1), parts.get(2)));
+ }
+ break;
+ }
+ }
+ return repositories;
+ }
+
+ /**
+ * Parse a {@link List} of artifacts from a {@link BufferedReader} of the Gradle {@code :dependencies}
+ * task.
+ * @param bufferedReader a {@link BufferedReader}
+ * @return the {@link List} of artifacts
+ * @throws IOException might occur with input/output operations
+ * @throws NullPointerException if the {@link BufferedReader} is {@code null}
+ * @throws BuildResolveException if the Gradle {@code :dependencies} task output is unexpected
+ * @since 1.0.0
+ */
+ static List> parseArtifacts(final BufferedReader bufferedReader) throws IOException {
+ Ensure.notNull("bufferedReader", bufferedReader);
+ final var artifacts = new ArrayList>();
+ String line;
+ while (null != (line = bufferedReader.readLine())) {
+ if ("> Task :dependencies".equals(line)) {
+ if (!Strings.EMPTY.equals(bufferedReader.readLine())
+ || !"-".repeat(60).equals(bufferedReader.readLine())
+
+ // Until Gradle 6.7: "Root project"
+ // Since Gradle 6.8: "Root project 'foo'"
+ || !Strings.nullToEmpty(bufferedReader.readLine()).startsWith("Root project")
+
+ || !"-".repeat(60).equals(bufferedReader.readLine())
+ || !Strings.EMPTY.equals(bufferedReader.readLine())) {
+ throw new BuildResolveException("Unexpected Gradle \":dependencies\" header format");
+ }
+ while (null != (line = bufferedReader.readLine())) {
+ if ("A web-based, searchable dependency report is available by adding the --scan option."
+ .equals(line)) {
+ break;
+ }
+ final var artifactTypeString = Strings.substringBefore(line, " - ");
+ final var optionalArtifactType = Arrays.stream(GradleArtifactType.values())
+ .filter(artifactType -> artifactType.dependenciesTaskName().equals(artifactTypeString))
+ .findAny();
+ if (optionalArtifactType.isEmpty()) {
+ while (null != (line = bufferedReader.readLine())) {
+ if (line.isEmpty()) {
+ break;
+ }
+ }
+ } else {
+ final var artifactType = optionalArtifactType.orElseThrow();
+ while (null != (line = bufferedReader.readLine())) {
+ if (line.isEmpty()) {
+ break;
+ }
+ if ("No dependencies".equals(line)
+ || line.startsWith("| ")
+ || line.startsWith(" ")) {
+ continue;
+ }
+ if (!line.startsWith("+--- ") && !line.startsWith("\\--- ")) {
+ throw new BuildResolveException("Unexpected Gradle \":dependencies\" artifact format");
+ }
+ final var artifactString = Strings.substringBefore(
+ Strings.substringAfter(
+ line,
+ "--- "
+ ),
+ ' '
+ );
+ final var frequency = Strings.frequency(artifactString, ':');
+ if (1 > frequency || 2 < frequency) {
+ throw new BuildResolveException("Unexpected Gradle \":dependencies\" artifact format");
+ }
+ final var parts = Strings.split(':', artifactString);
+ artifacts.add(
+ new Artifact<>(
+ artifactType,
+ new ArtifactIdentifier(parts.get(0), parts.get(1)),
+ 3 == parts.size()
+ ? parts.get(2)
+ : null
+ )
+ );
+ }
+ }
+ }
+ break;
+ }
+ }
+ return artifacts;
+ }
+
+ /**
+ * Filter a modifiable {@link List} of artifacts, removing redundant duplicates.
+ * @param artifacts a modifiable {@link List} of artifacts
+ * @return the {@link List} of artifacts
+ * @throws NullPointerException if the {@link List} of artifacts or any of them is {@code null}
+ * @since 1.0.0
+ */
+ static List> filter(final List> artifacts) {
+ Ensure.notNullAndNotNullElements("artifacts", artifacts);
+ artifacts.stream()
+ .filter(artifact -> {
+ final var artifactType = artifact.getType();
+ return !artifactType.isClasspath();
+ })
+ .collect(Collectors.toUnmodifiableList())
+ .forEach(artifact -> {
+ artifacts.remove(artifact.with(GradleArtifactType.COMPILE_CLASSPATH));
+ artifacts.remove(artifact.with(GradleArtifactType.RUNTIME_CLASSPATH));
+ artifacts.remove(artifact.with(GradleArtifactType.TEST_COMPILE_CLASSPATH));
+ artifacts.remove(artifact.with(GradleArtifactType.TEST_RUNTIME_CLASSPATH));
+ });
+ artifacts.stream()
+ .filter(artifact -> GradleArtifactType.COMPILE_CLASSPATH == artifact.getType())
+ .collect(Collectors.toUnmodifiableList())
+ .forEach(artifact -> {
+ artifacts.remove(artifact.with(GradleArtifactType.RUNTIME_CLASSPATH));
+ artifacts.remove(artifact.with(GradleArtifactType.TEST_COMPILE_CLASSPATH));
+ artifacts.remove(artifact.with(GradleArtifactType.TEST_RUNTIME_CLASSPATH));
+ });
+ artifacts.stream()
+ .filter(artifact -> GradleArtifactType.RUNTIME_CLASSPATH == artifact.getType())
+ .collect(Collectors.toUnmodifiableList())
+ .forEach(artifact -> {
+ artifacts.remove(artifact.with(GradleArtifactType.TEST_COMPILE_CLASSPATH));
+ artifacts.remove(artifact.with(GradleArtifactType.TEST_RUNTIME_CLASSPATH));
+ });
+ artifacts.stream()
+ .filter(artifact -> GradleArtifactType.TEST_COMPILE_CLASSPATH == artifact.getType())
+ .collect(Collectors.toUnmodifiableList())
+ .forEach(artifact -> artifacts.remove(artifact.with(GradleArtifactType.TEST_RUNTIME_CLASSPATH)));
+ return artifacts.stream()
+ .map(artifact -> {
+ final var artifactType = artifact.getType();
+ if (GradleArtifactType.COMPILE_CLASSPATH == artifactType) {
+ return artifact.with(GradleArtifactType.IMPLEMENTATION);
+ } else if (GradleArtifactType.RUNTIME_CLASSPATH == artifactType) {
+ return artifact.with(GradleArtifactType.RUNTIME_ONLY);
+ } else if (GradleArtifactType.TEST_COMPILE_CLASSPATH == artifactType) {
+ return artifact.with(GradleArtifactType.TEST_IMPLEMENTATION);
+ } else if (GradleArtifactType.TEST_RUNTIME_CLASSPATH == artifactType) {
+ return artifact.with(GradleArtifactType.TEST_RUNTIME_ONLY);
+ } else {
+ return artifact;
+ }
+ })
+ .collect(Collectors.toUnmodifiableList());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolver.java
new file mode 100644
index 0000000..ae4fff6
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolver.java
@@ -0,0 +1,385 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.build.Build;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import com.github.alexisjehan.mavencheck.core.component.session.MavenSession;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Extension;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.ReportPlugin;
+import org.apache.maven.model.building.DefaultModelBuilderFactory;
+import org.apache.maven.model.building.DefaultModelBuildingRequest;
+import org.apache.maven.model.building.ModelBuildingException;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.building.ModelBuildingResult;
+
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Class that describes a Maven resolver of the build for a file.
+ * @since 1.0.0
+ */
+public final class MavenBuildResolver implements BuildResolver {
+
+ /**
+ * {@link Set} of file types.
+ * @since 1.0.0
+ */
+ private static final Set FILE_TYPES = Set.of(BuildFileType.MAVEN);
+
+ /**
+ * Logger.
+ * @since 1.0.0
+ */
+ private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass());
+
+ /**
+ * Maven session.
+ * @since 1.0.0
+ */
+ private final MavenSession session;
+
+ /**
+ * Constructor.
+ * @param session a Maven session
+ * @throws NullPointerException if the Maven session is {@code null}
+ * @since 1.0.0
+ */
+ public MavenBuildResolver(final MavenSession session) {
+ Ensure.notNull("session", session);
+ this.session = session;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the file is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public Build resolve(final BuildFile file) {
+ Ensure.notNull("file", file);
+ logger.info("Resolving the {} build", () -> ToString.toString(file));
+ final var request = new DefaultModelBuildingRequest()
+ .setPomFile(file.getFile().toFile())
+ .setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL)
+ .setProcessPlugins(false)
+ .setSystemProperties(System.getProperties())
+ .setModelResolver(session.getModelResolver())
+ .setModelCache(session.getModelCache());
+ final ModelBuildingResult result;
+ try {
+ result = new DefaultModelBuilderFactory()
+ .newInstance()
+ .build(request);
+ } catch (final ModelBuildingException e) {
+ throw new BuildResolveException(e);
+ }
+ final var effectiveModel = result.getEffectiveModel();
+
+ logger.trace("Extracting repositories");
+ final var repositories = extractRepositories(effectiveModel);
+ logger.debug("Extracted repositories:");
+ repositories.forEach(
+ repository -> logger.debug("- {}", () -> ToString.toString(repository))
+ );
+
+ logger.trace("Extracting effective artifacts");
+ final var effectiveArtifacts = extractArtifacts(effectiveModel);
+ logger.debug("Extracted effective artifacts:");
+ effectiveArtifacts.forEach(
+ effectiveArtifact -> logger.debug("- {}", () -> ToString.toString(effectiveArtifact))
+ );
+
+ logger.trace("Extracting raw artifacts");
+ final var rawArtifacts = extractArtifacts(result.getRawModel());
+ logger.debug("Extracted raw artifacts:");
+ rawArtifacts.forEach(
+ rawArtifact -> logger.debug("- {}", () -> ToString.toString(rawArtifact))
+ );
+
+ logger.trace("Filtering artifacts");
+ final var filteredArtifacts = filter(effectiveArtifacts, rawArtifacts);
+ logger.debug("Filtered artifacts:");
+ filteredArtifacts.forEach(
+ filteredArtifact -> logger.debug("- {}", () -> ToString.toString(filteredArtifact))
+ );
+
+ return new Build(file, repositories, filteredArtifacts);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public Set getFileTypes() {
+ return FILE_TYPES;
+ }
+
+ /**
+ * Extract a {@link List} of repositories from a Maven model.
+ * @param model a Maven model
+ * @return the {@link List} of repositories
+ * @since 1.0.0
+ */
+ private static List extractRepositories(final Model model) {
+ return Stream.concat(
+ model.getRepositories()
+ .stream()
+ .map(repository -> toRepository(RepositoryType.NORMAL, repository)),
+ model.getPluginRepositories()
+ .stream()
+ .map(pluginRepository -> toRepository(RepositoryType.PLUGIN, pluginRepository))
+ ).collect(Collectors.toUnmodifiableList());
+ }
+
+ /**
+ * Extract a {@link List} of artifacts from a Maven model.
+ * @param model a Maven model
+ * @return the {@link List} of artifacts
+ * @since 1.0.0
+ */
+ private static List> extractArtifacts(final Model model) {
+ final var artifacts = new ArrayList>();
+ final var parent = model.getParent();
+ if (null != parent) {
+ artifacts.add(toArtifact(parent));
+ }
+ final var dependencyManagement = model.getDependencyManagement();
+ if (null != dependencyManagement) {
+ for (final var dependency : dependencyManagement.getDependencies()) {
+ artifacts.add(toArtifact(MavenArtifactType.DEPENDENCY_MANAGEMENT_DEPENDENCY, dependency));
+ }
+ }
+ for (final var dependency : model.getDependencies()) {
+ artifacts.add(toArtifact(MavenArtifactType.DEPENDENCY, dependency));
+ }
+ final var build = model.getBuild();
+ if (null != build) {
+ for (final var extension : build.getExtensions()) {
+ artifacts.add(toArtifact(extension));
+ }
+ final var buildPluginManagement = build.getPluginManagement();
+ if (null != buildPluginManagement) {
+ for (final var plugin : buildPluginManagement.getPlugins()) {
+ artifacts.add(toArtifact(MavenArtifactType.BUILD_PLUGIN_MANAGEMENT_PLUGIN, plugin));
+ for (final var dependency : plugin.getDependencies()) {
+ artifacts.add(
+ toArtifact(
+ MavenArtifactType.BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY,
+ dependency
+ )
+ );
+ }
+ }
+ }
+ for (final var plugin : build.getPlugins()) {
+ artifacts.add(toArtifact(MavenArtifactType.BUILD_PLUGIN, plugin));
+ for (final var dependency : plugin.getDependencies()) {
+ artifacts.add(toArtifact(MavenArtifactType.BUILD_PLUGIN_DEPENDENCY, dependency));
+ }
+ }
+ }
+ final var reporting = model.getReporting();
+ if (null != reporting) {
+ for (final var plugin : reporting.getPlugins()) {
+ artifacts.add(toArtifact(MavenArtifactType.REPORTING_PLUGIN, plugin));
+ }
+ }
+ for (final var profile : model.getProfiles()) {
+ final var profileDependencyManagement = profile.getDependencyManagement();
+ if (null != profileDependencyManagement) {
+ for (final var dependency : profileDependencyManagement.getDependencies()) {
+ artifacts.add(toArtifact(MavenArtifactType.PROFILE_DEPENDENCY_MANAGEMENT_DEPENDENCY, dependency));
+ }
+ }
+ for (final var dependency : profile.getDependencies()) {
+ artifacts.add(toArtifact(MavenArtifactType.PROFILE_DEPENDENCY, dependency));
+ }
+ final var profileBuild = profile.getBuild();
+ if (null != profileBuild) {
+ final var profileBuildPluginManagement = profileBuild.getPluginManagement();
+ if (null != profileBuildPluginManagement) {
+ for (final var plugin : profileBuildPluginManagement.getPlugins()) {
+ artifacts.add(toArtifact(MavenArtifactType.PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN, plugin));
+ for (final var dependency : plugin.getDependencies()) {
+ artifacts.add(
+ toArtifact(
+ MavenArtifactType.PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY,
+ dependency
+ )
+ );
+ }
+ }
+ }
+ for (final var plugin : profileBuild.getPlugins()) {
+ artifacts.add(toArtifact(MavenArtifactType.PROFILE_BUILD_PLUGIN, plugin));
+ for (final var dependency : plugin.getDependencies()) {
+ artifacts.add(toArtifact(MavenArtifactType.PROFILE_BUILD_PLUGIN_DEPENDENCY, dependency));
+ }
+ }
+ }
+ final var profileReporting = profile.getReporting();
+ if (null != profileReporting) {
+ for (final var plugin : profileReporting.getPlugins()) {
+ artifacts.add(toArtifact(MavenArtifactType.PROFILE_REPORTING_PLUGIN, plugin));
+ }
+ }
+ }
+ return artifacts;
+ }
+
+ /**
+ * Filter a {@link List} of effective artifacts using a {@link List} of raw artifacts.
+ * @param effectiveArtifacts a {@link List} of effective artifacts
+ * @param rawArtifacts a {@link List} of raw artifacts
+ * @return the {@link List} of artifacts
+ * @since 1.0.0
+ */
+ private static List> filter(
+ final List> effectiveArtifacts,
+ final List> rawArtifacts
+ ) {
+ return effectiveArtifacts.stream()
+ .filter(effectiveArtifact -> {
+ final var effectiveArtifactType = effectiveArtifact.getType();
+ final var effectiveArtifactIdentifier = effectiveArtifact.getIdentifier();
+ return rawArtifacts.stream()
+ .anyMatch(
+ rawArtifact -> rawArtifact.getType() == effectiveArtifactType
+ && rawArtifact.getIdentifier().equals(effectiveArtifactIdentifier)
+ );
+ })
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ /**
+ * Create a repository from a type and a Maven repository.
+ * @param type a type
+ * @param repository a Maven repository
+ * @return the repository
+ * @since 1.0.0
+ */
+ private static Repository toRepository(
+ final RepositoryType type,
+ final org.apache.maven.model.Repository repository
+ ) {
+ return new Repository(type, repository.getId(), repository.getUrl());
+ }
+
+ /**
+ * Create an artifact from a Maven parent.
+ * @param parent a Maven parent
+ * @return the artifact
+ * @since 1.0.0
+ */
+ private static Artifact toArtifact(final Parent parent) {
+ return new Artifact<>(
+ MavenArtifactType.PARENT,
+ new ArtifactIdentifier(parent.getGroupId(), parent.getArtifactId()),
+ parent.getVersion()
+ );
+ }
+
+ /**
+ * Create an artifact from a type and a Maven dependency.
+ * @param type a type
+ * @param dependency a Maven dependency
+ * @return the artifact
+ * @since 1.0.0
+ */
+ private static Artifact toArtifact(final MavenArtifactType type, final Dependency dependency) {
+ return new Artifact<>(
+ type,
+ new ArtifactIdentifier(dependency.getGroupId(), dependency.getArtifactId()),
+ dependency.getVersion()
+ );
+ }
+
+ /**
+ * Create an artifact from a Maven extension.
+ * @param extension a Maven extension
+ * @return the artifact
+ * @since 1.0.0
+ */
+ private static Artifact toArtifact(final Extension extension) {
+ return new Artifact<>(
+ MavenArtifactType.BUILD_EXTENSION,
+ new ArtifactIdentifier(extension.getGroupId(), extension.getArtifactId()),
+ extension.getVersion()
+ );
+ }
+
+ /**
+ * Create an artifact from a type and a Maven plugin.
+ * @param type a type
+ * @param plugin a Maven plugin
+ * @return the artifact
+ * @since 1.0.0
+ */
+ private static Artifact toArtifact(final MavenArtifactType type, final Plugin plugin) {
+ return new Artifact<>(
+ type,
+ new ArtifactIdentifier(plugin.getGroupId(), plugin.getArtifactId()),
+ plugin.getVersion()
+ );
+ }
+
+ /**
+ * Create an artifact from a type and a Maven report plugin.
+ * @param type a type
+ * @param reportPlugin a Maven report plugin
+ * @return the artifact
+ * @since 1.0.0
+ */
+ private static Artifact toArtifact(
+ final MavenArtifactType type,
+ final ReportPlugin reportPlugin
+ ) {
+ return new Artifact<>(
+ type,
+ new ArtifactIdentifier(reportPlugin.getGroupId(), reportPlugin.getArtifactId()),
+ reportPlugin.getVersion()
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/package-info.java
new file mode 100644
index 0000000..0013bc0
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Build resolving components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilter.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilter.java
new file mode 100644
index 0000000..c5f7676
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilter.java
@@ -0,0 +1,113 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+
+/**
+ * Interface that describes an artifact filter.
+ * @since 1.0.0
+ */
+public interface ArtifactFilter {
+
+ /**
+ * Artifact filter that reject all artifacts.
+ * @since 1.0.0
+ */
+ ArtifactFilter ALL = new ArtifactFilter() {
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean accept(final Artifact> artifact) {
+ Ensure.notNull("artifact", artifact);
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact or the update version is {@code null}
+ * @throws IllegalArgumentException if the update version is empty
+ * @since 1.0.0
+ */
+ @Override
+ public boolean accept(final Artifact> artifact, final String updateVersion) {
+ Ensure.notNull("artifact", artifact);
+ Ensure.notNullAndNotEmpty("updateVersion", updateVersion);
+ return false;
+ }
+ };
+
+ /**
+ * Artifact filter that accept all artifacts.
+ * @since 1.0.0
+ */
+ ArtifactFilter NONE = new ArtifactFilter() {
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean accept(final Artifact> artifact) {
+ Ensure.notNull("artifact", artifact);
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact or the update version is {@code null}
+ * @throws IllegalArgumentException if the update version is empty
+ * @since 1.0.0
+ */
+ @Override
+ public boolean accept(final Artifact> artifact, final String updateVersion) {
+ Ensure.notNull("artifact", artifact);
+ Ensure.notNullAndNotEmpty("updateVersion", updateVersion);
+ return true;
+ }
+ };
+
+ /**
+ * Test if an artifact is accepted.
+ * @param artifact an artifact
+ * @return {@code true} if the artifact is accepted
+ * @since 1.0.0
+ */
+ boolean accept(final Artifact> artifact);
+
+ /**
+ * Test if an artifact and an update version are accepted.
+ * @param artifact an artifact
+ * @param updateVersion an update version
+ * @return {@code true} if the artifact and the update version are accepted
+ * @since 1.0.0
+ */
+ boolean accept(final Artifact> artifact, final String updateVersion);
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilter.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilter.java
new file mode 100644
index 0000000..ad59e4e
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilter.java
@@ -0,0 +1,84 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Class that describes a composite artifact filter.
+ * @since 1.0.0
+ */
+public final class CompositeArtifactFilter implements ArtifactFilter {
+
+ /**
+ * {@link Set} of artifact filters.
+ * @since 1.0.0
+ */
+ private final Set filters;
+
+ /**
+ * Constructor.
+ * @param filters an array of artifact filters
+ * @throws NullPointerException if the array of artifacts or any of them is {@code null}
+ * @throws IllegalArgumentException if the array of artifacts is empty
+ * @since 1.0.0
+ */
+ public CompositeArtifactFilter(final ArtifactFilter... filters) {
+ Ensure.notNullAndNotEmpty("filters", filters);
+ Ensure.notNullAndNotNullElements("filters", filters);
+ this.filters = Arrays.stream(filters)
+ .collect(Collectors.toUnmodifiableSet());
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean accept(final Artifact> artifact) {
+ Ensure.notNull("artifact", artifact);
+ return filters.stream()
+ .allMatch(filter -> filter.accept(artifact));
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact or the update version is {@code null}
+ * @throws IllegalArgumentException if the update version is empty
+ * @since 1.0.0
+ */
+ @Override
+ public boolean accept(final Artifact> artifact, final String updateVersion) {
+ Ensure.notNull("artifact", artifact);
+ Ensure.notNullAndNotEmpty("updateVersion", updateVersion);
+ return filters.stream()
+ .allMatch(filter -> filter.accept(artifact, updateVersion));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/package-info.java
new file mode 100644
index 0000000..f0fe206
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Artifact filtering components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseException.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseException.java
new file mode 100644
index 0000000..065bf56
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseException.java
@@ -0,0 +1,161 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+
+import java.nio.file.Path;
+import java.util.Optional;
+
+/**
+ * Unchecked {@link Exception} related to artifact filter parsing.
+ * @since 1.0.0
+ */
+public final class ArtifactFilterParseException extends RuntimeException {
+
+ /**
+ * Serial version unique identifier.
+ * @since 1.0.0
+ */
+ private static final long serialVersionUID = 8647765091802310213L;
+
+ /**
+ * Reason.
+ * @since 1.0.0
+ */
+ private final String reason;
+
+ /**
+ * Line.
+ * @since 1.0.0
+ */
+ private final String line;
+
+ /**
+ * Line number.
+ * @since 1.0.0
+ */
+ private final long lineNumber;
+
+ /**
+ * File.
+ * @since 1.0.0
+ */
+ private final transient Path file;
+
+ /**
+ * Constructor without a file.
+ * @param reason a reason
+ * @param line a line
+ * @param lineNumber a line number
+ * @throws NullPointerException if the reason or the line is {@code null}
+ * @throws IllegalArgumentException if the reason or the line is empty or if the line number is lower than or equal
+ * to 0
+ * @since 1.0.0
+ */
+ ArtifactFilterParseException(final String reason, final String line, final long lineNumber) {
+ this(reason, line, lineNumber, null);
+ }
+
+ /**
+ * Constructor with a file.
+ * @param reason a reason
+ * @param line a line
+ * @param lineNumber a line number
+ * @param file a file or {@code null}
+ * @throws NullPointerException if the reason or the line is {@code null}
+ * @throws IllegalArgumentException if the reason or the line is empty or if the line number is lower than or equal
+ * to 0
+ * @since 1.0.0
+ */
+ private ArtifactFilterParseException(
+ final String reason,
+ final String line,
+ final long lineNumber,
+ final Path file
+ ) {
+ super(
+ Ensure.notNullAndNotEmpty("reason", reason)
+ + ": "
+ + ToString.toString(Ensure.notNullAndNotEmpty("line", line))
+ + " ("
+ + "at line " + Ensure.greaterThan("lineNumber", lineNumber, 0)
+ + (null != file ? " of the " + ToString.toString(file) + " file" : "")
+ + ")"
+ );
+ this.reason = reason;
+ this.line = line;
+ this.lineNumber = lineNumber;
+ this.file = file;
+ }
+
+ /**
+ * Return a copy of the current exception with the given file.
+ * @param file a file
+ * @return the copy of the current exception
+ * @throws NullPointerException if the file is {@code null}
+ * @since 1.0.0
+ */
+ public ArtifactFilterParseException with(final Path file) {
+ Ensure.notNull("file", file);
+ return new ArtifactFilterParseException(reason, line, lineNumber, file);
+ }
+
+ /**
+ * Get the reason.
+ * @return the reason
+ * @since 1.0.0
+ */
+ public String getReason() {
+ return reason;
+ }
+
+ /**
+ * Get the line.
+ * @return the line
+ * @since 1.0.0
+ */
+ public String getLine() {
+ return line;
+ }
+
+ /**
+ * Get the line number.
+ * @return the line number
+ * @since 1.0.0
+ */
+ public long getLineNumber() {
+ return lineNumber;
+ }
+
+ /**
+ * Get an {@link Optional} of the file.
+ * @return the {@link Optional} of the file
+ * @since 1.0.0
+ */
+ public Optional getOptionalFile() {
+ return Optional.ofNullable(file);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParser.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParser.java
new file mode 100644
index 0000000..7b34d9f
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParser.java
@@ -0,0 +1,202 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser;
+
+import com.github.alexisjehan.javanilla.io.Readers;
+import com.github.alexisjehan.javanilla.lang.Strings;
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.filter.artifact.ArtifactFilter;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.lang.invoke.MethodHandles;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * Class that describes an artifact filter parser.
+ * @since 1.0.0
+ */
+public final class ArtifactFilterParser {
+
+ /**
+ * Start of a comment line.
+ * @since 1.0.0
+ */
+ private static final char COMMENT_START = '#';
+
+ /**
+ * Separator.
+ * @since 1.0.0
+ */
+ private static final char SEPARATOR = ':';
+
+ /**
+ * Single character wildcard.
+ * @since 1.0.0
+ */
+ private static final char WILDCARD_SINGLE = '?';
+
+ /**
+ * Any characters wildcard.
+ * @since 1.0.0
+ */
+ private static final char WILDCARD_ANY = '*';
+
+ /**
+ * Logger.
+ * @since 1.0.0
+ */
+ private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass());
+
+ /**
+ * Constructor not available.
+ * @since 1.0.0
+ */
+ private ArtifactFilterParser() {
+ // Not available
+ }
+
+ /**
+ * Parse an artifact filter from the given ignore file.
+ * @param ignoreFile an ignore file
+ * @return the artifact filter
+ * @throws IOException might occur with input/output operations
+ * @throws NullPointerException if the ignore file is {@code null}
+ * @throws IllegalArgumentException if the ignore file does not exist
+ * @throws ArtifactFilterParseException if the content is unexpected
+ * @since 1.0.0
+ */
+ public static ArtifactFilter parse(final Path ignoreFile) throws IOException {
+ Ensure.notNullAndFile("ignoreFile", ignoreFile);
+ logger.info("Parsing the {} ignore file", () -> ToString.toString(ignoreFile));
+ try (final var reader = Readers.of(ignoreFile)) {
+ return parse(reader);
+ } catch (final ArtifactFilterParseException e) {
+ throw e.with(ignoreFile);
+ }
+ }
+
+ /**
+ * Parse an artifact filter from the given {@link Reader}.
+ * @param reader a {@link Reader}
+ * @return the artifact filter
+ * @throws IOException might occur with input/output operations
+ * @throws NullPointerException if the {@link Reader} is {@code null}
+ * @throws ArtifactFilterParseException if the content is unexpected
+ * @since 1.0.0
+ */
+ static ArtifactFilter parse(final Reader reader) throws IOException {
+ Ensure.notNull("reader", reader);
+ final var identifiers = new HashSet();
+ final var identifiersVersions = new HashMap>();
+ try (final var bufferedReader = Readers.buffered(reader)) {
+ String line;
+ long lineNumber = 1;
+ while (null != (line = bufferedReader.readLine())) {
+ line = Strings.substringBefore(line, COMMENT_START).trim();
+ if (line.isEmpty()) {
+ continue;
+ }
+ final var frequency = Strings.frequency(line, SEPARATOR);
+ if (1 != frequency && 2 != frequency) {
+ throw new ArtifactFilterParseException("Unexpected format", line, lineNumber);
+ }
+ final var parts = Strings.split(SEPARATOR, line);
+ final var groupId = parts.get(0);
+ if (groupId.isEmpty()) {
+ throw new ArtifactFilterParseException("Unexpected format, empty groupId", line, lineNumber);
+ }
+ final var artifactId = parts.get(1);
+ if (artifactId.isEmpty()) {
+ throw new ArtifactFilterParseException("Unexpected format, empty artifactId", line, lineNumber);
+ }
+ final var identifier = new ArtifactIdentifier(groupId, artifactId);
+ if (2 == parts.size()) {
+ logger.debug("Ignoring the {} artifact identifier", () -> ToString.toString(identifier));
+ identifiers.add(identifier);
+ } else {
+ final var versionExpression = parts.get(2);
+ if (versionExpression.isEmpty()) {
+ throw new ArtifactFilterParseException(
+ "Unexpected format, empty version expression",
+ line,
+ lineNumber
+ );
+ }
+ logger.debug(
+ "Ignoring the {} artifact identifier with {} version expression",
+ () -> ToString.toString(identifier),
+ () -> ToString.toString(versionExpression)
+ );
+ identifiersVersions.computeIfAbsent(identifier, key -> new HashSet<>()).add(
+ Pattern.compile(
+ "^" + Pattern.quote(versionExpression)
+ .replace(String.valueOf(WILDCARD_SINGLE), "\\E.\\Q")
+ .replace(String.valueOf(WILDCARD_ANY), "\\E.*\\Q") + "$",
+ Pattern.CASE_INSENSITIVE
+ )
+ );
+ }
+ ++lineNumber;
+ }
+ }
+ return new ArtifactFilter() {
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean accept(final Artifact> artifact) {
+ Ensure.notNull("artifact", artifact);
+ return !identifiers.contains(artifact.getIdentifier());
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact or the update version is {@code null}
+ * @throws IllegalArgumentException if the update version is empty
+ * @since 1.0.0
+ */
+ @Override
+ public boolean accept(final Artifact> artifact, final String updateVersion) {
+ Ensure.notNull("artifact", artifact);
+ Ensure.notNullAndNotEmpty("updateVersion", updateVersion);
+ final var identifierVersions = identifiersVersions.get(artifact.getIdentifier());
+ return null == identifierVersions
+ || identifierVersions.stream().noneMatch(pattern -> pattern.matcher(updateVersion).matches());
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/package-info.java
new file mode 100644
index 0000000..fda8eaa
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Artifact filter parsing components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/package-info.java
new file mode 100644
index 0000000..89784b3
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Filtering components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilter.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilter.java
new file mode 100644
index 0000000..e6a370f
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilter.java
@@ -0,0 +1,51 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+
+/**
+ * Interface that describes a version filter.
+ * @since 1.0.0
+ */
+@FunctionalInterface
+public interface VersionFilter {
+
+ /**
+ * Version filter that reject snapshots.
+ * @since 1.0.0
+ */
+ VersionFilter SNAPSHOT = version -> {
+ Ensure.notNullAndNotEmpty("version", version);
+ return version.endsWith("-SNAPSHOT");
+ };
+
+ /**
+ * Test if a version is accepted.
+ * @param version a version
+ * @return {@code true} if the version is accepted
+ * @since 1.0.0
+ */
+ boolean accept(final String version);
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactory.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactory.java
new file mode 100644
index 0000000..a9b2a44
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactory.java
@@ -0,0 +1,77 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version.factory;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.mavencheck.core.component.filter.version.VersionFilter;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Class that describes a composite version filter factory.
+ * @since 1.0.0
+ */
+public final class CompositeVersionFilterFactory implements VersionFilterFactory {
+
+ /**
+ * {@link Set} of version filter factories.
+ * @since 1.0.0
+ */
+ private final Set factories;
+
+ /**
+ * Constructor.
+ * @param factories an array of factories
+ * @throws NullPointerException if the array of factories or any of them is {@code null}
+ * @throws IllegalArgumentException if the array of factories is empty
+ * @since 1.0.0
+ */
+ public CompositeVersionFilterFactory(final VersionFilterFactory... factories) {
+ Ensure.notNullAndNotEmpty("factories", factories);
+ Ensure.notNullAndNotNullElements("factories", factories);
+ this.factories = Arrays.stream(factories)
+ .collect(Collectors.toUnmodifiableSet());
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact version is {@code null}
+ * @throws IllegalArgumentException if the artifact version is empty
+ * @since 1.0.0
+ */
+ @Override
+ public VersionFilter create(final String artifactVersion) {
+ Ensure.notNullAndNotEmpty("artifactVersion", artifactVersion);
+ final var filters = factories.stream()
+ .map(factory -> factory.create(artifactVersion))
+ .collect(Collectors.toUnmodifiableSet());
+ return version -> {
+ Ensure.notNullAndNotEmpty("version", version);
+ return filters.stream()
+ .allMatch(filter -> filter.accept(version));
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactory.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactory.java
new file mode 100644
index 0000000..db44895
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactory.java
@@ -0,0 +1,83 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version.factory;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.mavencheck.core.component.filter.version.VersionFilter;
+
+import java.util.regex.Pattern;
+
+/**
+ * Enumeration of a singleton qualifier version filter factory.
+ * @since 1.0.0
+ */
+public enum QualifierVersionFilterFactory implements VersionFilterFactory {
+
+ /**
+ * Singleton instance.
+ * @since 1.0.0
+ */
+ INSTANCE;
+
+ /**
+ * Pattern to extract the qualifier from a version.
+ * @since 1.0.0
+ */
+ private static final Pattern PATTERN = Pattern.compile(
+ "^.*[.\\-]?([a-z]+)[.\\-]?\\d*$",
+ Pattern.CASE_INSENSITIVE
+ );
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact version is {@code null}
+ * @throws IllegalArgumentException if the artifact version is empty
+ * @since 1.0.0
+ */
+ @Override
+ public VersionFilter create(final String artifactVersion) {
+ Ensure.notNullAndNotEmpty("artifactVersion", artifactVersion);
+ final var artifactVersionQualifier = extractQualifier(artifactVersion);
+ return version -> {
+ Ensure.notNullAndNotEmpty("version", version);
+ final var versionQualifier = extractQualifier(version);
+ return null == versionQualifier
+ || null == artifactVersionQualifier
+ || versionQualifier.equalsIgnoreCase(artifactVersionQualifier);
+ };
+ }
+
+ /**
+ * Extract the qualifier from a version.
+ * @param version a version
+ * @return the qualifier
+ * @since 1.0.0
+ */
+ private static String extractQualifier(final String version) {
+ final var matcher = PATTERN.matcher(version);
+ return matcher.matches()
+ ? matcher.group(1)
+ : null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactory.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactory.java
new file mode 100644
index 0000000..ba10f6e
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactory.java
@@ -0,0 +1,66 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version.factory;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.mavencheck.core.component.filter.version.VersionFilter;
+
+import java.util.regex.Pattern;
+
+/**
+ * Enumeration of a singleton release version filter factory.
+ * @since 1.0.0
+ */
+public enum ReleaseVersionFilterFactory implements VersionFilterFactory {
+
+ /**
+ * Singleton instance.
+ * @since 1.0.0
+ */
+ INSTANCE;
+
+ /**
+ * Pattern to match pre-release versions.
+ * @since 1.0.0
+ */
+ private static final Pattern PATTERN = Pattern.compile(
+ "^.*[.\\-]?(?:alpha|a|beta|b|milestone|m|rc|cr|snapshot)[.\\-]?\\d*$",
+ Pattern.CASE_INSENSITIVE
+ );
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the artifact version is {@code null}
+ * @throws IllegalArgumentException if the artifact version is empty
+ * @since 1.0.0
+ */
+ @Override
+ public VersionFilter create(final String artifactVersion) {
+ Ensure.notNullAndNotEmpty("artifactVersion", artifactVersion);
+ return version -> {
+ Ensure.notNullAndNotEmpty("version", version);
+ return !PATTERN.matcher(version).matches();
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/VersionFilterFactory.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/VersionFilterFactory.java
new file mode 100644
index 0000000..d700d9e
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/VersionFilterFactory.java
@@ -0,0 +1,42 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version.factory;
+
+import com.github.alexisjehan.mavencheck.core.component.filter.version.VersionFilter;
+
+/**
+ * Interface that describes a version filter factory.
+ * @since 1.0.0
+ */
+@FunctionalInterface
+public interface VersionFilterFactory {
+
+ /**
+ * Create a version filter for the given artifact version.
+ * @param artifactVersion an artifact version
+ * @return the version filter
+ * @since 1.0.0
+ */
+ VersionFilter create(final String artifactVersion);
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/package-info.java
new file mode 100644
index 0000000..f825c87
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Version filtering factory components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version.factory;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/package-info.java
new file mode 100644
index 0000000..29345e7
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Version filtering components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/package-info.java
new file mode 100644
index 0000000..b2d84a7
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/Repository.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/Repository.java
new file mode 100644
index 0000000..9ac015a
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/Repository.java
@@ -0,0 +1,145 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.repository;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.Equals;
+import com.github.alexisjehan.javanilla.misc.quality.HashCode;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.javanilla.misc.tuple.Pair;
+
+/**
+ * Class that describes a repository.
+ * @since 1.0.0
+ */
+public final class Repository {
+
+ /**
+ * Type.
+ * @since 1.0.0
+ */
+ private final RepositoryType type;
+
+ /**
+ * Identifier.
+ * @since 1.0.0
+ */
+ private final String id;
+
+ /**
+ * URL.
+ * @since 1.0.0
+ */
+ private final String url;
+
+ /**
+ * Constructor.
+ * @param type a type
+ * @param id an identifier
+ * @param url an URL
+ * @throws NullPointerException if the type, the identifier or the URL is {@code null}
+ * @throws IllegalArgumentException if the identifier or the URL is empty
+ * @since 1.0.0
+ */
+ public Repository(final RepositoryType type, final String id, final String url) {
+ Ensure.notNull("type", type);
+ Ensure.notNullAndNotEmpty("id", id);
+ Ensure.notNullAndNotEmpty("url", url);
+ this.type = type;
+ this.id = id;
+ this.url = url;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean equals(final Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof Repository)) {
+ return false;
+ }
+ final var other = (Repository) object;
+ return Equals.equals(type, other.type)
+ && Equals.equals(id, other.id)
+ && Equals.equals(url, other.url);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.of(
+ HashCode.hashCode(type),
+ HashCode.hashCode(id),
+ HashCode.hashCode(url)
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public String toString() {
+ return ToString.of(
+ this,
+ Pair.of("type", ToString.toString(type)),
+ Pair.of("id", ToString.toString(id)),
+ Pair.of("url", ToString.toString(url))
+ );
+ }
+
+ /**
+ * Get the type.
+ * @return the type
+ * @since 1.0.0
+ */
+ public RepositoryType getType() {
+ return type;
+ }
+
+ /**
+ * Get the identifier.
+ * @return the identifier
+ * @since 1.0.0
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Get the URL.
+ * @return the URL
+ * @since 1.0.0
+ */
+ public String getUrl() {
+ return url;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryType.java
new file mode 100644
index 0000000..a76459b
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryType.java
@@ -0,0 +1,43 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.repository;
+
+/**
+ * Enumeration of repository types.
+ * @since 1.0.0
+ */
+public enum RepositoryType {
+
+ /**
+ * Normal repositories.
+ * @since 1.0.0
+ */
+ NORMAL,
+
+ /**
+ * Plugin repositories.
+ * @since 1.0.0
+ */
+ PLUGIN
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/package-info.java
new file mode 100644
index 0000000..148a9b6
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Repository components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.repository;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSession.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSession.java
new file mode 100644
index 0000000..da63b4a
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSession.java
@@ -0,0 +1,156 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.session;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.util.Lists;
+import com.github.alexisjehan.mavencheck.core.util.MavenUtils;
+import org.apache.maven.model.building.ModelCache;
+import org.apache.maven.model.resolution.ModelResolver;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectModelResolver;
+import org.apache.maven.project.PublicReactorModelCache;
+import org.apache.maven.project.PublicReactorModelPool;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.VersionRangeRequest;
+import org.eclipse.aether.resolution.VersionRangeResolutionException;
+import org.eclipse.aether.resolution.VersionRangeResult;
+
+import java.util.List;
+
+/**
+ * Class that describes a Maven session.
+ * @since 1.0.0
+ */
+public final class MavenSession {
+
+ /**
+ * Repository system.
+ * @since 1.0.0
+ */
+ private final RepositorySystem repositorySystem;
+
+ /**
+ * Repository system session.
+ * @since 1.0.0
+ */
+ private final RepositorySystemSession repositorySystemSession;
+
+ /**
+ * {@link List} of remote repositories.
+ * @since 1.0.0
+ */
+ private final List remoteRepositories;
+
+ /**
+ * Model resolver.
+ * @since 1.0.0
+ */
+ private final ModelResolver modelResolver;
+
+ /**
+ * Model cache.
+ * @since 1.0.0
+ */
+ private final ModelCache modelCache;
+
+ /**
+ * Constructor.
+ * @throws MavenSessionException might occur while resolving Maven settings
+ * @since 1.0.0
+ */
+ public MavenSession() {
+ final var serviceLocator = MavenUtils.makeServiceLocator();
+ repositorySystem = MavenUtils.makeRepositorySystem(serviceLocator);
+ final Settings settings;
+ try {
+ settings = MavenUtils.makeSettings();
+ } catch (final SettingsBuildingException e) {
+ throw new MavenSessionException(e);
+ }
+ final var decryptedSettings = MavenUtils.makeDecryptedSettings(settings);
+ repositorySystemSession = MavenUtils.makeRepositorySystemSession(settings, decryptedSettings, repositorySystem);
+ remoteRepositories = MavenUtils.makeRemoteRepositories(settings);
+ modelResolver = new ProjectModelResolver(
+ repositorySystemSession,
+ null,
+ repositorySystem,
+ MavenUtils.makeRemoteRepositoryManager(serviceLocator),
+ remoteRepositories,
+ ProjectBuildingRequest.RepositoryMerging.POM_DOMINANT,
+ new PublicReactorModelPool()
+ );
+ modelCache = new PublicReactorModelCache();
+ }
+
+ /**
+ * Resolve remote repositories using the repository system session.
+ * @param remoteRepositories a {@link List} of remote repositories
+ * @return the {@link List} of remote repositories
+ * @throws NullPointerException if the {@link List} of remote repositories or any of them is {@code null}
+ * @since 1.0.0
+ */
+ public List resolve(final List remoteRepositories) {
+ Ensure.notNullAndNotNullElements("remoteRepositories", remoteRepositories);
+ return repositorySystem.newResolutionRepositories(
+ repositorySystemSession,
+ Lists.concat(this.remoteRepositories, remoteRepositories)
+ );
+ }
+
+ /**
+ * Request a version range using the repository system session.
+ * @param request a request
+ * @return the result
+ * @throws VersionRangeResolutionException might occur while requesting an invalid version range
+ * @throws NullPointerException if the request is {@code null}
+ * @since 1.0.0
+ */
+ public VersionRangeResult request(final VersionRangeRequest request) throws VersionRangeResolutionException {
+ Ensure.notNull("request", request);
+ return repositorySystem.resolveVersionRange(repositorySystemSession, request);
+ }
+
+ /**
+ * Get the model resolver.
+ * @return the model resolver
+ * @since 1.0.0
+ */
+ public ModelResolver getModelResolver() {
+ return modelResolver;
+ }
+
+ /**
+ * Get the model cache.
+ * @return the model cache
+ * @since 1.0.0
+ */
+ public ModelCache getModelCache() {
+ return modelCache;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionException.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionException.java
new file mode 100644
index 0000000..a14d3db
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionException.java
@@ -0,0 +1,49 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.session;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+
+/**
+ * Unchecked {@link Exception} related to Maven sessions.
+ * @since 1.0.0
+ */
+public final class MavenSessionException extends RuntimeException {
+
+ /**
+ * Serial version unique identifier.
+ * @since 1.0.0
+ */
+ private static final long serialVersionUID = -2024028478245530224L;
+
+ /**
+ * Constructor.
+ * @param cause a cause
+ * @throws NullPointerException if the cause is {@code null}
+ * @since 1.0.0
+ */
+ MavenSessionException(final Throwable cause) {
+ super(Ensure.notNull("cause", cause));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/package-info.java
new file mode 100644
index 0000000..e83b315
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Session components.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.component.session;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/package-info.java
new file mode 100644
index 0000000..2745eba
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Core package.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListener.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListener.java
new file mode 100644
index 0000000..0eeee9c
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListener.java
@@ -0,0 +1,330 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.eclipse.aether.RepositoryEvent;
+import org.eclipse.aether.RepositoryListener;
+
+import java.lang.invoke.MethodHandles;
+
+/**
+ * Class that describes a Maven console repository listener.
+ * @since 1.0.0
+ */
+final class ConsoleRepositoryListener implements RepositoryListener {
+
+ /**
+ * Logger.
+ * @since 1.0.0
+ */
+ private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass());
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactDescriptorInvalid(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Invalid {} artifact descriptor: {}",
+ () -> ToString.toString(event.getArtifact()),
+ () -> ToString.toString(event.getException())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactDescriptorMissing(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Missing {} artifact descriptor",
+ () -> ToString.toString(event.getArtifact())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactResolving(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Resolving {} artifact from {}",
+ () -> ToString.toString(event.getArtifact()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactResolved(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Resolved {} artifact from {}",
+ () -> ToString.toString(event.getArtifact()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactDownloading(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Downloading {} artifact from {}",
+ () -> ToString.toString(event.getArtifact()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactDownloaded(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Downloaded {} artifact from {}",
+ () -> ToString.toString(event.getArtifact()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactInstalling(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Installing {} artifact to {}",
+ () -> ToString.toString(event.getArtifact()),
+ () -> ToString.toString(event.getFile())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactInstalled(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Installed {} artifact to {}",
+ () -> ToString.toString(event.getArtifact()),
+ () -> ToString.toString(event.getFile())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactDeploying(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Deploying {} artifact to {}",
+ () -> ToString.toString(event.getArtifact()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void artifactDeployed(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Deployed {} artifact to {}",
+ () -> ToString.toString(event.getArtifact()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void metadataInvalid(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Invalid {} metadata: {}",
+ () -> ToString.toString(event.getMetadata()),
+ () -> ToString.toString(event.getException())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void metadataResolving(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Resolving {} metadata from {}",
+ () -> ToString.toString(event.getMetadata()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void metadataResolved(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Resolved {} metadata from {}",
+ () -> ToString.toString(event.getMetadata()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void metadataDownloading(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Downloading {} metadata from {}",
+ () -> ToString.toString(event.getMetadata()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void metadataDownloaded(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Downloaded {} metadata from {}",
+ () -> ToString.toString(event.getMetadata()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void metadataInstalling(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Installing {} metadata to {}",
+ () -> ToString.toString(event.getMetadata()),
+ () -> ToString.toString(event.getFile())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void metadataInstalled(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Installed {} metadata to {}",
+ () -> ToString.toString(event.getMetadata()),
+ () -> ToString.toString(event.getFile())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void metadataDeploying(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Deploying {} metadata to {}",
+ () -> ToString.toString(event.getMetadata()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the event is {@code null}
+ * @since 1.0.0
+ */
+ @Override
+ public void metadataDeployed(final RepositoryEvent event) {
+ Ensure.notNull("event", event);
+ logger.debug(
+ "Deployed {} metadata to {}",
+ () -> ToString.toString(event.getMetadata()),
+ () -> ToString.toString(event.getRepository())
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettings.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettings.java
new file mode 100644
index 0000000..e6f9399
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettings.java
@@ -0,0 +1,128 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import com.github.alexisjehan.javanilla.misc.quality.Equals;
+import com.github.alexisjehan.javanilla.misc.quality.HashCode;
+import com.github.alexisjehan.javanilla.misc.quality.ToString;
+import com.github.alexisjehan.javanilla.misc.tuple.Pair;
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
+
+import java.util.List;
+
+/**
+ * Class that describes Maven decrypted settings.
+ * @since 1.0.0
+ */
+final class DecryptedSettings {
+
+ /**
+ * {@link List} of proxies.
+ * @since 1.0.0
+ */
+ private final List proxies;
+
+ /**
+ * {@link List} of servers.
+ * @since 1.0.0
+ */
+ private final List servers;
+
+ /**
+ * Constructor.
+ * @param proxies a {@link List} of proxies
+ * @param servers a {@link List} of servers
+ * @throws NullPointerException if the {@link List} of proxies, any of them, the {@link List} of servers or any of
+ * them is {@code null}
+ * @since 1.0.0
+ */
+ DecryptedSettings(final List proxies, final List servers) {
+ Ensure.notNullAndNotNullElements("proxies", proxies);
+ Ensure.notNullAndNotNullElements("servers", servers);
+ this.proxies = List.copyOf(proxies);
+ this.servers = List.copyOf(servers);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public boolean equals(final Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof DecryptedSettings)) {
+ return false;
+ }
+ final var other = (DecryptedSettings) object;
+ return Equals.equals(proxies, other.proxies)
+ && Equals.equals(servers, other.servers);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.of(
+ HashCode.hashCode(proxies),
+ HashCode.hashCode(servers)
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0.0
+ */
+ @Override
+ public String toString() {
+ return ToString.of(
+ this,
+ Pair.of("proxies", ToString.toString(proxies)),
+ Pair.of("servers", ToString.toString(servers))
+ );
+ }
+
+ /**
+ * Get the {@link List} of proxies.
+ * @return the {@link List} of proxies
+ * @since 1.0.0
+ */
+ List getProxies() {
+ return proxies;
+ }
+
+ /**
+ * Get the {@link List} of servers.
+ * @return the {@link List} of servers
+ * @since 1.0.0
+ */
+ List getServers() {
+ return servers;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/GradleUtils.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/GradleUtils.java
new file mode 100644
index 0000000..42460e5
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/GradleUtils.java
@@ -0,0 +1,92 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.gradle.util.GradleVersion;
+
+import java.io.File;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+/**
+ * Utility class that helps dealing with Gradle.
+ * @since 1.0.0
+ */
+public final class GradleUtils {
+
+ /**
+ * Gradle version.
+ * @since 1.0.0
+ */
+ private static final String VERSION = GradleVersion.current().getVersion();
+
+ /**
+ * Pattern to extract the Gradle home from the {@code PATH} environment variable.
+ * @since 1.0.0
+ */
+ private static final Pattern PATH_PATTERN = Pattern.compile(
+ "^(.*[/\\\\]+gradle-\\d+\\.\\d+(?:\\.\\d+)?)[/\\\\]+bin[/\\\\]*$"
+ );
+
+ /**
+ * Constructor not available.
+ * @since 1.0.0
+ */
+ private GradleUtils() {
+ // Not available
+ }
+
+ /**
+ * Retrieve an {@link Optional} of the Gradle home.
+ * @return the {@link Optional} of the Gradle home
+ * @since 1.0.0
+ */
+ public static Optional retrieveOptionalHome() {
+ final var optionalGradleHome = SystemUtils.getEnvironmentVariable("GRADLE_HOME");
+ if (optionalGradleHome.isPresent()) {
+ return optionalGradleHome;
+ }
+ return Strings.split(File.pathSeparatorChar, SystemUtils.getPathEnvironmentVariable())
+ .stream()
+ .map(segment -> {
+ final var matcher = PATH_PATTERN.matcher(segment);
+ if (matcher.find()) {
+ return Optional.of(matcher.group(1));
+ }
+ return Optional.empty();
+ })
+ .flatMap(Optional::stream)
+ .findAny();
+ }
+
+ /**
+ * Get the Gradle version.
+ * @return the Gradle version
+ * @since 1.0.0
+ */
+ public static String getVersion() {
+ return VERSION;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/MavenUtils.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/MavenUtils.java
new file mode 100644
index 0000000..fb53ff0
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/MavenUtils.java
@@ -0,0 +1,494 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.maven.Maven;
+import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.apache.maven.settings.Repository;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.building.DefaultSettingsBuilderFactory;
+import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.apache.maven.settings.crypto.DefaultSettingsDecrypter;
+import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
+import org.eclipse.aether.DefaultRepositoryCache;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
+import org.eclipse.aether.impl.RemoteRepositoryManager;
+import org.eclipse.aether.repository.AuthenticationSelector;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.MirrorSelector;
+import org.eclipse.aether.repository.Proxy;
+import org.eclipse.aether.repository.ProxySelector;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.repository.RepositoryPolicy;
+import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
+import org.eclipse.aether.spi.connector.transport.TransporterFactory;
+import org.eclipse.aether.spi.locator.ServiceLocator;
+import org.eclipse.aether.transport.file.FileTransporterFactory;
+import org.eclipse.aether.transport.http.HttpTransporterFactory;
+import org.eclipse.aether.util.repository.AuthenticationBuilder;
+import org.eclipse.aether.util.repository.ConservativeAuthenticationSelector;
+import org.eclipse.aether.util.repository.ConservativeProxySelector;
+import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
+import org.eclipse.aether.util.repository.DefaultMirrorSelector;
+import org.eclipse.aether.util.repository.DefaultProxySelector;
+import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
+import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
+
+import java.io.File;
+import java.lang.invoke.MethodHandles;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+/**
+ * Utility class that helps dealing with Maven.
+ * @since 1.0.0
+ */
+public final class MavenUtils {
+
+ /**
+ * Maven version.
+ * @since 1.0.0
+ */
+ private static final String VERSION = Maven.class.getPackage().getImplementationVersion();
+
+ /**
+ * Pattern to extract the Maven home from the {@code PATH} environment variable.
+ * @since 1.0.0
+ */
+ private static final Pattern PATH_PATTERN = Pattern.compile(
+ "^(.*[/\\\\]+apache-maven-\\d+\\.\\d+\\.\\d+)[/\\\\]+bin[/\\\\]*$"
+ );
+
+ /**
+ * User {@code repository} directory.
+ * @since 1.0.0
+ */
+ private static final Path USER_REPOSITORY_DIRECTORY = SystemUtils.getUserHomeDirectory().resolve(
+ Path.of(".m2", "repository")
+ );
+
+ /**
+ * User {@code settings.xml} file.
+ * @since 1.0.0
+ */
+ private static final Path USER_SETTINGS_FILE = SystemUtils.getUserHomeDirectory().resolve(
+ Path.of(".m2", "settings.xml")
+ );
+
+ /**
+ * User {@code settings-security.xml} file.
+ * @since 1.0.0
+ */
+ private static final Path USER_SETTINGS_SECURITY_FILE = SystemUtils.getUserHomeDirectory().resolve(
+ Path.of(".m2", "settings-security.xml")
+ );
+
+ /**
+ * Logger.
+ * @since 1.0.0
+ */
+ private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass());
+
+ /**
+ * Constructor not available.
+ * @since 1.0.0
+ */
+ private MavenUtils() {
+ // Not available
+ }
+
+ /**
+ * Retrieve an {@link Optional} of the Maven home.
+ * @return the {@link Optional} of the Maven home
+ * @since 1.0.0
+ */
+ public static Optional retrieveOptionalGlobalHome() {
+ return Strings.split(File.pathSeparatorChar, SystemUtils.getPathEnvironmentVariable())
+ .stream()
+ .map(segment -> {
+ final var matcher = PATH_PATTERN.matcher(segment);
+ if (matcher.find()) {
+ return Optional.of(matcher.group(1));
+ }
+ return Optional.empty();
+ })
+ .flatMap(Optional::stream)
+ .findAny();
+ }
+
+ /**
+ * Retrieve an {@link Optional} of the global {@code settings.xml} file.
+ * @return the {@link Optional} of the global {@code settings.xml} file
+ * @since 1.0.0
+ */
+ public static Optional retrieveOptionalGlobalSettingsFile() {
+ return retrieveOptionalGlobalHome()
+ .map(globalHome -> Path.of(globalHome, "conf", "settings.xml"));
+ }
+
+ /**
+ * Create a remote repository from an identifier and an URL.
+ * @param id an identifier
+ * @param url an URL
+ * @return the remote repository
+ * @throws NullPointerException if the identifier or the URL is {@code null}
+ * @throws IllegalArgumentException if the identifier or the URL is empty
+ * @since 1.0.0
+ */
+ public static RemoteRepository createRemoteRepository(final String id, final String url) {
+ Ensure.notNullAndNotEmpty("id", id);
+ Ensure.notNullAndNotEmpty("url", url);
+ final var repository = new Repository();
+ repository.setId(id);
+ repository.setUrl(url);
+ return toRemoteRepository(repository);
+ }
+
+ /**
+ * Convert a repository to a remote repository.
+ * @param repository a repository
+ * @return the remote repository
+ * @throws NullPointerException if the repository is {@code null}
+ * @since 1.0.0
+ */
+ static RemoteRepository toRemoteRepository(final Repository repository) {
+ Ensure.notNull("repository", repository);
+ final var builder = new RemoteRepository.Builder(
+ repository.getId(),
+ repository.getLayout(),
+ repository.getUrl()
+ );
+ final var releasesPolicy = repository.getReleases();
+ if (null != releasesPolicy) {
+ builder.setReleasePolicy(
+ new RepositoryPolicy(
+ releasesPolicy.isEnabled(),
+ releasesPolicy.getUpdatePolicy(),
+ releasesPolicy.getChecksumPolicy()
+ )
+ );
+ }
+ final var snapshotsPolicy = repository.getSnapshots();
+ if (null != snapshotsPolicy) {
+ builder.setSnapshotPolicy(
+ new RepositoryPolicy(
+ snapshotsPolicy.isEnabled(),
+ snapshotsPolicy.getUpdatePolicy(),
+ snapshotsPolicy.getChecksumPolicy()
+ )
+ );
+ }
+ return builder.build();
+ }
+
+ /**
+ * Make a service locator.
+ * @return the service locator
+ * @since 1.0.0
+ */
+ public static ServiceLocator makeServiceLocator() {
+ return MavenRepositorySystemUtils.newServiceLocator()
+ .addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class)
+ .addService(TransporterFactory.class, FileTransporterFactory.class)
+ .addService(TransporterFactory.class, HttpTransporterFactory.class);
+ }
+
+ /**
+ * Make a repository system.
+ * @param serviceLocator a service locator
+ * @return the repository system
+ * @throws NullPointerException if the service locator is {@code null}
+ * @since 1.0.0
+ */
+ public static RepositorySystem makeRepositorySystem(final ServiceLocator serviceLocator) {
+ Ensure.notNull("serviceLocator", serviceLocator);
+ return serviceLocator.getService(RepositorySystem.class);
+ }
+
+ /**
+ * Make a remote repository manager.
+ * @param serviceLocator a service locator
+ * @return the remote repository manager
+ * @throws NullPointerException if the service locator is {@code null}
+ * @since 1.0.0
+ */
+ public static RemoteRepositoryManager makeRemoteRepositoryManager(final ServiceLocator serviceLocator) {
+ Ensure.notNull("serviceLocator", serviceLocator);
+ return serviceLocator.getService(RemoteRepositoryManager.class);
+ }
+
+ /**
+ * Make settings using default global and user {@code settings.xml} files.
+ * @return settings
+ * @throws SettingsBuildingException might occur while resolving settings
+ * @since 1.0.0
+ */
+ public static Settings makeSettings() throws SettingsBuildingException {
+ return makeSettings(retrieveOptionalGlobalSettingsFile().orElse(null), USER_SETTINGS_FILE);
+ }
+
+ /**
+ * Make settings using custom global and user {@code settings.xml} files.
+ * @param globalSettingsFile a global {@code settings.xml} file or {@code null}
+ * @param userSettingsFile a user {@code settings.xml} file or {@code null}
+ * @return settings
+ * @throws SettingsBuildingException might occur while resolving settings
+ * @since 1.0.0
+ */
+ static Settings makeSettings(
+ final Path globalSettingsFile,
+ final Path userSettingsFile
+ ) throws SettingsBuildingException {
+ final var result = new DefaultSettingsBuilderFactory()
+ .newInstance()
+ .build(
+ new DefaultSettingsBuildingRequest()
+ .setGlobalSettingsFile(
+ null != globalSettingsFile
+ ? globalSettingsFile.toFile()
+ : null
+ )
+ .setUserSettingsFile(
+ null != userSettingsFile
+ ? userSettingsFile.toFile()
+ : null
+ )
+ .setSystemProperties(System.getProperties())
+ );
+ for (final var exception : result.getProblems()) {
+ logger.warn(exception::getMessage);
+ }
+ return result.getEffectiveSettings();
+ }
+
+ /**
+ * Make decrypted settings using the default user {@code settings-security.xml} file.
+ * @param settings settings
+ * @return decrypted settings
+ * @throws NullPointerException if settings are {@code null}
+ * @since 1.0.0
+ */
+ public static DecryptedSettings makeDecryptedSettings(final Settings settings) {
+ return makeDecryptedSettings(settings, USER_SETTINGS_SECURITY_FILE);
+ }
+
+ /**
+ * Make decrypted settings using a custom user {@code settings-security.xml} file.
+ * @param settings settings
+ * @param userSettingsSecurityFile a user {@code settings-security.xml} file or {@code null}
+ * @return decrypted settings
+ * @throws NullPointerException if settings are {@code null}
+ * @since 1.0.0
+ */
+ static DecryptedSettings makeDecryptedSettings(
+ final Settings settings,
+ final Path userSettingsSecurityFile
+ ) {
+ Ensure.notNull("settings", settings);
+ final var result = new DefaultSettingsDecrypter(
+ new DefaultSecDispatcher(
+ new DefaultPlexusCipher(),
+ Map.of(),
+ null != userSettingsSecurityFile
+ ? userSettingsSecurityFile.toString()
+ : null
+ )
+ ).decrypt(new DefaultSettingsDecryptionRequest(settings));
+ for (final var exception : result.getProblems()) {
+ logger.warn(exception::getMessage);
+ }
+ return new DecryptedSettings(result.getProxies(), result.getServers());
+ }
+
+ /**
+ * Make a local repository.
+ * @param settings settings
+ * @return the local repository
+ * @throws NullPointerException if settings are {@code null}
+ * @since 1.0.0
+ */
+ static LocalRepository makeLocalRepository(final Settings settings) {
+ Ensure.notNull("settings", settings);
+ final var settingsLocalRepository = settings.getLocalRepository();
+ if (null != settingsLocalRepository) {
+ return new LocalRepository(settingsLocalRepository);
+ }
+ return new LocalRepository(USER_REPOSITORY_DIRECTORY.toFile());
+ }
+
+ /**
+ * Make a proxy selector.
+ * @param decryptedSettings decrypted settings
+ * @return the proxy selector
+ * @throws NullPointerException if decrypted settings are {@code null}
+ * @since 1.0.0
+ */
+ static ProxySelector makeProxySelector(final DecryptedSettings decryptedSettings) {
+ Ensure.notNull("decryptedSettings", decryptedSettings);
+ final var proxySelector = new DefaultProxySelector();
+ for (final var proxy : decryptedSettings.getProxies()) {
+ proxySelector.add(
+ new Proxy(
+ proxy.getProtocol(),
+ proxy.getHost(),
+ proxy.getPort(),
+ new AuthenticationBuilder()
+ .addUsername(proxy.getUsername())
+ .addPassword(proxy.getPassword())
+ .build()
+ ),
+ proxy.getNonProxyHosts()
+ );
+ }
+ return new ConservativeProxySelector(proxySelector);
+ }
+
+ /**
+ * Make an authentication selector.
+ * @param decryptedSettings decrypted settings
+ * @return the authentication selector
+ * @throws NullPointerException if decrypted settings are {@code null}
+ * @since 1.0.0
+ */
+ static AuthenticationSelector makeAuthenticationSelector(final DecryptedSettings decryptedSettings) {
+ Ensure.notNull("decryptedSettings", decryptedSettings);
+ final var authenticationSelector = new DefaultAuthenticationSelector();
+ for (final var server : decryptedSettings.getServers()) {
+ authenticationSelector.add(
+ server.getId(),
+ new AuthenticationBuilder()
+ .addUsername(server.getUsername())
+ .addPassword(server.getPassword())
+ .addPrivateKey(server.getPrivateKey(), server.getPassphrase())
+ .build()
+ );
+ }
+ return new ConservativeAuthenticationSelector(authenticationSelector);
+ }
+
+ /**
+ * Make a mirror selector.
+ * @param settings settings
+ * @return the mirror selector
+ * @throws NullPointerException if settings are {@code null}
+ * @since 1.0.0
+ */
+ static MirrorSelector makeMirrorSelector(final Settings settings) {
+ Ensure.notNull("settings", settings);
+ final var mirrorSelector = new DefaultMirrorSelector();
+ for (final var mirror : settings.getMirrors()) {
+ mirrorSelector.add(
+ mirror.getId(),
+ mirror.getUrl(),
+ mirror.getLayout(),
+ false,
+ mirror.isBlocked(),
+ mirror.getMirrorOf(),
+ mirror.getMirrorOfLayouts()
+ );
+ }
+ return mirrorSelector;
+ }
+
+ /**
+ * Make a repository system session.
+ * @param settings settings
+ * @param decryptedSettings decrypted settings
+ * @param repositorySystem a repository system
+ * @return the repository system session
+ * @throws NullPointerException if settings, decrypted settings or the repository system are {@code null}
+ * @since 1.0.0
+ */
+ public static RepositorySystemSession makeRepositorySystemSession(
+ final Settings settings,
+ final DecryptedSettings decryptedSettings,
+ final RepositorySystem repositorySystem
+ ) {
+ Ensure.notNull("settings", settings);
+ Ensure.notNull("decryptedSettings", decryptedSettings);
+ Ensure.notNull("repositorySystem", repositorySystem);
+ final var repositorySystemSession = MavenRepositorySystemUtils.newSession();
+ return repositorySystemSession
+ .setOffline(settings.isOffline())
+ .setLocalRepositoryManager(
+ repositorySystem.newLocalRepositoryManager(
+ repositorySystemSession,
+ makeLocalRepository(settings)
+ )
+ )
+ .setProxySelector(makeProxySelector(decryptedSettings))
+ .setAuthenticationSelector(makeAuthenticationSelector(decryptedSettings))
+ .setMirrorSelector(makeMirrorSelector(settings))
+ .setRepositoryListener(new ConsoleRepositoryListener())
+ .setCache(new DefaultRepositoryCache())
+ .setSystemProperties(System.getProperties());
+ }
+
+ /**
+ * Make a {@link List} of remote repositories.
+ * @param settings settings
+ * @return the {@link List} of remote repositories
+ * @throws NullPointerException if settings are {@code null}
+ * @since 1.0.0
+ */
+ public static List makeRemoteRepositories(final Settings settings) {
+ Ensure.notNull("settings", settings);
+ final var remoteRepositories = new ArrayList();
+ final var activeProfileIds = settings.getActiveProfiles();
+ for (final var entry : settings.getProfilesAsMap().entrySet()) {
+ final var id = entry.getKey();
+ final var profile = entry.getValue();
+ final var profileActivation = profile.getActivation();
+ if (activeProfileIds.contains(id) || null != profileActivation && profileActivation.isActiveByDefault()) {
+ for (final var repository : profile.getRepositories()) {
+ remoteRepositories.add(toRemoteRepository(repository));
+ }
+ for (final var pluginRepository : profile.getPluginRepositories()) {
+ remoteRepositories.add(toRemoteRepository(pluginRepository));
+ }
+ }
+ }
+ return remoteRepositories;
+ }
+
+ /**
+ * Get the Maven version.
+ * @return the Maven version
+ * @since 1.0.0
+ */
+ public static String getVersion() {
+ return VERSION;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/SystemUtils.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/SystemUtils.java
new file mode 100644
index 0000000..5ec127d
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/SystemUtils.java
@@ -0,0 +1,87 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import com.github.alexisjehan.javanilla.misc.quality.Ensure;
+
+import java.nio.file.Path;
+import java.util.Optional;
+
+/**
+ * Utility class that helps dealing with the system.
+ * @since 1.0.0
+ */
+public final class SystemUtils {
+
+ /**
+ * {@code PATH} environment variable.
+ * @since 1.0.0
+ */
+ private static final String PATH_ENVIRONMENT_VARIABLE = System.getenv("PATH");
+
+ /**
+ * User home directory.
+ * @since 1.0.0
+ */
+ private static final Path USER_HOME_DIRECTORY = Path.of(System.getProperty("user.home"));
+
+ /**
+ * Constructor not available.
+ * @since 1.0.0
+ */
+ private SystemUtils() {
+ // Not available
+ }
+
+ /**
+ * Get an {@link Optional} environment variable for the given name.
+ * @param name a name
+ * @return the {@link Optional} environment variable
+ * @throws NullPointerException if the name is {@code null}
+ * @throws IllegalArgumentException if the name is empty
+ * @since 1.0.0
+ */
+ public static Optional getEnvironmentVariable(final String name) {
+ Ensure.notNullAndNotEmpty("name", name);
+ return Optional.ofNullable(System.getenv(name));
+ }
+
+ /**
+ * Get the {@code PATH} environment variable.
+ * @return the {@code PATH} environment variable
+ * @since 1.0.0
+ */
+ public static String getPathEnvironmentVariable() {
+ return PATH_ENVIRONMENT_VARIABLE;
+ }
+
+ /**
+ * Get the user home directory.
+ * @return the user home directory
+ * @since 1.0.0
+ */
+ public static Path getUserHomeDirectory() {
+ return USER_HOME_DIRECTORY;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/package-info.java
new file mode 100644
index 0000000..f65519b
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Utilities.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck.core.util;
\ No newline at end of file
diff --git a/src/main/java/com/github/alexisjehan/mavencheck/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/package-info.java
new file mode 100644
index 0000000..8d553ef
--- /dev/null
+++ b/src/main/java/com/github/alexisjehan/mavencheck/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * Main package.
+ * @since 1.0.0
+ */
+package com.github.alexisjehan.mavencheck;
\ No newline at end of file
diff --git a/src/main/java/org/apache/maven/project/PublicReactorModelCache.java b/src/main/java/org/apache/maven/project/PublicReactorModelCache.java
new file mode 100644
index 0000000..bebd94b
--- /dev/null
+++ b/src/main/java/org/apache/maven/project/PublicReactorModelCache.java
@@ -0,0 +1,39 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.apache.maven.project;
+
+/**
+ * Public access to the {@link ReactorModelCache} class.
+ * @since 1.0.0
+ */
+public final class PublicReactorModelCache extends ReactorModelCache {
+
+ /**
+ * Constructor by default.
+ * @since 1.0.0
+ */
+ public PublicReactorModelCache() {
+ // By default
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/maven/project/PublicReactorModelPool.java b/src/main/java/org/apache/maven/project/PublicReactorModelPool.java
new file mode 100644
index 0000000..59a267d
--- /dev/null
+++ b/src/main/java/org/apache/maven/project/PublicReactorModelPool.java
@@ -0,0 +1,39 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.apache.maven.project;
+
+/**
+ * Public access to the {@link ReactorModelPool} class.
+ * @since 1.0.0
+ */
+public final class PublicReactorModelPool extends ReactorModelPool {
+
+ /**
+ * Constructor by default.
+ * @since 1.0.0
+ */
+ public PublicReactorModelPool() {
+ // By default
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/maven/project/package-info.java b/src/main/java/org/apache/maven/project/package-info.java
new file mode 100644
index 0000000..a2569c6
--- /dev/null
+++ b/src/main/java/org/apache/maven/project/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * {@link org.apache.maven.project} additional custom classes.
+ * @since 1.0.0
+ */
+package org.apache.maven.project;
\ No newline at end of file
diff --git a/src/main/resources/init.gradle b/src/main/resources/init.gradle
new file mode 100644
index 0000000..aa674fe
--- /dev/null
+++ b/src/main/resources/init.gradle
@@ -0,0 +1,29 @@
+settingsEvaluated {
+ settings -> allprojects {
+ task repositories {
+ doLast {
+ [
+ 'NORMAL': [
+ '6.8' <= gradle.gradleVersion
+ ? settings.dependencyResolutionManagement.repositories // Since Gradle 6.8
+ : [],
+ repositories
+ ],
+ 'PLUGIN': [
+ settings.pluginManagement.repositories
+ ]
+ ].each {
+ repositoryType, repositories ->
+ repositories
+ .flatten()
+ .findAll {
+ repository -> repository instanceof MavenArtifactRepository
+ }
+ .each {
+ repository -> println "$repositoryType:${repository.name}:${repository.url}"
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..def2504
--- /dev/null
+++ b/src/main/resources/log4j2.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/ApplicationIT.java b/src/test/java/com/github/alexisjehan/mavencheck/ApplicationIT.java
new file mode 100644
index 0000000..4f02389
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/ApplicationIT.java
@@ -0,0 +1,115 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+final class ApplicationIT {
+
+ @Test
+ void testRun(@TempDir final Path tmpDirectory) throws IOException {
+ final var tmpMavenBuildFile = tmpDirectory.resolve("pom.xml");
+ Files.copy(
+ Path.of("src", "test", "resources", "pom_it.xml"),
+ tmpMavenBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ final var tmpGroovyBuildDirectory = tmpDirectory.resolve("groovy");
+ Files.createDirectory(tmpGroovyBuildDirectory);
+ final var tmpGroovyBuildFile = tmpGroovyBuildDirectory.resolve("build.gradle");
+ Files.copy(
+ Path.of("src", "test", "resources", "build_it.gradle"),
+ tmpGroovyBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ final var tmpKotlinBuildDirectory = tmpDirectory.resolve("kotlin");
+ Files.createDirectory(tmpKotlinBuildDirectory);
+ final var tmpKotlinBuildFile = tmpKotlinBuildDirectory.resolve("build.gradle.kts");
+ Files.copy(
+ Path.of("src", "test", "resources", "build_it.gradle.kts"),
+ tmpKotlinBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ try (final var outputStream = new ByteArrayOutputStream()) {
+ try (final var printStream = new PrintStream(outputStream)) {
+ final var application = new Application(printStream);
+ application.run(tmpDirectory, false, false);
+ }
+ assertThat(outputStream.toString()).matches(
+ "^"
+ + "3 build file\\(s\\) found, checking for artifact updates\\R"
+ + "\\R"
+ + ".+[/\\\\]pom\\.xml\\R"
+ + "\\[DEPENDENCY] com\\.google\\.android\\.material:material 1\\.0\\.0 -> "
+ + "\\d+\\.\\d+\\.\\d+\\R"
+ + "\\[DEPENDENCY] com\\.google\\.guava:guava 10\\.0 -> \\d+\\.\\d+(?:\\.\\d+)?-jre\\R"
+ + "\\[DEPENDENCY] org\\.springframework:spring-core 3\\.0\\.0\\.RELEASE -> "
+ + "\\d+\\.\\d+\\.\\d+\\R"
+ + "\\[PROFILE DEPENDENCY] com\\.google\\.guava:guava 23\\.1-jre -> "
+ + "\\d+\\.\\d+(?:\\.\\d+)?-jre\\R"
+ + "\\[PROFILE DEPENDENCY] com\\.google\\.guava:guava 23\\.1-android -> "
+ + "\\d+\\.\\d+(?:\\.\\d+)?-android\\R"
+ + "5 artifact update\\(s\\) available\\R"
+ + "\\R"
+ + ".+[/\\\\]build\\.gradle\\R"
+ + "\\[IMPLEMENTATION] com\\.google\\.android\\.material:material 1\\.0\\.0 -> "
+ + "\\d+\\.\\d+\\.\\d+\\R"
+ + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 10\\.0 -> \\d+\\.\\d+(?:\\.\\d+)?-jre\\R"
+ + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 23\\.1-jre -> "
+ + "\\d+\\.\\d+(?:\\.\\d+)?-jre\\R"
+ + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 23\\.1-android -> "
+ + "\\d+\\.\\d+(?:\\.\\d+)?-android\\R"
+ + "\\[IMPLEMENTATION] org\\.springframework:spring-core 3\\.0\\.0\\.RELEASE -> "
+ + "\\d+\\.\\d+\\.\\d+\\R"
+ + "5 artifact update\\(s\\) available\\R"
+ + "\\R"
+ + ".+[/\\\\]build\\.gradle\\.kts\\R"
+ + "\\[IMPLEMENTATION] com\\.google\\.android\\.material:material 1\\.0\\.0 -> "
+ + "\\d+\\.\\d+\\.\\d+\\R"
+ + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 10\\.0 -> \\d+\\.\\d+(?:\\.\\d+)?-jre\\R"
+ + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 23\\.1-jre -> "
+ + "\\d+\\.\\d+(?:\\.\\d+)?-jre\\R"
+ + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 23\\.1-android -> "
+ + "\\d+\\.\\d+(?:\\.\\d+)?-android\\R"
+ + "\\[IMPLEMENTATION] org\\.springframework:spring-core 3\\.0\\.0\\.RELEASE -> "
+ + "\\d+\\.\\d+\\.\\d+\\R"
+ + "5 artifact update\\(s\\) available\\R"
+ + "\\R"
+ + "3/3 build file\\(s\\) checked, 15 artifact update\\(s\\) available\\R"
+ + "\\R"
+ + "$"
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/ApplicationTest.java b/src/test/java/com/github/alexisjehan/mavencheck/ApplicationTest.java
new file mode 100644
index 0000000..0ac6f74
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/ApplicationTest.java
@@ -0,0 +1,192 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck;
+
+import com.github.alexisjehan.mavencheck.core.Service;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.ArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactUpdateVersion;
+import com.github.alexisjehan.mavencheck.core.component.build.Build;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+import com.github.alexisjehan.mavencheck.core.component.build.resolver.BuildResolveException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.nio.file.Path;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+@ExtendWith(MockitoExtension.class)
+final class ApplicationTest {
+
+ @Mock
+ private Service mockedService;
+
+ @Test
+ void testConstructorInvalid() {
+ try (final var printStream = new PrintStream(OutputStream.nullOutputStream())) {
+ assertThatNullPointerException()
+ .isThrownBy(() -> new Application(null, printStream, false));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new Application(printStream, null, false));
+ }
+ }
+
+ @Test
+ void testRun() throws IOException {
+ final var path1 = Path.of("path1");
+ final var path2 = Path.of("path2");
+ final var path3 = Path.of("path3");
+ final var buildFile1 = new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml"));
+ final var buildFile2 = new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle"));
+ final var buildFile3 = new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts"));
+ final var artifact = new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("foo-group-id", "foo-artifact-id"),
+ "1.0.0"
+ );
+ final var build1 = new Build(
+ buildFile1,
+ List.of(),
+ List.of(artifact)
+ );
+ final var build2 = new Build(
+ buildFile2,
+ List.of(),
+ List.of(artifact)
+ );
+ Mockito.when(mockedService.findBuildFiles(Mockito.argThat(path1::equals)))
+ .thenReturn(List.of());
+ Mockito.when(mockedService.findBuildFiles(Mockito.argThat(path2::equals)))
+ .thenReturn(List.of(buildFile1));
+ Mockito.when(mockedService.findBuildFiles(Mockito.argThat(path3::equals)))
+ .thenReturn(List.of(buildFile1, buildFile2, buildFile3));
+ Mockito.when(mockedService.findBuild(Mockito.argThat(buildFile1::equals)))
+ .thenReturn(build1);
+ Mockito.when(mockedService.findBuild(Mockito.argThat(buildFile2::equals)))
+ .thenReturn(build2);
+ Mockito.when(mockedService.findBuild(Mockito.argThat(buildFile3::equals)))
+ .thenThrow(BuildResolveException.class);
+ Mockito.when(mockedService.findArtifactUpdateVersions(Mockito.argThat(build1::equals), Mockito.anyBoolean()))
+ .thenReturn(List.of());
+ Mockito.when(mockedService.findArtifactUpdateVersions(Mockito.argThat(build2::equals), Mockito.anyBoolean()))
+ .thenReturn(List.of(new ArtifactUpdateVersion(artifact, "2.0.0")));
+ try (final var mockedApplication = Mockito.mockStatic(Application.class)) {
+ mockedApplication.when(Application::createService)
+ .thenReturn(mockedService);
+ try (final var printStream = new PrintStream(OutputStream.nullOutputStream())) {
+ final var application = new Application(printStream);
+ assertThatNoException().isThrownBy(application::run);
+ assertThatNoException().isThrownBy(() -> application.run("-h"));
+ assertThatNoException().isThrownBy(() -> application.run("-i"));
+ assertThatNoException().isThrownBy(() -> application.run("-s"));
+ assertThatNoException().isThrownBy(() -> application.run("-v"));
+ assertThatNoException().isThrownBy(() -> application.run("directory_not-found"));
+ assertThatNoException().isThrownBy(() -> application.run(path1.toString()));
+ assertThatNoException().isThrownBy(() -> application.run(path2.toString()));
+ assertThatNoException().isThrownBy(() -> application.run(path3.toString()));
+ assertThatNoException().isThrownBy(() -> application.run(path1, false, true));
+ assertThatNoException().isThrownBy(() -> application.run(path2, false, true));
+ assertThatNoException().isThrownBy(() -> application.run(path3, false, true));
+ }
+ }
+ }
+
+ @Test
+ void testRunInvalid() {
+ try (final var printStream = new PrintStream(OutputStream.nullOutputStream())) {
+ final var application = new Application(printStream);
+ assertThatNullPointerException()
+ .isThrownBy(() -> application.run((String[]) null));
+ assertThatNullPointerException()
+ .isThrownBy(() -> application.run((String) null));
+ assertThatNullPointerException()
+ .isThrownBy(() -> application.run(null, false, false));
+ }
+ }
+
+ @Test
+ void testCreateService() {
+ assertThatNoException().isThrownBy(Application::createService);
+ }
+
+ @Test
+ void testToStringException() {
+ assertThat(Application.toString(new Exception(" foo "))).isEqualTo("foo");
+ assertThat(Application.toString(new Exception(" foo ", new Exception(" bar ")))).isEqualTo("bar");
+ }
+
+ @Test
+ void testToStringExceptionInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> Application.toString((Exception) null));
+ }
+
+ @Test
+ void testToStringPath() {
+ assertThat(Application.toString(Path.of("." + File.separator + "pom.xml")))
+ .isEqualTo("pom.xml");
+ assertThat(Application.toString(Path.of("." + File.separator + "foo" + File.separator + "pom.xml")))
+ .isEqualTo("foo" + File.separator + "pom.xml");
+ }
+
+ @Test
+ void testToStringPathInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> Application.toString((Path) null));
+ }
+
+ @Test
+ void testToStringArtifactType() {
+ assertThat(Application.toString(MavenArtifactType.DEPENDENCY)).isEqualTo("DEPENDENCY");
+ assertThat(Application.toString(MavenArtifactType.BUILD_PLUGIN)).isEqualTo("BUILD PLUGIN");
+ }
+
+ @Test
+ void testToStringArtifactTypeInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> Application.toString((ArtifactType) null));
+ }
+
+ @Test
+ void testToStringArtifactIdentifier() {
+ assertThat(Application.toString(new ArtifactIdentifier("foo-group-id", "foo-artifact-id")))
+ .isEqualTo("foo-group-id:foo-artifact-id");
+ }
+
+ @Test
+ void testToStringArtifactIdentifierInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> Application.toString((ArtifactIdentifier) null));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/ServiceTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/ServiceTest.java
new file mode 100644
index 0000000..da10bac
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/ServiceTest.java
@@ -0,0 +1,357 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core;
+
+import com.github.alexisjehan.javanilla.util.function.ThrowableConsumer;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactAvailableVersions;
+import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactUpdateVersion;
+import com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver.ArtifactAvailableVersionsResolver;
+import com.github.alexisjehan.mavencheck.core.component.build.Build;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+import com.github.alexisjehan.mavencheck.core.component.build.resolver.GradleBuildResolver;
+import com.github.alexisjehan.mavencheck.core.component.build.resolver.MavenBuildResolver;
+import com.github.alexisjehan.mavencheck.core.component.filter.artifact.ArtifactFilter;
+import com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser.ArtifactFilterParser;
+import com.github.alexisjehan.mavencheck.core.component.session.MavenSession;
+import com.github.alexisjehan.mavencheck.core.util.SystemUtils;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+@ExtendWith(MockitoExtension.class)
+final class ServiceTest {
+
+ @Mock
+ private MavenSession mockedMavenSession;
+
+ @Mock
+ private MavenBuildResolver mockedMavenBuildResolver;
+
+ @Mock
+ private GradleBuildResolver mockedGradleBuildResolver;
+
+ @Mock
+ private ArtifactAvailableVersionsResolver mockedArtifactAvailableVersionsResolver;
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(
+ () -> new Service(
+ null
+ )
+ );
+ assertThatNullPointerException().isThrownBy(
+ () -> new Service(
+ null,
+ mockedArtifactAvailableVersionsResolver
+ )
+ );
+ assertThatNullPointerException().isThrownBy(
+ () -> new Service(
+ Collections.singleton(null),
+ mockedArtifactAvailableVersionsResolver
+ )
+ );
+ assertThatNullPointerException().isThrownBy(
+ () -> new Service(
+ Set.of(mockedMavenBuildResolver, mockedGradleBuildResolver),
+ null
+ )
+ );
+ }
+
+ @Test
+ void testFindBuildFiles(@TempDir final Path tmpDirectory) throws IOException {
+ final var service = new Service(mockedMavenSession);
+ final var rootMavenFile = tmpDirectory.resolve(Path.of("pom.xml"));
+ final var fooMavenFile = tmpDirectory.resolve(Path.of("foo", "pom.xml"));
+ final var fooGradleGroovyFile = tmpDirectory.resolve(Path.of("foo", "build.gradle"));
+ final var fooGradleKotlinFile = tmpDirectory.resolve(Path.of("foo", "build.gradle.kts"));
+ final var foo10MavenFile = tmpDirectory.resolve(Path.of("foo", "10", "pom.xml"));
+ final var foo1GradleGroovyFile = tmpDirectory.resolve(Path.of("foo", "1", "build.gradle"));
+ final var foo2GradleKotlinFile = tmpDirectory.resolve(Path.of("foo", "2", "build.gradle.kts"));
+ final var barMavenFile = tmpDirectory.resolve(Path.of("bar", "pom.xml"));
+ final var barGradleGroovyFile = tmpDirectory.resolve(Path.of("bar", "build.gradle"));
+ final var barGradleKotlinFile = tmpDirectory.resolve(Path.of("bar", "build.gradle.kts"));
+ final var bar10MavenFile = tmpDirectory.resolve(Path.of("bar", "10", "pom.xml"));
+ final var bar1GradleGroovyFile = tmpDirectory.resolve(Path.of("bar", "1", "build.gradle"));
+ final var bar2GradleKotlinFile = tmpDirectory.resolve(Path.of("bar", "2", "build.gradle.kts"));
+ Stream.of(
+ rootMavenFile,
+ fooMavenFile,
+ fooGradleGroovyFile,
+ fooGradleKotlinFile,
+ foo10MavenFile,
+ foo1GradleGroovyFile,
+ foo2GradleKotlinFile,
+ barMavenFile,
+ barGradleGroovyFile,
+ barGradleKotlinFile,
+ bar10MavenFile,
+ bar1GradleGroovyFile,
+ bar2GradleKotlinFile
+ ).forEach(
+ ThrowableConsumer.sneaky(file -> {
+ Files.createDirectories(file.getParent());
+ Files.createFile(file);
+ })
+ );
+ assertThat(service.findBuildFiles(tmpDirectory)).containsExactly(
+ new BuildFile(BuildFileType.MAVEN, rootMavenFile),
+ new BuildFile(BuildFileType.GRADLE_GROOVY, barGradleGroovyFile),
+ new BuildFile(BuildFileType.GRADLE_KOTLIN, barGradleKotlinFile),
+ new BuildFile(BuildFileType.MAVEN, barMavenFile),
+ new BuildFile(BuildFileType.GRADLE_GROOVY, bar1GradleGroovyFile),
+ new BuildFile(BuildFileType.GRADLE_KOTLIN, bar2GradleKotlinFile),
+ new BuildFile(BuildFileType.MAVEN, bar10MavenFile),
+ new BuildFile(BuildFileType.GRADLE_GROOVY, fooGradleGroovyFile),
+ new BuildFile(BuildFileType.GRADLE_KOTLIN, fooGradleKotlinFile),
+ new BuildFile(BuildFileType.MAVEN, fooMavenFile),
+ new BuildFile(BuildFileType.GRADLE_GROOVY, foo1GradleGroovyFile),
+ new BuildFile(BuildFileType.GRADLE_KOTLIN, foo2GradleKotlinFile),
+ new BuildFile(BuildFileType.MAVEN, foo10MavenFile)
+ );
+ }
+
+ @Test
+ void testFindBuildFilesInvalid() throws IOException {
+ final var service = new Service(mockedMavenSession);
+ assertThatNullPointerException()
+ .isThrownBy(() -> service.findBuildFiles(null));
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> service.findBuildFiles(Path.of("directory_not-found")));
+ }
+
+ @Test
+ void testFindBuild() throws IOException {
+ Mockito.when(mockedMavenBuildResolver.resolve(Mockito.notNull()))
+ .then(invocation -> new Build(invocation.getArgument(0), List.of(), List.of()));
+ Mockito.when(mockedMavenBuildResolver.getFileTypes())
+ .thenCallRealMethod();
+ Mockito.when(mockedGradleBuildResolver.resolve(Mockito.notNull()))
+ .then(invocation -> new Build(invocation.getArgument(0), List.of(), List.of()));
+ Mockito.when(mockedGradleBuildResolver.getFileTypes())
+ .thenCallRealMethod();
+ assertThat(
+ new Service(
+ Set.of(),
+ mockedArtifactAvailableVersionsResolver
+ )
+ ).satisfies(service -> {
+ assertThat(new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml"))).satisfies(
+ buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(
+ () -> service.findBuild(buildFile)
+ )
+ );
+ assertThat(new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle"))).satisfies(
+ buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(
+ () -> service.findBuild(buildFile)
+ )
+ );
+ assertThat(new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts"))).satisfies(
+ buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(
+ () -> service.findBuild(buildFile)
+ )
+ );
+ });
+ assertThat(
+ new Service(
+ Set.of(mockedMavenBuildResolver),
+ mockedArtifactAvailableVersionsResolver
+ )
+ ).satisfies(service -> {
+ assertThat(new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml"))).satisfies(
+ buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile)
+ );
+ assertThat(new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle"))).satisfies(
+ buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(
+ () -> service.findBuild(buildFile)
+ )
+ );
+ assertThat(new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts"))).satisfies(
+ buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(
+ () -> service.findBuild(buildFile)
+ )
+ );
+ });
+ assertThat(
+ new Service(
+ Set.of(mockedGradleBuildResolver),
+ mockedArtifactAvailableVersionsResolver
+ )
+ ).satisfies(service -> {
+ assertThat(new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml"))).satisfies(
+ buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(
+ () -> service.findBuild(buildFile)
+ )
+ );
+ assertThat(new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle"))).satisfies(
+ buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile)
+ );
+ assertThat(new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts"))).satisfies(
+ buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile)
+ );
+ });
+ assertThat(
+ new Service(
+ Set.of(mockedMavenBuildResolver, mockedGradleBuildResolver),
+ mockedArtifactAvailableVersionsResolver
+ )
+ ).satisfies(service -> {
+ assertThat(new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml"))).satisfies(
+ buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile)
+ );
+ assertThat(new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle"))).satisfies(
+ buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile)
+ );
+ assertThat(new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts"))).satisfies(
+ buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile)
+ );
+ });
+ }
+
+ @Test
+ void testFindBuildInvalid() throws IOException {
+ final var service = new Service(mockedMavenSession);
+ assertThatNullPointerException().isThrownBy(() -> service.findBuild(null));
+ }
+
+ @Test
+ void testFindArtifactUpdateVersions() throws IOException {
+ final var service = new Service(
+ Set.of(mockedMavenBuildResolver, mockedGradleBuildResolver),
+ mockedArtifactAvailableVersionsResolver
+ );
+ final var fooIdentifier = new ArtifactIdentifier("foo-group-id", "foo-artifact-id");
+ final var barIdentifier = new ArtifactIdentifier("bar-group-id", "bar-artifact-id");
+ Mockito
+ .when(
+ mockedArtifactAvailableVersionsResolver.resolve(
+ Mockito.argThat(
+ artifact -> null != artifact && fooIdentifier.equals(artifact.getIdentifier())
+ ),
+ Mockito.notNull()
+ )
+ )
+ .then(
+ invocation -> new ArtifactAvailableVersions(
+ invocation.getArgument(0),
+ List.of("1.0.0", "2.0.0")
+ )
+ );
+ Mockito
+ .when(
+ mockedArtifactAvailableVersionsResolver.resolve(
+ Mockito.argThat(
+ artifact -> null != artifact && barIdentifier.equals(artifact.getIdentifier())
+ ),
+ Mockito.notNull()
+ )
+ )
+ .then(
+ invocation -> new ArtifactAvailableVersions(
+ invocation.getArgument(0),
+ List.of()
+ )
+ );
+ final var fooArtifact1 = new Artifact<>(MavenArtifactType.DEPENDENCY, fooIdentifier, "1.0.0");
+ final var fooArtifact2 = new Artifact<>(MavenArtifactType.DEPENDENCY, fooIdentifier, "2.0.0-SNAPSHOT");
+ final var fooArtifact3 = new Artifact<>(MavenArtifactType.DEPENDENCY, fooIdentifier, "2.0.0");
+ final var barArtifact = new Artifact<>(MavenArtifactType.DEPENDENCY, barIdentifier, "1.1.0");
+ final var build = new Build(
+ new BuildFile(BuildFileType.MAVEN, Path.of("src", "test", "resources", "pom.xml")),
+ List.of(),
+ List.of(fooArtifact1, fooArtifact2, fooArtifact3, barArtifact)
+ );
+ assertThat(service.findArtifactUpdateVersions(build, false)).containsExactly(
+ new ArtifactUpdateVersion(fooArtifact1, "2.0.0"),
+ new ArtifactUpdateVersion(fooArtifact2, "2.0.0")
+ );
+ assertThat(service.findArtifactUpdateVersions(build, true)).containsExactly(
+ new ArtifactUpdateVersion(fooArtifact1, "2.0.0")
+ );
+ }
+
+ @Test
+ void testFindArtifactUpdateVersionsInvalid() throws IOException {
+ final var service = new Service(mockedMavenSession);
+ assertThatNullPointerException()
+ .isThrownBy(() -> service.findArtifactUpdateVersions(null, false));
+ }
+
+ @Test
+ void testCreateUserArtifactFilter(@TempDir final Path tmpDirectory) throws IOException {
+ final var ignoreFile = tmpDirectory.resolve(Path.of(".mvnchk-ignore"));
+ try (final var mockedArtifactFilterParser = Mockito.mockStatic(ArtifactFilterParser.class)) {
+ mockedArtifactFilterParser.when(() -> ArtifactFilterParser.parse(Mockito.notNull()))
+ .thenReturn(ArtifactFilter.ALL);
+ try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) {
+ mockedSystemUtils.when(SystemUtils::getUserHomeDirectory)
+ .thenReturn(tmpDirectory);
+ assertThat(Service.createUserArtifactFilter()).isSameAs(ArtifactFilter.NONE);
+ Files.createFile(ignoreFile);
+ assertThat(Service.createUserArtifactFilter()).isSameAs(ArtifactFilter.ALL);
+ }
+ }
+ }
+
+ @Test
+ void testCreateBuildArtifactFilter(@TempDir final Path tmpDirectory) throws IOException {
+ final var ignoreFile = tmpDirectory.resolve(Path.of(".mvnchk-ignore"));
+ try (final var mockedArtifactFilterParser = Mockito.mockStatic(ArtifactFilterParser.class)) {
+ mockedArtifactFilterParser.when(() -> ArtifactFilterParser.parse(Mockito.notNull()))
+ .thenReturn(ArtifactFilter.ALL);
+ final var buildFile = new BuildFile(BuildFileType.MAVEN, tmpDirectory.resolve("pom.xml"));
+ assertThat(Service.createBuildArtifactFilter(buildFile)).isSameAs(ArtifactFilter.NONE);
+ Files.createFile(ignoreFile);
+ assertThat(Service.createBuildArtifactFilter(buildFile)).isSameAs(ArtifactFilter.ALL);
+ }
+ }
+
+ @Test
+ void testCreateBuildArtifactFilterInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> Service.createBuildArtifactFilter(null));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifierTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifierTest.java
new file mode 100644
index 0000000..cbff3ab
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifierTest.java
@@ -0,0 +1,83 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class ArtifactIdentifierTest {
+
+ private static final String GROUP_ID = "foo-group-id";
+ private static final String ARTIFACT_ID = "foo-artifact-id";
+ private static final String OTHER_GROUP_ID = "bar-group-id";
+ private static final String OTHER_ARTIFACT_ID = "bar-artifact-id";
+
+ private final ArtifactIdentifier artifactIdentifier = new ArtifactIdentifier(GROUP_ID, ARTIFACT_ID);
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> new ArtifactIdentifier(null, ARTIFACT_ID));
+ assertThatIllegalArgumentException().isThrownBy(() -> new ArtifactIdentifier(Strings.EMPTY, ARTIFACT_ID));
+ assertThatNullPointerException().isThrownBy(() -> new ArtifactIdentifier(GROUP_ID, null));
+ assertThatIllegalArgumentException().isThrownBy(() -> new ArtifactIdentifier(GROUP_ID, Strings.EMPTY));
+ }
+
+ @Test
+ void testEqualsAndHashCodeAndToString() {
+ assertThat(artifactIdentifier.equals(artifactIdentifier)).isTrue();
+ assertThat(artifactIdentifier).isNotEqualTo(new Object());
+ assertThat(new ArtifactIdentifier(GROUP_ID, ARTIFACT_ID)).satisfies(otherArtifactIdentifier -> {
+ assertThat(artifactIdentifier).isNotSameAs(otherArtifactIdentifier);
+ assertThat(artifactIdentifier).isEqualTo(otherArtifactIdentifier);
+ assertThat(artifactIdentifier).hasSameHashCodeAs(otherArtifactIdentifier);
+ assertThat(artifactIdentifier).hasToString(otherArtifactIdentifier.toString());
+ });
+ assertThat(new ArtifactIdentifier(OTHER_GROUP_ID, ARTIFACT_ID)).satisfies(otherArtifactIdentifier -> {
+ assertThat(artifactIdentifier).isNotSameAs(otherArtifactIdentifier);
+ assertThat(artifactIdentifier).isNotEqualTo(otherArtifactIdentifier);
+ assertThat(artifactIdentifier).doesNotHaveSameHashCodeAs(otherArtifactIdentifier);
+ assertThat(artifactIdentifier).doesNotHaveToString(otherArtifactIdentifier.toString());
+ });
+ assertThat(new ArtifactIdentifier(GROUP_ID, OTHER_ARTIFACT_ID)).satisfies(otherArtifactIdentifier -> {
+ assertThat(artifactIdentifier).isNotSameAs(otherArtifactIdentifier);
+ assertThat(artifactIdentifier).isNotEqualTo(otherArtifactIdentifier);
+ assertThat(artifactIdentifier).doesNotHaveSameHashCodeAs(otherArtifactIdentifier);
+ assertThat(artifactIdentifier).doesNotHaveToString(otherArtifactIdentifier.toString());
+ });
+ }
+
+ @Test
+ void testGetGroupId() {
+ assertThat(artifactIdentifier.getGroupId()).isEqualTo(GROUP_ID);
+ }
+
+ @Test
+ void testGetArtifactId() {
+ assertThat(artifactIdentifier.getArtifactId()).isEqualTo(ARTIFACT_ID);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactTest.java
new file mode 100644
index 0000000..da9c51e
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactTest.java
@@ -0,0 +1,112 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class ArtifactTest {
+
+ private static final MavenArtifactType TYPE = MavenArtifactType.DEPENDENCY;
+ private static final ArtifactIdentifier IDENTIFIER = new ArtifactIdentifier(
+ "foo-group-id",
+ "foo-artifact-id"
+ );
+ private static final String VERSION = "foo-version";
+ private static final MavenArtifactType OTHER_TYPE = MavenArtifactType.BUILD_PLUGIN;
+ private static final ArtifactIdentifier OTHER_IDENTIFIER = new ArtifactIdentifier(
+ "bar-group-id",
+ "bar-artifact-id"
+ );
+
+ private final Artifact artifact = new Artifact<>(TYPE, IDENTIFIER, VERSION);
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> new Artifact<>(null, IDENTIFIER, VERSION));
+ assertThatNullPointerException().isThrownBy(() -> new Artifact<>(TYPE, null, VERSION));
+ }
+
+ @Test
+ void testWith() {
+ assertThat(artifact.with(TYPE)).satisfies(otherArtifact -> {
+ assertThat(otherArtifact.getType()).isEqualTo(TYPE);
+ assertThat(artifact.getIdentifier()).isEqualTo(otherArtifact.getIdentifier());
+ assertThat(artifact.getOptionalVersion()).isEqualTo(otherArtifact.getOptionalVersion());
+ });
+ assertThat(artifact.with(OTHER_TYPE)).satisfies(otherArtifact -> {
+ assertThat(otherArtifact.getType()).isEqualTo(OTHER_TYPE);
+ assertThat(artifact.getIdentifier()).isEqualTo(otherArtifact.getIdentifier());
+ assertThat(artifact.getOptionalVersion()).isEqualTo(otherArtifact.getOptionalVersion());
+ });
+ }
+
+ @Test
+ void testEqualsAndHashCodeAndToString() {
+ assertThat(artifact.equals(artifact)).isTrue();
+ assertThat(artifact).isNotEqualTo(new Object());
+ assertThat(new Artifact<>(TYPE, IDENTIFIER, VERSION)).satisfies(otherArtifact -> {
+ assertThat(artifact).isNotSameAs(otherArtifact);
+ assertThat(artifact).isEqualTo(otherArtifact);
+ assertThat(artifact).hasSameHashCodeAs(otherArtifact);
+ assertThat(artifact).hasToString(otherArtifact.toString());
+ });
+ assertThat(new Artifact<>(OTHER_TYPE, IDENTIFIER, VERSION)).satisfies(otherArtifact -> {
+ assertThat(artifact).isNotSameAs(otherArtifact);
+ assertThat(artifact).isNotEqualTo(otherArtifact);
+ assertThat(artifact).doesNotHaveSameHashCodeAs(otherArtifact);
+ assertThat(artifact).doesNotHaveToString(otherArtifact.toString());
+ });
+ assertThat(new Artifact<>(TYPE, OTHER_IDENTIFIER, VERSION)).satisfies(otherArtifact -> {
+ assertThat(artifact).isNotSameAs(otherArtifact);
+ assertThat(artifact).isNotEqualTo(otherArtifact);
+ assertThat(artifact).doesNotHaveSameHashCodeAs(otherArtifact);
+ assertThat(artifact).doesNotHaveToString(otherArtifact.toString());
+ });
+ assertThat(new Artifact<>(TYPE, IDENTIFIER)).satisfies(otherArtifact -> {
+ assertThat(artifact).isNotSameAs(otherArtifact);
+ assertThat(artifact).isNotEqualTo(otherArtifact);
+ assertThat(artifact).doesNotHaveSameHashCodeAs(otherArtifact);
+ assertThat(artifact).doesNotHaveToString(otherArtifact.toString());
+ });
+ }
+
+ @Test
+ void testGetType() {
+ assertThat(artifact.getType()).isEqualTo(TYPE);
+ }
+
+ @Test
+ void testGetIdentifier() {
+ assertThat(artifact.getIdentifier()).isEqualTo(IDENTIFIER);
+ }
+
+ @Test
+ void testGetOptionalVersion() {
+ assertThat(artifact.getOptionalVersion()).hasValue(VERSION);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactTypeTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactTypeTest.java
new file mode 100644
index 0000000..eb4c964
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactTypeTest.java
@@ -0,0 +1,54 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.type;
+
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+final class GradleArtifactTypeTest {
+
+ @Test
+ void testDependenciesTaskName() {
+ assertThat(GradleArtifactType.COMPILE_ONLY.dependenciesTaskName()).isEqualTo("compileOnly");
+ }
+
+ @Test
+ void testIsClasspath() {
+ assertThat(GradleArtifactType.COMPILE_CLASSPATH.isClasspath()).isTrue();
+ assertThat(GradleArtifactType.COMPILE_ONLY.isClasspath()).isFalse();
+ }
+
+ @Test
+ void testIsDeprecated() {
+ assertThat(GradleArtifactType.COMPILE.isDeprecated()).isTrue();
+ assertThat(GradleArtifactType.COMPILE_ONLY.isDeprecated()).isFalse();
+ }
+
+ @Test
+ void testGetRepositoryType() {
+ assertThat(GradleArtifactType.COMPILE_ONLY.getRepositoryType()).isEqualTo(RepositoryType.NORMAL);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactTypeTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactTypeTest.java
new file mode 100644
index 0000000..8a08899
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactTypeTest.java
@@ -0,0 +1,38 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.type;
+
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+final class MavenArtifactTypeTest {
+
+ @Test
+ void testGetRepositoryType() {
+ assertThat(MavenArtifactType.DEPENDENCY.getRepositoryType()).isEqualTo(RepositoryType.NORMAL);
+ assertThat(MavenArtifactType.BUILD_PLUGIN.getRepositoryType()).isEqualTo(RepositoryType.PLUGIN);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersionsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersionsTest.java
new file mode 100644
index 0000000..2bc2413
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersionsTest.java
@@ -0,0 +1,129 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class ArtifactAvailableVersionsTest {
+
+ private static final Artifact> ARTIFACT = new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("foo-group-id", "foo-artifact-id")
+ );
+ private static final List AVAILABLE_VERSIONS = List.of("foo-version");
+ private static final Artifact> OTHER_ARTIFACT = new Artifact<>(
+ MavenArtifactType.BUILD_PLUGIN,
+ new ArtifactIdentifier("bar-group-id", "bar-artifact-id")
+ );
+ private static final List OTHER_AVAILABLE_VERSIONS = List.of();
+
+ private final ArtifactAvailableVersions artifactAvailableVersions = new ArtifactAvailableVersions(
+ ARTIFACT,
+ AVAILABLE_VERSIONS
+ );
+
+ @Test
+ void testConstructorImmutable() {
+ final var availableVersions = new ArrayList<>(AVAILABLE_VERSIONS);
+ final var artifactAvailableVersions = new ArtifactAvailableVersions(ARTIFACT, availableVersions);
+ availableVersions.clear();
+ assertThat(artifactAvailableVersions.getAvailableVersions()).containsExactlyElementsOf(AVAILABLE_VERSIONS);
+ }
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException()
+ .isThrownBy(() -> new ArtifactAvailableVersions(null, AVAILABLE_VERSIONS));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new ArtifactAvailableVersions(ARTIFACT, null));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new ArtifactAvailableVersions(ARTIFACT, Collections.singletonList(null)));
+ }
+
+ @Test
+ void testEqualsAndHashCodeAndToString() {
+ assertThat(artifactAvailableVersions.equals(artifactAvailableVersions)).isTrue();
+ assertThat(artifactAvailableVersions).isNotEqualTo(new Object());
+ assertThat(new ArtifactAvailableVersions(ARTIFACT, AVAILABLE_VERSIONS))
+ .satisfies(otherArtifactAvailableVersions -> {
+ assertThat(artifactAvailableVersions)
+ .isNotSameAs(otherArtifactAvailableVersions);
+ assertThat(artifactAvailableVersions)
+ .isEqualTo(otherArtifactAvailableVersions);
+ assertThat(artifactAvailableVersions)
+ .hasSameHashCodeAs(otherArtifactAvailableVersions);
+ assertThat(artifactAvailableVersions)
+ .hasToString(otherArtifactAvailableVersions.toString());
+ });
+ assertThat(new ArtifactAvailableVersions(OTHER_ARTIFACT, AVAILABLE_VERSIONS))
+ .satisfies(otherArtifactAvailableVersions -> {
+ assertThat(artifactAvailableVersions)
+ .isNotSameAs(otherArtifactAvailableVersions);
+ assertThat(artifactAvailableVersions)
+ .isNotEqualTo(otherArtifactAvailableVersions);
+ assertThat(artifactAvailableVersions)
+ .doesNotHaveSameHashCodeAs(otherArtifactAvailableVersions);
+ assertThat(artifactAvailableVersions)
+ .doesNotHaveToString(otherArtifactAvailableVersions.toString());
+ });
+ assertThat(new ArtifactAvailableVersions(ARTIFACT, OTHER_AVAILABLE_VERSIONS))
+ .satisfies(otherArtifactAvailableVersions -> {
+ assertThat(artifactAvailableVersions)
+ .isNotSameAs(otherArtifactAvailableVersions);
+ assertThat(artifactAvailableVersions)
+ .isNotEqualTo(otherArtifactAvailableVersions);
+ assertThat(artifactAvailableVersions)
+ .doesNotHaveSameHashCodeAs(otherArtifactAvailableVersions);
+ assertThat(artifactAvailableVersions)
+ .doesNotHaveToString(otherArtifactAvailableVersions.toString());
+ });
+ }
+
+ @Test
+ void testGetArtifact() {
+ assertThat(artifactAvailableVersions.getArtifact()).isEqualTo(ARTIFACT);
+ }
+
+ @Test
+ void testGetAvailableVersions() {
+ assertThat(artifactAvailableVersions.getAvailableVersions()).isEqualTo(AVAILABLE_VERSIONS);
+ }
+
+ @Test
+ void testGetAvailableVersionsImmutable() {
+ final var availableVersions = artifactAvailableVersions.getAvailableVersions();
+ assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(availableVersions::clear);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersionTest.java
new file mode 100644
index 0000000..0d1c087
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersionTest.java
@@ -0,0 +1,91 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class ArtifactUpdateVersionTest {
+
+ private static final Artifact> ARTIFACT = new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("foo-group-id", "foo-artifact-id")
+ );
+ private static final String UPDATE_VERSION = "foo-version";
+ private static final Artifact> OTHER_ARTIFACT = new Artifact<>(
+ MavenArtifactType.BUILD_PLUGIN,
+ new ArtifactIdentifier("bar-group-id", "bar-artifact-id")
+ );
+ private static final String OTHER_UPDATE_VERSION = "bar-version";
+
+ private final ArtifactUpdateVersion artifactUpdateVersion = new ArtifactUpdateVersion(ARTIFACT, UPDATE_VERSION);
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> new ArtifactUpdateVersion(null, UPDATE_VERSION));
+ assertThatNullPointerException().isThrownBy(() -> new ArtifactUpdateVersion(ARTIFACT, null));
+ assertThatIllegalArgumentException().isThrownBy(() -> new ArtifactUpdateVersion(ARTIFACT, Strings.EMPTY));
+ }
+
+ @Test
+ void testEqualsAndHashCodeAndToString() {
+ assertThat(artifactUpdateVersion.equals(artifactUpdateVersion)).isTrue();
+ assertThat(artifactUpdateVersion).isNotEqualTo(new Object());
+ assertThat(new ArtifactUpdateVersion(ARTIFACT, UPDATE_VERSION)).satisfies(otherArtifactUpdateVersion -> {
+ assertThat(artifactUpdateVersion).isNotSameAs(otherArtifactUpdateVersion);
+ assertThat(artifactUpdateVersion).isEqualTo(otherArtifactUpdateVersion);
+ assertThat(artifactUpdateVersion).hasSameHashCodeAs(otherArtifactUpdateVersion);
+ assertThat(artifactUpdateVersion).hasToString(otherArtifactUpdateVersion.toString());
+ });
+ assertThat(new ArtifactUpdateVersion(OTHER_ARTIFACT, UPDATE_VERSION)).satisfies(otherArtifactUpdateVersion -> {
+ assertThat(artifactUpdateVersion).isNotSameAs(otherArtifactUpdateVersion);
+ assertThat(artifactUpdateVersion).isNotEqualTo(otherArtifactUpdateVersion);
+ assertThat(artifactUpdateVersion).doesNotHaveSameHashCodeAs(otherArtifactUpdateVersion);
+ assertThat(artifactUpdateVersion).doesNotHaveToString(otherArtifactUpdateVersion.toString());
+ });
+ assertThat(new ArtifactUpdateVersion(ARTIFACT, OTHER_UPDATE_VERSION)).satisfies(otherArtifactUpdateVersion -> {
+ assertThat(artifactUpdateVersion).isNotSameAs(otherArtifactUpdateVersion);
+ assertThat(artifactUpdateVersion).isNotEqualTo(otherArtifactUpdateVersion);
+ assertThat(artifactUpdateVersion).doesNotHaveSameHashCodeAs(otherArtifactUpdateVersion);
+ assertThat(artifactUpdateVersion).doesNotHaveToString(otherArtifactUpdateVersion.toString());
+ });
+ }
+
+ @Test
+ void testGetArtifact() {
+ assertThat(artifactUpdateVersion.getArtifact()).isEqualTo(ARTIFACT);
+ }
+
+ @Test
+ void testGetUpdateVersion() {
+ assertThat(artifactUpdateVersion.getUpdateVersion()).isEqualTo(UPDATE_VERSION);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverIT.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverIT.java
new file mode 100644
index 0000000..f1fd4e6
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverIT.java
@@ -0,0 +1,120 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import com.github.alexisjehan.mavencheck.core.component.session.MavenSession;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+final class MavenArtifactAvailableVersionsResolverIT {
+
+ private final MavenArtifactAvailableVersionsResolver mavenArtifactAvailableVersionsResolver
+ = new MavenArtifactAvailableVersionsResolver(new MavenSession());
+
+ @Test
+ void testResolve() {
+ assertThat(
+ new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("org.apache.maven", "maven-core")
+ )
+ ).satisfies(artifact -> {
+ assertThat(
+ mavenArtifactAvailableVersionsResolver.resolve(
+ artifact,
+ List.of()
+ ).getAvailableVersions()
+ ).isEmpty();
+ assertThat(
+ mavenArtifactAvailableVersionsResolver.resolve(
+ artifact,
+ List.of(
+ new Repository(
+ RepositoryType.NORMAL,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ )
+ )
+ ).getAvailableVersions()
+ ).isNotEmpty();
+ assertThat(
+ mavenArtifactAvailableVersionsResolver.resolve(
+ artifact,
+ List.of(
+ new Repository(
+ RepositoryType.PLUGIN,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ )
+ )
+ ).getAvailableVersions()
+ ).isEmpty();
+ });
+ assertThat(
+ new Artifact<>(
+ MavenArtifactType.BUILD_PLUGIN,
+ new ArtifactIdentifier("org.apache.maven.plugins", "maven-compiler-plugin")
+ )
+ ).satisfies(artifact -> {
+ assertThat(
+ mavenArtifactAvailableVersionsResolver.resolve(
+ artifact,
+ List.of()
+ ).getAvailableVersions()
+ ).isEmpty();
+ assertThat(
+ mavenArtifactAvailableVersionsResolver.resolve(
+ artifact,
+ List.of(
+ new Repository(
+ RepositoryType.NORMAL,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ )
+ )
+ ).getAvailableVersions()
+ ).isNotEmpty();
+ assertThat(
+ mavenArtifactAvailableVersionsResolver.resolve(
+ artifact,
+ List.of(
+ new Repository(
+ RepositoryType.PLUGIN,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ )
+ )
+ ).getAvailableVersions()
+ ).isNotEmpty();
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverTest.java
new file mode 100644
index 0000000..42205a1
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverTest.java
@@ -0,0 +1,160 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactAvailableVersions;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import com.github.alexisjehan.mavencheck.core.component.session.MavenSession;
+import org.eclipse.aether.resolution.VersionRangeRequest;
+import org.eclipse.aether.resolution.VersionRangeResolutionException;
+import org.eclipse.aether.resolution.VersionRangeResult;
+import org.eclipse.aether.version.Version;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.AdditionalAnswers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+@ExtendWith(MockitoExtension.class)
+final class MavenArtifactAvailableVersionsResolverTest {
+
+ private static final class SimpleVersion implements Version {
+
+ private final String string;
+
+ private SimpleVersion(final String string) {
+ this.string = string;
+ }
+
+ @Override
+ public int compareTo(final Version o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return string;
+ }
+ }
+
+ @Mock
+ private MavenSession mockedMavenSession;
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> new MavenArtifactAvailableVersionsResolver(null));
+ }
+
+ @Test
+ void testResolve() throws VersionRangeResolutionException {
+ final var versionRangeResult = new VersionRangeResult(new VersionRangeRequest());
+ versionRangeResult.setVersions(
+ List.of(
+ new SimpleVersion("foo-version1"),
+ new SimpleVersion("foo-version2")
+ )
+ );
+ versionRangeResult.addException(new RuntimeException());
+ Mockito.when(mockedMavenSession.resolve(Mockito.notNull()))
+ .then(AdditionalAnswers.returnsFirstArg());
+ Mockito.when(mockedMavenSession.request(Mockito.notNull()))
+ .thenReturn(versionRangeResult);
+ final var mavenArtifactAvailableVersionsResolver = new MavenArtifactAvailableVersionsResolver(
+ mockedMavenSession
+ );
+ final var repositories = List.of(
+ new Repository(RepositoryType.NORMAL, "foo-id", "https://foo-host"),
+ new Repository(RepositoryType.PLUGIN, "foo-plugin-id", "https://foo-plugin-host")
+ );
+ assertThat(
+ new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("foo-group-id", "foo-artifact-id"),
+ "foo-version"
+ )
+ ).satisfies(
+ artifact -> assertThat(mavenArtifactAvailableVersionsResolver.resolve(artifact, repositories))
+ .isEqualTo(new ArtifactAvailableVersions(artifact, List.of("foo-version1", "foo-version2")))
+ );
+ assertThat(
+ new Artifact<>(
+ MavenArtifactType.BUILD_PLUGIN,
+ new ArtifactIdentifier("foo-plugin-group-id", "foo-plugin-artifact-id"),
+ "foo-plugin-version"
+ )
+ ).satisfies(
+ artifact -> assertThat(mavenArtifactAvailableVersionsResolver.resolve(artifact, repositories))
+ .isEqualTo(new ArtifactAvailableVersions(artifact, List.of("foo-version1", "foo-version2")))
+ );
+ }
+
+ @Test
+ void testResolveInvalid() throws VersionRangeResolutionException {
+ Mockito.when(mockedMavenSession.resolve(Mockito.notNull()))
+ .then(AdditionalAnswers.returnsFirstArg());
+ Mockito.when(mockedMavenSession.request(Mockito.notNull()))
+ .thenThrow(VersionRangeResolutionException.class);
+ final var mavenArtifactAvailableVersionsResolver = new MavenArtifactAvailableVersionsResolver(
+ mockedMavenSession
+ );
+ final var artifact = new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("foo-group-id", "foo-artifact-id"),
+ "foo-version"
+ );
+ final var repositories = List.of(
+ new Repository(RepositoryType.NORMAL, "foo-id", "https://foo-host"),
+ new Repository(RepositoryType.PLUGIN, "foo-plugin-id", "https://foo-plugin-host")
+ );
+ assertThatNullPointerException()
+ .isThrownBy(
+ () -> mavenArtifactAvailableVersionsResolver.resolve(null, repositories)
+ );
+ assertThatNullPointerException()
+ .isThrownBy(
+ () -> mavenArtifactAvailableVersionsResolver.resolve(artifact, null)
+ );
+ assertThatNullPointerException()
+ .isThrownBy(
+ () -> mavenArtifactAvailableVersionsResolver.resolve(artifact, Collections.singletonList(null))
+ );
+ assertThatExceptionOfType(AssertionError.class)
+ .isThrownBy(
+ () -> mavenArtifactAvailableVersionsResolver.resolve(artifact, repositories)
+ )
+ .withCauseInstanceOf(VersionRangeResolutionException.class);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/BuildTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/BuildTest.java
new file mode 100644
index 0000000..91b7b69
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/BuildTest.java
@@ -0,0 +1,151 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class BuildTest {
+
+ private static final BuildFile FILE = new BuildFile(BuildFileType.MAVEN, Path.of("foo-file"));
+ private static final List REPOSITORIES = List.of(
+ new Repository(RepositoryType.NORMAL, "foo-id", "https://foo-host")
+ );
+ private static final List> ARTIFACTS = List.of(
+ new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("foo-group-id", "foo-artifact-id"),
+ "foo-version"
+ )
+ );
+ private static final BuildFile OTHER_FILE = new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("bar-file"));
+ private static final List OTHER_REPOSITORIES = List.of(
+ new Repository(RepositoryType.PLUGIN, "bar-id", "https://bar-host")
+ );
+ private static final List> OTHER_ARTIFACTS = List.of(
+ new Artifact<>(
+ MavenArtifactType.BUILD_PLUGIN,
+ new ArtifactIdentifier("bar-group-id", "bar-artifact-id")
+ )
+ );
+
+ private final Build build = new Build(FILE, REPOSITORIES, ARTIFACTS);
+
+ @Test
+ void testConstructorImmutable() {
+ final var repositories = new ArrayList<>(REPOSITORIES);
+ final var artifacts = new ArrayList<>(ARTIFACTS);
+ final var build = new Build(FILE, repositories, artifacts);
+ repositories.clear();
+ artifacts.clear();
+ assertThat(build.getRepositories()).containsExactlyElementsOf(REPOSITORIES);
+ assertThat(build.getArtifacts()).containsExactlyElementsOf(ARTIFACTS);
+ }
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException()
+ .isThrownBy(() -> new Build(null, REPOSITORIES, ARTIFACTS));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new Build(FILE, null, ARTIFACTS));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new Build(FILE, Collections.singletonList(null), ARTIFACTS));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new Build(FILE, REPOSITORIES, null));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new Build(FILE, REPOSITORIES, Collections.singletonList(null)));
+ }
+
+ @Test
+ void testEqualsAndHashCodeAndToString() {
+ assertThat(build.equals(build)).isTrue();
+ assertThat(build).isNotEqualTo(new Object());
+ assertThat(new Build(FILE, REPOSITORIES, ARTIFACTS)).satisfies(otherBuild -> {
+ assertThat(build).isNotSameAs(otherBuild);
+ assertThat(build).isEqualTo(otherBuild);
+ assertThat(build).hasSameHashCodeAs(otherBuild);
+ assertThat(build).hasToString(otherBuild.toString());
+ });
+ assertThat(new Build(OTHER_FILE, REPOSITORIES, ARTIFACTS)).satisfies(otherBuild -> {
+ assertThat(build).isNotSameAs(otherBuild);
+ assertThat(build).isNotEqualTo(otherBuild);
+ assertThat(build).doesNotHaveSameHashCodeAs(otherBuild);
+ assertThat(build).doesNotHaveToString(otherBuild.toString());
+ });
+ assertThat(new Build(FILE, OTHER_REPOSITORIES, ARTIFACTS)).satisfies(otherBuild -> {
+ assertThat(build).isNotSameAs(otherBuild);
+ assertThat(build).isNotEqualTo(otherBuild);
+ assertThat(build).doesNotHaveSameHashCodeAs(otherBuild);
+ assertThat(build).doesNotHaveToString(otherBuild.toString());
+ });
+ assertThat(new Build(FILE, REPOSITORIES, OTHER_ARTIFACTS)).satisfies(otherBuild -> {
+ assertThat(build).isNotSameAs(otherBuild);
+ assertThat(build).isNotEqualTo(otherBuild);
+ assertThat(build).doesNotHaveSameHashCodeAs(otherBuild);
+ assertThat(build).doesNotHaveToString(otherBuild.toString());
+ });
+ }
+
+ @Test
+ void testGetFile() {
+ assertThat(build.getFile()).isEqualTo(FILE);
+ }
+
+ @Test
+ void testGetRepositories() {
+ assertThat(build.getRepositories()).isEqualTo(REPOSITORIES);
+ }
+
+ @Test
+ void testGetRepositoriesImmutable() {
+ final var repositories = build.getRepositories();
+ assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(repositories::clear);
+ }
+
+ @Test
+ void testGetArtifacts() {
+ assertThat(build.getArtifacts()).isEqualTo(ARTIFACTS);
+ }
+
+ @Test
+ void testGetArtifactsImmutable() {
+ final var artifacts = build.getArtifacts();
+ assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(artifacts::clear);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTest.java
new file mode 100644
index 0000000..7d7f1c7
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTest.java
@@ -0,0 +1,81 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.file;
+
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class BuildFileTest {
+
+ private static final BuildFileType TYPE = BuildFileType.MAVEN;
+ private static final Path FILE = Path.of("foo-file");
+ private static final BuildFileType OTHER_TYPE = BuildFileType.GRADLE_GROOVY;
+ private static final Path OTHER_FILE = Path.of("bar-file");
+
+ private final BuildFile buildFile = new BuildFile(TYPE, FILE);
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> new BuildFile(null, FILE));
+ assertThatNullPointerException().isThrownBy(() -> new BuildFile(TYPE, null));
+ }
+
+ @Test
+ void testEqualsAndHashCodeAndToString() {
+ assertThat(buildFile.equals(buildFile)).isTrue();
+ assertThat(buildFile).isNotEqualTo(new Object());
+ assertThat(new BuildFile(TYPE, FILE)).satisfies(otherBuildFile -> {
+ assertThat(buildFile).isNotSameAs(otherBuildFile);
+ assertThat(buildFile).isEqualTo(otherBuildFile);
+ assertThat(buildFile).hasSameHashCodeAs(otherBuildFile);
+ assertThat(buildFile).hasToString(otherBuildFile.toString());
+ });
+ assertThat(new BuildFile(OTHER_TYPE, FILE)).satisfies(otherBuildFile -> {
+ assertThat(buildFile).isNotSameAs(otherBuildFile);
+ assertThat(buildFile).isNotEqualTo(otherBuildFile);
+ assertThat(buildFile).doesNotHaveSameHashCodeAs(otherBuildFile);
+ assertThat(buildFile).doesNotHaveToString(otherBuildFile.toString());
+ });
+ assertThat(new BuildFile(TYPE, OTHER_FILE)).satisfies(otherBuildFile -> {
+ assertThat(buildFile).isNotSameAs(otherBuildFile);
+ assertThat(buildFile).isNotEqualTo(otherBuildFile);
+ assertThat(buildFile).doesNotHaveSameHashCodeAs(otherBuildFile);
+ assertThat(buildFile).doesNotHaveToString(otherBuildFile.toString());
+ });
+ }
+
+ @Test
+ void testGetType() {
+ assertThat(buildFile.getType()).isEqualTo(TYPE);
+ }
+
+ @Test
+ void testGetFile() {
+ assertThat(buildFile.getFile()).isEqualTo(FILE);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTypeTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTypeTest.java
new file mode 100644
index 0000000..e9a316d
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTypeTest.java
@@ -0,0 +1,51 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.file;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class BuildFileTypeTest {
+
+ @Test
+ void testGetFileName() {
+ assertThat(BuildFileType.MAVEN.getFileName()).isEqualTo("pom.xml");
+ }
+
+ @Test
+ void testOptionalValueOf() {
+ assertThat(BuildFileType.optionalValueOf("pom.xml")).hasValue(BuildFileType.MAVEN);
+ assertThat(BuildFileType.optionalValueOf("unknown")).isEmpty();
+ }
+
+ @Test
+ void testOptionalValueOfInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> BuildFileType.optionalValueOf(null));
+ assertThatIllegalArgumentException().isThrownBy(() -> BuildFileType.optionalValueOf(Strings.EMPTY));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveExceptionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveExceptionTest.java
new file mode 100644
index 0000000..132df1e
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveExceptionTest.java
@@ -0,0 +1,62 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
+
+import com.github.alexisjehan.javanilla.io.Serializables;
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class BuildResolveExceptionTest {
+
+ private static final String MESSAGE = "foo-message";
+ private static final Exception CAUSE = new Exception("foo-cause");
+
+ private final BuildResolveException buildResolveException1 = new BuildResolveException(MESSAGE);
+ private final BuildResolveException buildResolveException2 = new BuildResolveException(CAUSE);
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> {
+ throw new BuildResolveException((String) null);
+ });
+ assertThatIllegalArgumentException().isThrownBy(() -> {
+ throw new BuildResolveException(Strings.EMPTY);
+ });
+ assertThatNullPointerException().isThrownBy(() -> {
+ throw new BuildResolveException((Throwable) null);
+ });
+ }
+
+ @Test
+ void testSerializable() {
+ assertThat(Serializables.deserialize(Serializables.serialize(buildResolveException1)))
+ .hasSameClassAs(buildResolveException1);
+ assertThat(Serializables.deserialize(Serializables.serialize(buildResolveException2)))
+ .hasSameClassAs(buildResolveException2);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverIT.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverIT.java
new file mode 100644
index 0000000..2587226
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverIT.java
@@ -0,0 +1,392 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.GradleArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import com.github.alexisjehan.mavencheck.core.util.GradleUtils;
+import org.gradle.tooling.GradleConnector;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledForJreRange;
+import org.junit.jupiter.api.condition.JRE;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.Mockito;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+final class GradleBuildResolverIT {
+
+ private final GradleBuildResolver gradleBuildResolver = new GradleBuildResolver();
+
+ @Test
+ void testUpToDate() {
+ assertThat(GradleUtils.getVersion()).startsWith("7.6"); // Ensure tests are up-to-date after updating Gradle
+ }
+
+ @ParameterizedTest
+ @EnabledForJreRange(max = JRE.JAVA_13)
+ @ValueSource(strings = {"4.8", "4.9", "4.10", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "6.0", "6.1", "6.2"})
+ void testResolveUntilGradle67UntilJava13(final String gradleVersion, @TempDir final Path tmpDirectory) {
+ testResolveUntilGradle67(gradleVersion, tmpDirectory);
+ }
+
+ @ParameterizedTest
+ @EnabledForJreRange(max = JRE.JAVA_17)
+ @ValueSource(strings = {"6.3", "6.4", "6.5", "6.6", "6.7"})
+ void testResolveUntilGradle67UntilJava17(final String gradleVersion, @TempDir final Path tmpDirectory) {
+ testResolveUntilGradle67(gradleVersion, tmpDirectory);
+ }
+
+ @ParameterizedTest
+ @EnabledForJreRange(max = JRE.JAVA_17)
+ @ValueSource(strings = {"6.8", "6.9", "7.0", "7.1", "7.2"})
+ void testResolveSinceGradle68UntilJava17(final String gradleVersion, @TempDir final Path tmpDirectory) {
+ testResolveSinceGradle68(gradleVersion, tmpDirectory);
+ }
+
+ @ParameterizedTest
+ @EnabledForJreRange(max = JRE.JAVA_18)
+ @ValueSource(strings = {"7.3", "7.4", "7.5"})
+ void testResolveSinceGradle68UntilJava18(final String gradleVersion, @TempDir final Path tmpDirectory) {
+ testResolveSinceGradle68(gradleVersion, tmpDirectory);
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = "7.6")
+ void testResolveSinceGradle68UntilJavaLatest(final String gradleVersion, @TempDir final Path tmpDirectory) {
+ testResolveSinceGradle68(gradleVersion, tmpDirectory);
+ }
+
+ private void testResolveUntilGradle67(final String gradleVersion, final Path tmpDirectory) {
+ try (final var mockedGradleUtils = Mockito.mockStatic(GradleUtils.class)) {
+ mockedGradleUtils.when(GradleUtils::retrieveOptionalHome)
+ .thenReturn(Optional.empty());
+ assertThat(BuildFileType.GRADLE_GROOVY).satisfies(buildFileType -> {
+ final var connector = GradleConnector.newConnector()
+ .useGradleVersion(gradleVersion);
+ try (final var mockedGradleConnector = Mockito.mockStatic(GradleConnector.class)) {
+ mockedGradleConnector.when(GradleConnector::newConnector)
+ .thenReturn(connector);
+ final var tmpBuildDirectory = tmpDirectory.resolve("groovy");
+ Files.createDirectory(tmpBuildDirectory);
+ final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle");
+ final var tmpSettingsFile = tmpBuildDirectory.resolve("settings.gradle");
+ Files.copy(
+ Path.of("src", "test", "resources", "build_it.gradle"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ Files.copy(
+ Path.of("src", "test", "resources", "settings_it_until-6.7.gradle"),
+ tmpSettingsFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ final var build = gradleBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "MavenRepo",
+ "https://repo.maven.apache.org/maven2/"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "google",
+ "https://maven.google.com"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "maven",
+ "https://plugin-management.example.com"
+ )
+ );
+ assertThat(build.getArtifacts()).containsExactly(
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.android.material", "material"),
+ "1.0.0"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "10.0"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-jre"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-android"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("org.springframework", "spring-core"),
+ "3.0.0.RELEASE"
+ )
+ );
+ }
+ });
+ assertThat(BuildFileType.GRADLE_KOTLIN).satisfies(buildFileType -> {
+ final var connector = GradleConnector.newConnector()
+ .useGradleVersion(gradleVersion);
+ try (final var mockedGradleConnector = Mockito.mockStatic(GradleConnector.class)) {
+ mockedGradleConnector.when(GradleConnector::newConnector)
+ .thenReturn(connector);
+ final var tmpBuildDirectory = tmpDirectory.resolve("kotlin");
+ Files.createDirectory(tmpBuildDirectory);
+ final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle.kts");
+ final var tmpSettingsFile = tmpBuildDirectory.resolve("settings.gradle.kts");
+ Files.copy(
+ Path.of("src", "test", "resources", "build_it.gradle.kts"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ Files.copy(
+ Path.of("src", "test", "resources", "settings_it_until-6.7.gradle.kts"),
+ tmpSettingsFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ final var build = gradleBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "MavenRepo",
+ "https://repo.maven.apache.org/maven2/"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "google",
+ "https://maven.google.com"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "maven",
+ "https://plugin-management.example.com"
+ )
+ );
+ assertThat(build.getArtifacts()).containsExactly(
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.android.material", "material"),
+ "1.0.0"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "10.0"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-jre"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-android"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("org.springframework", "spring-core"),
+ "3.0.0.RELEASE"
+ )
+ );
+ }
+ });
+ }
+ }
+
+ private void testResolveSinceGradle68(final String gradleVersion, final Path tmpDirectory) {
+ try (final var mockedGradleUtils = Mockito.mockStatic(GradleUtils.class)) {
+ mockedGradleUtils.when(GradleUtils::retrieveOptionalHome)
+ .thenReturn(Optional.empty());
+ assertThat(BuildFileType.GRADLE_GROOVY).satisfies(buildFileType -> {
+ final var connector = GradleConnector.newConnector()
+ .useGradleVersion(gradleVersion);
+ try (final var mockedGradleConnector = Mockito.mockStatic(GradleConnector.class)) {
+ mockedGradleConnector.when(GradleConnector::newConnector)
+ .thenReturn(connector);
+ final var tmpBuildDirectory = tmpDirectory.resolve("groovy");
+ Files.createDirectory(tmpBuildDirectory);
+ final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle");
+ final var tmpSettingsFile = tmpBuildDirectory.resolve("settings.gradle");
+ Files.copy(
+ Path.of("src", "test", "resources", "build_it.gradle"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ Files.copy(
+ Path.of("src", "test", "resources", "settings_it_since-6.8.gradle"),
+ tmpSettingsFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ final var build = gradleBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "maven",
+ "https://dependency-resolution-management.example.com"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "MavenRepo",
+ "https://repo.maven.apache.org/maven2/"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "google",
+ "https://maven.google.com"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "maven",
+ "https://plugin-management.example.com"
+ )
+ );
+ assertThat(build.getArtifacts()).containsExactly(
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.android.material", "material"),
+ "1.0.0"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "10.0"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-jre"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-android"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("org.springframework", "spring-core"),
+ "3.0.0.RELEASE"
+ )
+ );
+ }
+ });
+ assertThat(BuildFileType.GRADLE_KOTLIN).satisfies(buildFileType -> {
+ final var connector = GradleConnector.newConnector()
+ .useGradleVersion(gradleVersion);
+ try (final var mockedGradleConnector = Mockito.mockStatic(GradleConnector.class)) {
+ mockedGradleConnector.when(GradleConnector::newConnector)
+ .thenReturn(connector);
+ final var tmpBuildDirectory = tmpDirectory.resolve("kotlin");
+ Files.createDirectory(tmpBuildDirectory);
+ final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle.kts");
+ final var tmpSettingsFile = tmpBuildDirectory.resolve("settings.gradle.kts");
+ Files.copy(
+ Path.of("src", "test", "resources", "build_it.gradle.kts"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ Files.copy(
+ Path.of("src", "test", "resources", "settings_it_since-6.8.gradle.kts"),
+ tmpSettingsFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ final var build = gradleBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "maven",
+ "https://dependency-resolution-management.example.com"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "MavenRepo",
+ "https://repo.maven.apache.org/maven2/"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "google",
+ "https://maven.google.com"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "maven",
+ "https://plugin-management.example.com"
+ )
+ );
+ assertThat(build.getArtifacts()).containsExactly(
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.android.material", "material"),
+ "1.0.0"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "10.0"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-jre"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-android"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier("org.springframework", "spring-core"),
+ "3.0.0.RELEASE"
+ )
+ );
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverTest.java
new file mode 100644
index 0000000..d5b8e2a
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverTest.java
@@ -0,0 +1,1026 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.GradleArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import com.github.alexisjehan.mavencheck.core.util.GradleUtils;
+import org.gradle.tooling.GradleConnectionException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.mockito.Mockito;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class GradleBuildResolverTest {
+
+ private final GradleBuildResolver gradleBuildResolver = new GradleBuildResolver();
+
+ @Test
+ void testResolve(@TempDir final Path tmpDirectory) {
+ assertThat(BuildFileType.GRADLE_GROOVY).satisfies(buildFileType -> {
+ final var tmpBuildDirectory = tmpDirectory.resolve("groovy");
+ Files.createDirectory(tmpBuildDirectory);
+ final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle");
+ Files.copy(
+ Path.of("src", "test", "resources", "build_foo.gradle"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ final var build = gradleBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "MavenRepo",
+ "https://repo.maven.apache.org/maven2/"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "foo-repository-name",
+ "https://foo-repository-host"
+ )
+ );
+ assertThat(build.getArtifacts()).containsExactly(
+ new Artifact<>(
+ GradleArtifactType.ANNOTATION_PROCESSOR,
+ new ArtifactIdentifier(
+ "foo-annotation-processor-group-id",
+ "foo-annotation-processor-artifact-id"
+ ),
+ "foo-annotation-processor-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.API,
+ new ArtifactIdentifier(
+ "foo-api-group-id",
+ "foo-api-artifact-id"
+ ),
+ "foo-api-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.COMPILE_ONLY,
+ new ArtifactIdentifier(
+ "foo-compile-only-group-id",
+ "foo-compile-only-artifact-id"
+ ),
+ "foo-compile-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.COMPILE_ONLY_API,
+ new ArtifactIdentifier(
+ "foo-compile-only-api-group-id",
+ "foo-compile-only-api-artifact-id"
+ ),
+ "foo-compile-only-api-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-implementation-group-id",
+ "foo-implementation-artifact-id"
+ ),
+ "foo-implementation-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-runtime-only-group-id",
+ "foo-runtime-only-artifact-id"
+ ),
+ "foo-runtime-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_ANNOTATION_PROCESSOR,
+ new ArtifactIdentifier(
+ "foo-test-annotation-processor-group-id",
+ "foo-test-annotation-processor-artifact-id"
+ ),
+ "foo-test-annotation-processor-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_COMPILE_ONLY,
+ new ArtifactIdentifier(
+ "foo-test-compile-only-group-id",
+ "foo-test-compile-only-artifact-id"
+ ),
+ "foo-test-compile-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-test-implementation-group-id",
+ "foo-test-implementation-artifact-id"
+ ),
+ "foo-test-implementation-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-test-runtime-only-group-id",
+ "foo-test-runtime-only-artifact-id"
+ ),
+ "foo-test-runtime-only-version"
+ )
+ );
+ });
+ assertThat(BuildFileType.GRADLE_KOTLIN).satisfies(buildFileType -> {
+ final var tmpBuildDirectory = tmpDirectory.resolve("kotlin");
+ Files.createDirectory(tmpBuildDirectory);
+ final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle.kts");
+ Files.copy(
+ Path.of("src", "test", "resources", "build_foo.gradle.kts"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ final var build = gradleBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "MavenRepo",
+ "https://repo.maven.apache.org/maven2/"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "foo-repository-name",
+ "https://foo-repository-host"
+ )
+ );
+ assertThat(build.getArtifacts()).containsExactly(
+ new Artifact<>(
+ GradleArtifactType.ANNOTATION_PROCESSOR,
+ new ArtifactIdentifier(
+ "foo-annotation-processor-group-id",
+ "foo-annotation-processor-artifact-id"
+ ),
+ "foo-annotation-processor-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.API,
+ new ArtifactIdentifier(
+ "foo-api-group-id",
+ "foo-api-artifact-id"
+ ),
+ "foo-api-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.COMPILE_ONLY,
+ new ArtifactIdentifier(
+ "foo-compile-only-group-id",
+ "foo-compile-only-artifact-id"
+ ),
+ "foo-compile-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.COMPILE_ONLY_API,
+ new ArtifactIdentifier(
+ "foo-compile-only-api-group-id",
+ "foo-compile-only-api-artifact-id"
+ ),
+ "foo-compile-only-api-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-implementation-group-id",
+ "foo-implementation-artifact-id"
+ ),
+ "foo-implementation-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-runtime-only-group-id",
+ "foo-runtime-only-artifact-id"
+ ),
+ "foo-runtime-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_ANNOTATION_PROCESSOR,
+ new ArtifactIdentifier(
+ "foo-test-annotation-processor-group-id",
+ "foo-test-annotation-processor-artifact-id"
+ ),
+ "foo-test-annotation-processor-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_COMPILE_ONLY,
+ new ArtifactIdentifier(
+ "foo-test-compile-only-group-id",
+ "foo-test-compile-only-artifact-id"
+ ),
+ "foo-test-compile-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-test-implementation-group-id",
+ "foo-test-implementation-artifact-id"
+ ),
+ "foo-test-implementation-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-test-runtime-only-group-id",
+ "foo-test-runtime-only-artifact-id"
+ ),
+ "foo-test-runtime-only-version"
+ )
+ );
+ });
+ }
+
+ @Test
+ void testResolveInvalid(@TempDir final Path tmpDirectory) {
+ assertThatNullPointerException().isThrownBy(() -> gradleBuildResolver.resolve(null));
+ assertThat(BuildFileType.GRADLE_GROOVY).satisfies(buildFileType -> {
+ final var tmpBuildDirectory = tmpDirectory.resolve("groovy");
+ Files.createDirectory(tmpBuildDirectory);
+ assertThat(tmpBuildDirectory.resolve("build_not-found.gradle")).satisfies(tmpBuildFile -> {
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> gradleBuildResolver.resolve(buildFile))
+ .withCauseInstanceOf(GradleConnectionException.class);
+ });
+ assertThat(tmpBuildDirectory.resolve("build.gradle")).satisfies(tmpBuildFile -> {
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ Files.copy(
+ Path.of("src", "test", "resources", "build_error.gradle"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> gradleBuildResolver.resolve(buildFile))
+ .withCauseInstanceOf(GradleConnectionException.class);
+ try (final var mockedGradleUtils = Mockito.mockStatic(GradleUtils.class)) {
+ mockedGradleUtils.when(GradleUtils::retrieveOptionalHome)
+ .thenReturn(Optional.of("directory_not-found"));
+ Files.copy(
+ Path.of("src", "test", "resources", "build_foo.gradle"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> gradleBuildResolver.resolve(buildFile))
+ .withCauseInstanceOf(GradleConnectionException.class);
+ }
+ });
+ });
+ assertThat(BuildFileType.GRADLE_KOTLIN).satisfies(buildFileType -> {
+ final var tmpBuildDirectory = tmpDirectory.resolve("kotlin");
+ Files.createDirectory(tmpBuildDirectory);
+ assertThat(tmpBuildDirectory.resolve("build_not-found.gradle.kts")).satisfies(tmpBuildFile -> {
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> gradleBuildResolver.resolve(buildFile))
+ .withCauseInstanceOf(GradleConnectionException.class);
+ });
+ assertThat(tmpBuildDirectory.resolve("build.gradle.kts")).satisfies(tmpBuildFile -> {
+ final var buildFile = new BuildFile(buildFileType, tmpBuildFile);
+ Files.copy(
+ Path.of("src", "test", "resources", "build_error.gradle.kts"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> gradleBuildResolver.resolve(buildFile))
+ .withCauseInstanceOf(GradleConnectionException.class);
+ try (final var mockedGradleUtils = Mockito.mockStatic(GradleUtils.class)) {
+ mockedGradleUtils.when(GradleUtils::retrieveOptionalHome)
+ .thenReturn(Optional.of("directory_not-found"));
+ Files.copy(
+ Path.of("src", "test", "resources", "build_foo.gradle.kts"),
+ tmpBuildFile,
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> gradleBuildResolver.resolve(buildFile))
+ .withCauseInstanceOf(GradleConnectionException.class);
+ }
+ });
+ });
+ }
+
+ @Test
+ void testGetFileTypes() {
+ assertThat(gradleBuildResolver.getFileTypes()).contains(
+ BuildFileType.GRADLE_GROOVY,
+ BuildFileType.GRADLE_KOTLIN
+ );
+ }
+
+ @Test
+ void testParseRepositories() throws IOException {
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "\n"
+ )
+ )
+ ) {
+ assertThat(GradleBuildResolver.parseRepositories(bufferedReader)).isEmpty();
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :repositories\n"
+ + "NORMAL:foo-repository-name:https://foo-repository-host\n"
+ + "PLUGIN:foo-plugin-repository-name:https://foo-plugin-repository-host"
+ )
+ )
+ ) {
+ assertThat(GradleBuildResolver.parseRepositories(bufferedReader)).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "foo-repository-name",
+ "https://foo-repository-host"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "foo-plugin-repository-name",
+ "https://foo-plugin-repository-host"
+ )
+ );
+ }
+ }
+
+ @Test
+ void testParseRepositoriesInvalid() throws IOException {
+ assertThatNullPointerException()
+ .isThrownBy(() -> GradleBuildResolver.parseRepositories(null));
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :repositories\n"
+ + "NORMAL:foo-repository-name"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseRepositories(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :repositories\n"
+ + "UNKNOWN:foo-repository-name:https://foo-repository-host"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseRepositories(bufferedReader));
+ }
+ }
+
+ @Test
+ void testParseArtifacts() throws IOException {
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "\n"
+ )
+ )
+ ) {
+ assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty();
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project\n" // Until Gradle 6.7
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "api - API dependencies for source set 'main'. (n)"
+ )
+ )
+ ) {
+ assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty();
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project 'foo-project'\n" // Since Gradle 6.8
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "api - API dependencies for source set 'main'. (n)"
+ )
+ )
+ ) {
+ assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty();
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project\n" // Until Gradle 6.7
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "api - API dependencies for source set 'main'. (n)\n"
+ + "No dependencies\n"
+ + "\n"
+ + "apiElements - API elements for main. (n)"
+ )
+ )
+ ) {
+ assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty();
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project 'foo-project'\n" // Since Gradle 6.8
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "api - API dependencies for source set 'main'. (n)\n"
+ + "No dependencies\n"
+ + "\n"
+ + "apiElements - API elements for main. (n)"
+ )
+ )
+ ) {
+ assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty();
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project\n" // Until Gradle 6.7
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "api - API dependencies for source set 'main'. (n)\n"
+ + "No dependencies\n"
+ + "\n"
+ + "apiElements - API elements for main. (n)\n"
+ + "No dependencies\n"
+ + "\n"
+ + "compileOnly - Compile only dependencies for source set 'main'. (n)\n"
+ + "+--- foo-compile-only-group-id:foo-compile-only-artifact-id:"
+ + "foo-compile-only-version (n)\n"
+ + "| \\--- sub-foo-compile-only-group-id:"
+ + "sub-foo-compile-only-artifact-id -> sub-foo-compile-only-version (n)\n"
+ + "\\--- bar-compile-only-group-id:bar-compile-only-artifact-id (n)\n"
+ + " \\--- sub-bar-compile-only-group-id:"
+ + "sub-bar-compile-only-artifact-id (n)\n"
+ + "\n"
+ + "A web-based, searchable dependency report is available by adding the --scan "
+ + "option."
+ )
+ )
+ ) {
+ assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).containsExactly(
+ new Artifact<>(
+ GradleArtifactType.COMPILE_ONLY,
+ new ArtifactIdentifier(
+ "foo-compile-only-group-id",
+ "foo-compile-only-artifact-id"
+ ),
+ "foo-compile-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.COMPILE_ONLY,
+ new ArtifactIdentifier(
+ "bar-compile-only-group-id",
+ "bar-compile-only-artifact-id"
+ )
+ )
+ );
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project 'foo-project'\n" // Since Gradle 6.8
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "api - API dependencies for source set 'main'. (n)\n"
+ + "No dependencies\n"
+ + "\n"
+ + "apiElements - API elements for main. (n)\n"
+ + "No dependencies\n"
+ + "\n"
+ + "compileOnly - Compile only dependencies for source set 'main'. (n)\n"
+ + "+--- foo-compile-only-group-id:foo-compile-only-artifact-id:"
+ + "foo-compile-only-version (n)\n"
+ + "| \\--- sub-foo-compile-only-group-id:"
+ + "sub-foo-compile-only-artifact-id -> sub-foo-compile-only-version (n)\n"
+ + "\\--- bar-compile-only-group-id:bar-compile-only-artifact-id (n)\n"
+ + " \\--- sub-bar-compile-only-group-id:"
+ + "sub-bar-compile-only-artifact-id (n)\n"
+ + "\n"
+ + "A web-based, searchable dependency report is available by adding the --scan "
+ + "option."
+ )
+ )
+ ) {
+ assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).containsExactly(
+ new Artifact<>(
+ GradleArtifactType.COMPILE_ONLY,
+ new ArtifactIdentifier(
+ "foo-compile-only-group-id",
+ "foo-compile-only-artifact-id"
+ ),
+ "foo-compile-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.COMPILE_ONLY,
+ new ArtifactIdentifier(
+ "bar-compile-only-group-id",
+ "bar-compile-only-artifact-id"
+ )
+ )
+ );
+ }
+ }
+
+ @Test
+ void testParseArtifactsInvalid() throws IOException {
+ assertThatNullPointerException()
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(null));
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project" // Until Gradle 6.7
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project 'foo-project'" // Since Gradle 6.8
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project\n" // Until Gradle 6.7
+ + "------------------------------------------------------------"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project 'foo-project'\n" // Since Gradle 6.8
+ + "------------------------------------------------------------"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project\n" // Until Gradle 6.7
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "compileOnly - Compile only dependencies for source set 'main'. (n)\n"
+ + "???? foo-compile-only-group-id:foo-compile-only-artifact-id:"
+ + "foo-compile-only-version (n)"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project 'foo-project'\n" // Since Gradle 6.8
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "compileOnly - Compile only dependencies for source set 'main'. (n)\n"
+ + "???? foo-compile-only-group-id:foo-compile-only-artifact-id:"
+ + "foo-compile-only-version (n)"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project\n" // Until Gradle 6.7
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "compileOnly - Compile only dependencies for source set 'main'. (n)\n"
+ + "+--- foo-compile-only-group-id (n)"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project 'foo-project'\n" // Since Gradle 6.8
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "compileOnly - Compile only dependencies for source set 'main'. (n)\n"
+ + "+--- foo-compile-only-group-id (n)"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project\n" // Until Gradle 6.7
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "compileOnly - Compile only dependencies for source set 'main'. (n)\n"
+ + "+--- foo-compile-only-group-id:foo-compile-only-artifact-id:"
+ + "foo-compile-only-version:foo (n)"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ try (
+ final var bufferedReader = new BufferedReader(
+ new StringReader(
+ "> Task :dependencies\n"
+ + "\n"
+ + "------------------------------------------------------------\n"
+ + "Root project 'foo-project'\n" // Since Gradle 6.8
+ + "------------------------------------------------------------\n"
+ + "\n"
+ + "compileOnly - Compile only dependencies for source set 'main'. (n)\n"
+ + "+--- foo-compile-only-group-id:foo-compile-only-artifact-id:"
+ + "foo-compile-only-version:foo (n)"
+ )
+ )
+ ) {
+ assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader));
+ }
+ }
+
+ @Test
+ void testFilter() {
+ final var list = Stream.of(
+ // Deprecated or classpath duplicates to be removed
+ new Artifact<>(
+ GradleArtifactType.COMPILE_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-implementation-group-id",
+ "foo-implementation-artifact-id"
+ ),
+ "foo-implementation-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.RUNTIME_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-runtime-only-group-id",
+ "foo-runtime-only-artifact-id"
+ ),
+ "foo-runtime-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_COMPILE_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-test-implementation-group-id",
+ "foo-test-implementation-artifact-id"
+ ),
+ "foo-test-implementation-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-test-runtime-only-group-id",
+ "foo-test-runtime-only-artifact-id"
+ ),
+ "foo-test-runtime-only-version"
+ ),
+
+ // "COMPILE_CLASSPATH" duplicates to be removed
+ new Artifact<>(
+ GradleArtifactType.RUNTIME_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-compile-classpath-group-id",
+ "foo-compile-classpath-artifact-id"
+ ),
+ "foo-compile-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_COMPILE_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-compile-classpath-group-id",
+ "foo-compile-classpath-artifact-id"
+ ),
+ "foo-compile-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-compile-classpath-group-id",
+ "foo-compile-classpath-artifact-id"
+ ),
+ "foo-compile-classpath-version"
+ ),
+
+ // "RUNTIME_CLASSPATH" duplicates to be removed
+ new Artifact<>(
+ GradleArtifactType.TEST_COMPILE_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-runtime-classpath-group-id",
+ "foo-runtime-classpath-artifact-id"
+ ),
+ "foo-runtime-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-runtime-classpath-group-id",
+ "foo-runtime-classpath-artifact-id"
+ ),
+ "foo-runtime-classpath-version"
+ ),
+
+ // "TEST_COMPILE_CLASSPATH" duplicates to be removed
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-test-compile-classpath-group-id",
+ "foo-test-compile-classpath-artifact-id"
+ ),
+ "foo-test-compile-classpath-version"
+ ),
+
+ // "COMPILE_CLASSPATH" to "IMPLEMENTATION"
+ new Artifact<>(
+ GradleArtifactType.COMPILE_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-compile-classpath-group-id",
+ "foo-compile-classpath-artifact-id"
+ ),
+ "foo-compile-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-implementation-group-id",
+ "foo-implementation-artifact-id"
+ ),
+ "foo-implementation-version"
+ ),
+
+ // "RUNTIME_CLASSPATH" to "RUNTIME_ONLY"
+ new Artifact<>(
+ GradleArtifactType.RUNTIME_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-runtime-classpath-group-id",
+ "foo-runtime-classpath-artifact-id"
+ ),
+ "foo-runtime-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-runtime-only-group-id",
+ "foo-runtime-only-artifact-id"
+ ),
+ "foo-runtime-only-version"
+ ),
+
+ // "TEST_COMPILE_CLASSPATH" to "TEST_IMPLEMENTATION"
+ new Artifact<>(
+ GradleArtifactType.TEST_COMPILE_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-test-compile-classpath-group-id",
+ "foo-test-compile-classpath-artifact-id"
+ ),
+ "foo-test-compile-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-test-implementation-group-id",
+ "foo-test-implementation-artifact-id"
+ ),
+ "foo-test-implementation-version"
+ ),
+
+ // "TEST_RUNTIME_CLASSPATH" to "TEST_RUNTIME_ONLY"
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_CLASSPATH,
+ new ArtifactIdentifier(
+ "foo-test-runtime-classpath-group-id",
+ "foo-test-runtime-classpath-artifact-id"
+ ),
+ "foo-test-runtime-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-test-runtime-only-group-id",
+ "foo-test-runtime-only-artifact-id"
+ ),
+ "foo-test-runtime-only-version"
+ )
+ ).collect(Collectors.toList());
+ assertThat(GradleBuildResolver.filter(list)).containsExactly(
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-compile-classpath-group-id",
+ "foo-compile-classpath-artifact-id"
+ ),
+ "foo-compile-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-implementation-group-id",
+ "foo-implementation-artifact-id"
+ ),
+ "foo-implementation-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-runtime-classpath-group-id",
+ "foo-runtime-classpath-artifact-id"
+ ),
+ "foo-runtime-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-runtime-only-group-id",
+ "foo-runtime-only-artifact-id"
+ ),
+ "foo-runtime-only-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-test-compile-classpath-group-id",
+ "foo-test-compile-classpath-artifact-id"
+ ),
+ "foo-test-compile-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_IMPLEMENTATION,
+ new ArtifactIdentifier(
+ "foo-test-implementation-group-id",
+ "foo-test-implementation-artifact-id"
+ ),
+ "foo-test-implementation-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-test-runtime-classpath-group-id",
+ "foo-test-runtime-classpath-artifact-id"
+ ),
+ "foo-test-runtime-classpath-version"
+ ),
+ new Artifact<>(
+ GradleArtifactType.TEST_RUNTIME_ONLY,
+ new ArtifactIdentifier(
+ "foo-test-runtime-only-group-id",
+ "foo-test-runtime-only-artifact-id"
+ ),
+ "foo-test-runtime-only-version"
+ )
+ );
+ }
+
+ @Test
+ void testFilterInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> GradleBuildResolver.filter(null));
+ assertThatNullPointerException().isThrownBy(() -> GradleBuildResolver.filter(Collections.singletonList(null)));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverIT.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverIT.java
new file mode 100644
index 0000000..dbe646f
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverIT.java
@@ -0,0 +1,97 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import com.github.alexisjehan.mavencheck.core.component.session.MavenSession;
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+final class MavenBuildResolverIT {
+
+ private final MavenBuildResolver mavenBuildResolver = new MavenBuildResolver(new MavenSession());
+
+ @Test
+ void testResolve() {
+ final var buildFile = new BuildFile(
+ BuildFileType.MAVEN,
+ Path.of("src", "test", "resources", "pom_it.xml")
+ );
+ final var build = mavenBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "google",
+ "https://maven.google.com"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ )
+ );
+ assertThat(build.getArtifacts()).containsExactly(
+ new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("com.google.android.material", "material"),
+ "1.0.0"
+ ),
+ new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "10.0"
+ ),
+ new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("org.springframework", "spring-core"),
+ "3.0.0.RELEASE"
+ ),
+ new Artifact<>(
+ MavenArtifactType.PROFILE_DEPENDENCY,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-jre"
+ ),
+ new Artifact<>(
+ MavenArtifactType.PROFILE_DEPENDENCY,
+ new ArtifactIdentifier("com.google.guava", "guava"),
+ "23.1-android"
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverTest.java
new file mode 100644
index 0000000..dba5ce5
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverTest.java
@@ -0,0 +1,298 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.build.resolver;
+
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile;
+import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType;
+import com.github.alexisjehan.mavencheck.core.component.repository.Repository;
+import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType;
+import com.github.alexisjehan.mavencheck.core.component.session.MavenSession;
+import org.apache.maven.model.building.ModelBuildingException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+@ExtendWith(MockitoExtension.class)
+final class MavenBuildResolverTest {
+
+ @Mock
+ private MavenSession mockedMavenSession;
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> new MavenBuildResolver(null));
+ }
+
+ @Test
+ void testResolve() {
+ final var mavenBuildResolver = new MavenBuildResolver(mockedMavenSession);
+ assertThat(
+ new BuildFile(
+ BuildFileType.MAVEN,
+ Path.of("src", "test", "resources", "pom_empty.xml")
+ )
+ ).satisfies(buildFile -> {
+ final var build = mavenBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ )
+ );
+ assertThat(build.getArtifacts()).isEmpty();
+ });
+ assertThat(
+ new BuildFile(
+ BuildFileType.MAVEN,
+ Path.of("src", "test", "resources", "pom_foo_parent.xml")
+ )
+ ).satisfies(buildFile -> {
+ final var build = mavenBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ )
+ );
+ assertThat(build.getArtifacts()).isEmpty();
+ });
+ assertThat(
+ new BuildFile(
+ BuildFileType.MAVEN,
+ Path.of("src", "test", "resources", "pom_foo.xml")
+ )
+ ).satisfies(buildFile -> {
+ final var build = mavenBuildResolver.resolve(buildFile);
+ assertThat(build.getFile()).isSameAs(buildFile);
+ assertThat(build.getRepositories()).containsExactly(
+ new Repository(
+ RepositoryType.NORMAL,
+ "foo-repository-id",
+ "https://foo-repository-host"
+ ),
+ new Repository(
+ RepositoryType.NORMAL,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "foo-plugin-repository-id",
+ "https://foo-plugin-repository-host"
+ ),
+ new Repository(
+ RepositoryType.PLUGIN,
+ "central",
+ "https://repo.maven.apache.org/maven2"
+ )
+ );
+ assertThat(build.getArtifacts()).containsExactly(
+ new Artifact<>(
+ MavenArtifactType.PARENT,
+ new ArtifactIdentifier(
+ "foo-parent-group-id",
+ "foo-parent-artifact-id"
+ ),
+ "foo-parent-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.DEPENDENCY_MANAGEMENT_DEPENDENCY,
+ new ArtifactIdentifier(
+ "foo-dependency-management-dependency-group-id",
+ "foo-dependency-management-dependency-artifact-id"
+ ),
+ "foo-dependency-management-dependency-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier(
+ "foo-dependency-group-id",
+ "foo-dependency-artifact-id"
+ ),
+ "foo-dependency-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.BUILD_EXTENSION,
+ new ArtifactIdentifier(
+ "foo-build-extension-group-id",
+ "foo-build-extension-artifact-id"
+ ),
+ "foo-build-extension-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.BUILD_PLUGIN_MANAGEMENT_PLUGIN,
+ new ArtifactIdentifier(
+ "foo-build-plugin-management-plugin-group-id",
+ "foo-build-plugin-management-plugin-artifact-id"
+ ),
+ "foo-build-plugin-management-plugin-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY,
+ new ArtifactIdentifier(
+ "foo-build-plugin-management-plugin-dependency-group-id",
+ "foo-build-plugin-management-plugin-dependency-artifact-id"
+ ),
+ "foo-build-plugin-management-plugin-dependency-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.BUILD_PLUGIN,
+ new ArtifactIdentifier(
+ "foo-build-plugin-group-id",
+ "foo-build-plugin-artifact-id"
+ ),
+ "foo-build-plugin-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.BUILD_PLUGIN_DEPENDENCY,
+ new ArtifactIdentifier(
+ "foo-build-plugin-dependency-group-id",
+ "foo-build-plugin-dependency-artifact-id"
+ ),
+ "foo-build-plugin-dependency-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.REPORTING_PLUGIN,
+ new ArtifactIdentifier(
+ "foo-reporting-plugin-group-id",
+ "foo-reporting-plugin-artifact-id"
+ ),
+ "foo-reporting-plugin-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.PROFILE_DEPENDENCY_MANAGEMENT_DEPENDENCY,
+ new ArtifactIdentifier(
+ "foo-profile-dependency-management-dependency-group-id",
+ "foo-profile-dependency-management-dependency-artifact-id"
+ ),
+ "foo-profile-dependency-management-dependency-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.PROFILE_DEPENDENCY,
+ new ArtifactIdentifier(
+ "foo-profile-dependency-group-id",
+ "foo-profile-dependency-artifact-id"
+ ),
+ "foo-profile-dependency-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN,
+ new ArtifactIdentifier(
+ "foo-profile-build-plugin-management-plugin-group-id",
+ "foo-profile-build-plugin-management-plugin-artifact-id"
+ ),
+ "foo-profile-build-plugin-management-plugin-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY,
+ new ArtifactIdentifier(
+ "foo-profile-build-plugin-management-plugin-dependency-group-id",
+ "foo-profile-build-plugin-management-plugin-dependency-artifact-id"
+ ),
+ "foo-profile-build-plugin-management-plugin-dependency-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.PROFILE_BUILD_PLUGIN,
+ new ArtifactIdentifier(
+ "foo-profile-build-plugin-group-id",
+ "foo-profile-build-plugin-artifact-id"
+ ),
+ "foo-profile-build-plugin-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.PROFILE_BUILD_PLUGIN_DEPENDENCY,
+ new ArtifactIdentifier(
+ "foo-profile-build-plugin-dependency-group-id",
+ "foo-profile-build-plugin-dependency-artifact-id"
+ ),
+ "foo-profile-build-plugin-dependency-version"
+ ),
+ new Artifact<>(
+ MavenArtifactType.PROFILE_REPORTING_PLUGIN,
+ new ArtifactIdentifier(
+ "foo-profile-reporting-plugin-group-id",
+ "foo-profile-reporting-plugin-artifact-id"
+ ),
+ "foo-profile-reporting-plugin-version"
+ )
+ );
+ });
+ }
+
+ @Test
+ void testResolveInvalid() {
+ final var mavenBuildResolver = new MavenBuildResolver(mockedMavenSession);
+ assertThatNullPointerException().isThrownBy(() -> mavenBuildResolver.resolve(null));
+ assertThat(
+ new BuildFile(
+ BuildFileType.MAVEN,
+ Path.of("src", "test", "resources", "pom_not-found.xml")
+ )
+ ).satisfies(
+ buildFile -> assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> mavenBuildResolver.resolve(buildFile))
+ .withCauseInstanceOf(ModelBuildingException.class)
+ );
+ assertThat(
+ new BuildFile(
+ BuildFileType.MAVEN,
+ Path.of("src", "test", "resources", "pom_error.xml")
+ )
+ ).satisfies(
+ buildFile -> assertThatExceptionOfType(BuildResolveException.class)
+ .isThrownBy(() -> mavenBuildResolver.resolve(buildFile))
+ .withCauseInstanceOf(ModelBuildingException.class)
+ );
+ }
+
+ @Test
+ void testGetFileTypes() {
+ final var mavenBuildResolver = new MavenBuildResolver(mockedMavenSession);
+ assertThat(mavenBuildResolver.getFileTypes()).contains(BuildFileType.MAVEN);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilterTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilterTest.java
new file mode 100644
index 0000000..5321104
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilterTest.java
@@ -0,0 +1,87 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class ArtifactFilterTest {
+
+ private static final Artifact> ARTIFACT = new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("foo-group-id", "foo-artifact-id")
+ );
+ private static final String UPDATE_VERSION = "foo-version";
+
+ @Test
+ void testAllAccept() {
+ assertThat(ArtifactFilter.ALL.accept(ARTIFACT)).isFalse();
+ }
+
+ @Test
+ void testAllAcceptInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.ALL.accept(null));
+ }
+
+ @Test
+ void testAllAcceptUpdateVersion() {
+ assertThat(ArtifactFilter.ALL.accept(ARTIFACT, UPDATE_VERSION)).isFalse();
+ }
+
+ @Test
+ void testAllAcceptUpdateVersionInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.ALL.accept(null, UPDATE_VERSION));
+ assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.ALL.accept(ARTIFACT, null));
+ assertThatIllegalArgumentException().isThrownBy(() -> ArtifactFilter.ALL.accept(ARTIFACT, Strings.EMPTY));
+ }
+
+ @Test
+ void testNoneAccept() {
+ assertThat(ArtifactFilter.NONE.accept(ARTIFACT)).isTrue();
+ }
+
+ @Test
+ void testNoneAcceptInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.NONE.accept(null));
+ }
+
+ @Test
+ void testNoneAcceptUpdateVersion() {
+ assertThat(ArtifactFilter.NONE.accept(ARTIFACT, UPDATE_VERSION)).isTrue();
+ }
+
+ @Test
+ void testNoneAcceptUpdateVersionInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.NONE.accept(null, UPDATE_VERSION));
+ assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.NONE.accept(ARTIFACT, null));
+ assertThatIllegalArgumentException().isThrownBy(() -> ArtifactFilter.NONE.accept(ARTIFACT, Strings.EMPTY));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilterTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilterTest.java
new file mode 100644
index 0000000..c8e3d23
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilterTest.java
@@ -0,0 +1,92 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class CompositeArtifactFilterTest {
+
+ private static final Artifact> ARTIFACT = new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("foo-group-id", "foo-artifact-id")
+ );
+ private static final String UPDATE_VERSION = "foo-version";
+
+ private final CompositeArtifactFilter compositeArtifactFilter = new CompositeArtifactFilter(ArtifactFilter.ALL);
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> new CompositeArtifactFilter((ArtifactFilter[]) null));
+ assertThatIllegalArgumentException().isThrownBy(CompositeArtifactFilter::new);
+ assertThatNullPointerException().isThrownBy(() -> new CompositeArtifactFilter((ArtifactFilter) null));
+ }
+
+ @Test
+ void testAccept() {
+ assertThat(new CompositeArtifactFilter(ArtifactFilter.ALL).accept(ARTIFACT)).isFalse();
+ assertThat(new CompositeArtifactFilter(ArtifactFilter.NONE).accept(ARTIFACT)).isTrue();
+ assertThat(new CompositeArtifactFilter(ArtifactFilter.ALL, ArtifactFilter.ALL).accept(ARTIFACT)).isFalse();
+ assertThat(new CompositeArtifactFilter(ArtifactFilter.ALL, ArtifactFilter.NONE).accept(ARTIFACT)).isFalse();
+ assertThat(new CompositeArtifactFilter(ArtifactFilter.NONE, ArtifactFilter.NONE).accept(ARTIFACT)).isTrue();
+ }
+
+ @Test
+ void testAcceptInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> compositeArtifactFilter.accept(null));
+ }
+
+ @Test
+ void testAcceptUpdateVersion() {
+ assertThat(
+ new CompositeArtifactFilter(ArtifactFilter.ALL).accept(ARTIFACT, UPDATE_VERSION)
+ ).isFalse();
+ assertThat(
+ new CompositeArtifactFilter(ArtifactFilter.NONE).accept(ARTIFACT, UPDATE_VERSION)
+ ).isTrue();
+ assertThat(
+ new CompositeArtifactFilter(ArtifactFilter.ALL, ArtifactFilter.ALL).accept(ARTIFACT, UPDATE_VERSION)
+ ).isFalse();
+ assertThat(
+ new CompositeArtifactFilter(ArtifactFilter.ALL, ArtifactFilter.NONE).accept(ARTIFACT, UPDATE_VERSION)
+ ).isFalse();
+ assertThat(
+ new CompositeArtifactFilter(ArtifactFilter.NONE, ArtifactFilter.NONE).accept(ARTIFACT, UPDATE_VERSION)
+ ).isTrue();
+ }
+
+ @Test
+ void testAcceptUpdateVersionInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> compositeArtifactFilter.accept(null, UPDATE_VERSION));
+ assertThatNullPointerException().isThrownBy(() -> compositeArtifactFilter.accept(ARTIFACT, null));
+ assertThatIllegalArgumentException().isThrownBy(() -> compositeArtifactFilter.accept(ARTIFACT, Strings.EMPTY));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseExceptionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseExceptionTest.java
new file mode 100644
index 0000000..3d221c3
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseExceptionTest.java
@@ -0,0 +1,124 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser;
+
+import com.github.alexisjehan.javanilla.io.Serializables;
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class ArtifactFilterParseExceptionTest {
+
+ private static final String REASON = "foo-reason";
+ private static final String LINE = "foo-line";
+ private static final long LINE_NUMBER = 1;
+ private static final Path FILE = Path.of("foo-file");
+
+ private final ArtifactFilterParseException artifactFilterParseException = new ArtifactFilterParseException(
+ REASON,
+ LINE,
+ LINE_NUMBER
+ );
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> {
+ throw new ArtifactFilterParseException(null, LINE, LINE_NUMBER);
+ });
+ assertThatIllegalArgumentException().isThrownBy(() -> {
+ throw new ArtifactFilterParseException(Strings.EMPTY, LINE, LINE_NUMBER);
+ });
+ assertThatNullPointerException().isThrownBy(() -> {
+ throw new ArtifactFilterParseException(REASON, null, LINE_NUMBER);
+ });
+ assertThatIllegalArgumentException().isThrownBy(() -> {
+ throw new ArtifactFilterParseException(REASON, Strings.EMPTY, LINE_NUMBER);
+ });
+ assertThatIllegalArgumentException().isThrownBy(() -> {
+ throw new ArtifactFilterParseException(REASON, LINE, 0);
+ });
+ }
+
+ @Test
+ void testWith() {
+ final var otherArtifactFilterParseException = artifactFilterParseException.with(FILE);
+ assertThat(otherArtifactFilterParseException.getOptionalFile())
+ .hasValue(FILE);
+ assertThat(artifactFilterParseException.getReason())
+ .isEqualTo(otherArtifactFilterParseException.getReason());
+ assertThat(artifactFilterParseException.getLine())
+ .isEqualTo(otherArtifactFilterParseException.getLine());
+ assertThat(artifactFilterParseException.getLineNumber())
+ .isEqualTo(otherArtifactFilterParseException.getLineNumber());
+ }
+
+ @Test
+ void testWithInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> artifactFilterParseException.with(null));
+ }
+
+ @Test
+ void testGetMessage() {
+ assertThat(artifactFilterParseException.getMessage()).isEqualTo(
+ REASON + ": \"" + LINE + "\" (at line " + LINE_NUMBER + ")"
+ );
+ assertThat(artifactFilterParseException.with(FILE).getMessage()).isEqualTo(
+ REASON + ": \"" + LINE + "\" (at line " + LINE_NUMBER + " of the " + FILE + " file)"
+ );
+ }
+
+ @Test
+ void testGetReason() {
+ assertThat(artifactFilterParseException.getReason()).isEqualTo(REASON);
+ }
+
+ @Test
+ void testGetLine() {
+ assertThat(artifactFilterParseException.getLine()).isEqualTo(LINE);
+ }
+
+ @Test
+ void testGetLineNumber() {
+ assertThat(artifactFilterParseException.getLineNumber()).isEqualTo(LINE_NUMBER);
+ }
+
+ @Test
+ void testGetOptionalFile() {
+ assertThat(artifactFilterParseException.getOptionalFile()).isEmpty();
+ }
+
+ @Test
+ void testSerializable() {
+ assertThat(
+ Serializables.deserialize(
+ Serializables.serialize(artifactFilterParseException)
+ )
+ ).hasSameClassAs(artifactFilterParseException);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParserTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParserTest.java
new file mode 100644
index 0000000..ae4316f
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParserTest.java
@@ -0,0 +1,163 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact;
+import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier;
+import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class ArtifactFilterParserTest {
+
+ private static final Artifact> ARTIFACT = new Artifact<>(
+ MavenArtifactType.DEPENDENCY,
+ new ArtifactIdentifier("foo-group-id", "foo-artifact-id")
+ );
+ private static final String UPDATE_VERSION = "foo-version";
+
+ @Test
+ void testParsePath() {
+ assertThatNoException().isThrownBy(
+ () -> ArtifactFilterParser.parse(Path.of("src", "test", "resources", ".mvnchk-ignore_foo"))
+ );
+ }
+
+ @Test
+ void testParsePathInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> ArtifactFilterParser.parse((Path) null));
+ assertThat(Path.of("src", "test", "resources", ".mvnchk-ignore_not-found")).satisfies(
+ ignoreFile -> assertThatIllegalArgumentException()
+ .isThrownBy(() -> ArtifactFilterParser.parse(ignoreFile))
+ );
+ assertThat(Path.of("src", "test", "resources", ".mvnchk-ignore_error")).satisfies(
+ ignoreFile -> assertThatExceptionOfType(ArtifactFilterParseException.class)
+ .isThrownBy(() -> ArtifactFilterParser.parse(ignoreFile))
+ );
+ }
+
+ @Test
+ void testParseReader() {
+ try (final var reader = new StringReader(Strings.EMPTY)) {
+ assertThatNoException().isThrownBy(() -> ArtifactFilterParser.parse(reader));
+ }
+ }
+
+ @Test
+ void testParseReaderInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> ArtifactFilterParser.parse((Reader) null));
+ try (final var reader = new StringReader("foo-group-id")) {
+ assertThatExceptionOfType(ArtifactFilterParseException.class)
+ .isThrownBy(() -> ArtifactFilterParser.parse(reader));
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-version:foo")) {
+ assertThatExceptionOfType(ArtifactFilterParseException.class)
+ .isThrownBy(() -> ArtifactFilterParser.parse(reader));
+ }
+ try (final var reader = new StringReader(":foo-artifact-id")) {
+ assertThatExceptionOfType(ArtifactFilterParseException.class)
+ .isThrownBy(() -> ArtifactFilterParser.parse(reader));
+ }
+ try (final var reader = new StringReader("foo-group-id:")) {
+ assertThatExceptionOfType(ArtifactFilterParseException.class)
+ .isThrownBy(() -> ArtifactFilterParser.parse(reader));
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:")) {
+ assertThatExceptionOfType(ArtifactFilterParseException.class)
+ .isThrownBy(() -> ArtifactFilterParser.parse(reader));
+ }
+ }
+
+ @Test
+ void testParseReaderAccept() throws IOException {
+ try (final var reader = new StringReader("#foo-group-id:foo-artifact-id")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT)).isTrue();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT)).isFalse();
+ }
+ try (final var reader = new StringReader("foo-group-id:bar-artifact-id")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT)).isTrue();
+ }
+ }
+
+ @Test
+ void testParseReaderAcceptInvalid() throws IOException {
+ final var artifactFilter = ArtifactFilterParser.parse(new StringReader(Strings.EMPTY));
+ assertThatNullPointerException().isThrownBy(() -> artifactFilter.accept(null));
+ }
+
+ @Test
+ void testParseReaderAcceptUpdateVersion() throws IOException {
+ try (final var reader = new StringReader("#foo-group-id:foo-artifact-id:foo-version")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isTrue();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-version")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:bar-version")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isTrue();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:FOO-VERSION")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-version?")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isTrue();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-?")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isTrue();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-???????")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-version*")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-*")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse();
+ }
+ try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-*******")) {
+ assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse();
+ }
+ }
+
+ @Test
+ void testParseReaderAcceptUpdateVersionInvalid() throws IOException {
+ final var artifactFilter = ArtifactFilterParser.parse(new StringReader(Strings.EMPTY));
+ assertThatNullPointerException().isThrownBy(() -> artifactFilter.accept(null, UPDATE_VERSION));
+ assertThatNullPointerException().isThrownBy(() -> artifactFilter.accept(ARTIFACT, null));
+ assertThatIllegalArgumentException().isThrownBy(() -> artifactFilter.accept(ARTIFACT, Strings.EMPTY));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilterTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilterTest.java
new file mode 100644
index 0000000..9974741
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilterTest.java
@@ -0,0 +1,69 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class VersionFilterTest {
+
+ @Test
+ void testSnapshotAccept() {
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3snapshot")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3snapshot123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3snapshot.123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3snapshot-123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3SNAPSHOT")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3SNAPSHOT123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3SNAPSHOT.123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3SNAPSHOT-123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.snapshot")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.snapshot123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.snapshot.123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.snapshot-123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.SNAPSHOT")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.SNAPSHOT123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.SNAPSHOT.123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.SNAPSHOT-123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-snapshot")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-snapshot123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-snapshot.123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-snapshot-123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-SNAPSHOT")).isTrue();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-SNAPSHOT123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-SNAPSHOT.123")).isFalse();
+ assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-SNAPSHOT-123")).isFalse();
+ }
+
+ @Test
+ void testSnapshotAcceptInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> VersionFilter.SNAPSHOT.accept(null));
+ assertThatIllegalArgumentException().isThrownBy(() -> VersionFilter.SNAPSHOT.accept(Strings.EMPTY));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactoryTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactoryTest.java
new file mode 100644
index 0000000..9ac425b
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactoryTest.java
@@ -0,0 +1,71 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version.factory;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class CompositeVersionFilterFactoryTest {
+
+ private static final VersionFilterFactory ALL = artifactVersion -> version -> false;
+ private static final VersionFilterFactory NONE = artifactVersion -> version -> true;
+
+ private final CompositeVersionFilterFactory compositeVersionFilterFactory = new CompositeVersionFilterFactory(ALL);
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException()
+ .isThrownBy(() -> new CompositeVersionFilterFactory((VersionFilterFactory[]) null));
+ assertThatIllegalArgumentException()
+ .isThrownBy(CompositeVersionFilterFactory::new);
+ assertThatNullPointerException()
+ .isThrownBy(() -> new CompositeVersionFilterFactory((VersionFilterFactory) null));
+ }
+
+ @Test
+ void testCreateInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> compositeVersionFilterFactory.create(null));
+ assertThatIllegalArgumentException().isThrownBy(() -> compositeVersionFilterFactory.create(Strings.EMPTY));
+ }
+
+ @Test
+ void testCreateAccept() {
+ assertThat(new CompositeVersionFilterFactory(ALL).create("1.0.0").accept("1.2.3")).isFalse();
+ assertThat(new CompositeVersionFilterFactory(NONE).create("1.0.0").accept("1.2.3")).isTrue();
+ assertThat(new CompositeVersionFilterFactory(ALL, ALL).create("1.0.0").accept("1.2.3")).isFalse();
+ assertThat(new CompositeVersionFilterFactory(ALL, NONE).create("1.0.0").accept("1.2.3")).isFalse();
+ assertThat(new CompositeVersionFilterFactory(NONE, NONE).create("1.0.0").accept("1.2.3")).isTrue();
+ }
+
+ @Test
+ void testCreateAcceptInvalid() {
+ final var versionFilter = compositeVersionFilterFactory.create("1.0.0");
+ assertThatNullPointerException().isThrownBy(() -> versionFilter.accept(null));
+ assertThatIllegalArgumentException().isThrownBy(() -> versionFilter.accept(Strings.EMPTY));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactoryTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactoryTest.java
new file mode 100644
index 0000000..9fe302c
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactoryTest.java
@@ -0,0 +1,139 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version.factory;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class QualifierVersionFilterFactoryTest {
+
+ private final QualifierVersionFilterFactory qualifierVersionFilterFactory = QualifierVersionFilterFactory.INSTANCE;
+
+ @Test
+ void testCreateInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> qualifierVersionFilterFactory.create(null));
+ assertThatIllegalArgumentException().isThrownBy(() -> qualifierVersionFilterFactory.create(Strings.EMPTY));
+ }
+
+ @Test
+ void testCreateAccept() {
+ // No qualifier
+ assertThat(qualifierVersionFilterFactory.create("1.0.0")).satisfies(versionFilter -> {
+ assertThat(versionFilter.accept("1.2.3")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO-123")).isTrue();
+ });
+
+ // Same qualifier
+ assertThat(qualifierVersionFilterFactory.create("1.0.0-foo")).satisfies(versionFilter -> {
+ assertThat(versionFilter.accept("1.2.3")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO-123")).isTrue();
+ });
+
+ // Not same qualifier
+ assertThat(qualifierVersionFilterFactory.create("1.0.0-bar")).satisfies(versionFilter -> {
+ assertThat(versionFilter.accept("1.2.3")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo")).isFalse();
+ assertThat(versionFilter.accept("1.2.3foo123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3foo.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3foo-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3FOO")).isFalse();
+ assertThat(versionFilter.accept("1.2.3FOO123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3FOO.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3FOO-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.foo")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.foo123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.foo.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.foo-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.FOO")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.FOO123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.FOO.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.FOO-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-foo")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-foo123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-foo.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-foo-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-FOO")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-FOO123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-FOO.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-FOO-123")).isFalse();
+ });
+ }
+
+ @Test
+ void testCreateAcceptInvalid() {
+ final var versionFilter = qualifierVersionFilterFactory.create("1.0.0");
+ assertThatNullPointerException().isThrownBy(() -> versionFilter.accept(null));
+ assertThatIllegalArgumentException().isThrownBy(() -> versionFilter.accept(Strings.EMPTY));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactoryTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactoryTest.java
new file mode 100644
index 0000000..d18a4c9
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactoryTest.java
@@ -0,0 +1,309 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.filter.version.factory;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class ReleaseVersionFilterFactoryTest {
+
+ private final ReleaseVersionFilterFactory releaseVersionFilterFactory = ReleaseVersionFilterFactory.INSTANCE;
+
+ @Test
+ void testCreateInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> releaseVersionFilterFactory.create(null));
+ assertThatIllegalArgumentException().isThrownBy(() -> releaseVersionFilterFactory.create(Strings.EMPTY));
+ }
+
+ @Test
+ void testCreateAccept() {
+ final var versionFilter = releaseVersionFilterFactory.create("1.0.0");
+
+ // No qualifier
+ assertThat(versionFilter.accept("1.2.3")).isTrue();
+
+ // Any qualifier
+ assertThat(versionFilter.accept("1.2.3foo")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3foo-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3FOO-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.foo-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3.FOO-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-foo-123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO.123")).isTrue();
+ assertThat(versionFilter.accept("1.2.3-FOO-123")).isTrue();
+
+ // Alpha qualifier
+ assertThat(versionFilter.accept("1.2.3alpha")).isFalse();
+ assertThat(versionFilter.accept("1.2.3alpha123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3alpha.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3alpha-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3ALPHA")).isFalse();
+ assertThat(versionFilter.accept("1.2.3ALPHA123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3ALPHA.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3ALPHA-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.alpha")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.alpha123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.alpha.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.alpha-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.ALPHA")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.ALPHA123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.ALPHA.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.ALPHA-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-alpha")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-alpha123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-alpha.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-alpha-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-ALPHA")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-ALPHA123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-ALPHA.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-ALPHA-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3a")).isFalse();
+ assertThat(versionFilter.accept("1.2.3a123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3a.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3a-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3A")).isFalse();
+ assertThat(versionFilter.accept("1.2.3A123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3A.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3A-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.a")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.a123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.a.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.a-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.A")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.A123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.A.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.A-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-a")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-a123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-a.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-a-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-A")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-A123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-A.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-A-123")).isFalse();
+
+ // Beta qualifier
+ assertThat(versionFilter.accept("1.2.3beta")).isFalse();
+ assertThat(versionFilter.accept("1.2.3beta123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3beta.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3beta-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3BETA")).isFalse();
+ assertThat(versionFilter.accept("1.2.3BETA123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3BETA.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3BETA-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.beta")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.beta123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.beta.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.beta-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.BETA")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.BETA123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.BETA.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.BETA-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-beta")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-beta123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-beta.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-beta-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-BETA")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-BETA123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-BETA.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-BETA-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3b")).isFalse();
+ assertThat(versionFilter.accept("1.2.3b123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3b.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3b-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3B")).isFalse();
+ assertThat(versionFilter.accept("1.2.3B123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3B.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3B-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.b")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.b123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.b.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.b-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.B")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.B123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.B.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.B-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-b")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-b123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-b.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-b-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-B")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-B123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-B.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-B-123")).isFalse();
+
+ // Milestone qualifier
+ assertThat(versionFilter.accept("1.2.3milestone")).isFalse();
+ assertThat(versionFilter.accept("1.2.3milestone123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3milestone.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3milestone-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3MILESTONE")).isFalse();
+ assertThat(versionFilter.accept("1.2.3MILESTONE123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3MILESTONE.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3MILESTONE-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.milestone")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.milestone123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.milestone.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.milestone-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.MILESTONE")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.MILESTONE123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.MILESTONE.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.MILESTONE-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-milestone")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-milestone123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-milestone.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-milestone-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-MILESTONE")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-MILESTONE123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-MILESTONE.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-MILESTONE-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3m")).isFalse();
+ assertThat(versionFilter.accept("1.2.3m123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3m.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3m-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3M")).isFalse();
+ assertThat(versionFilter.accept("1.2.3M123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3M.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3M-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.m")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.m123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.m.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.m-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.M")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.M123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.M.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.M-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-m")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-m123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-m.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-m-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-M")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-M123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-M.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-M-123")).isFalse();
+
+ // Release candidate qualifier
+ assertThat(versionFilter.accept("1.2.3rc")).isFalse();
+ assertThat(versionFilter.accept("1.2.3rc123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3rc.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3rc-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3RC")).isFalse();
+ assertThat(versionFilter.accept("1.2.3RC123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3RC.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3RC-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.rc")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.rc123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.rc.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.rc-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.RC")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.RC123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.RC.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.RC-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-rc")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-rc123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-rc.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-rc-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-RC")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-RC123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-RC.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-RC-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3cr")).isFalse();
+ assertThat(versionFilter.accept("1.2.3cr123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3cr.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3cr-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3CR")).isFalse();
+ assertThat(versionFilter.accept("1.2.3CR123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3CR.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3CR-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.cr")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.cr123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.cr.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.cr-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.CR")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.CR123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.CR.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.CR-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-cr")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-cr123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-cr.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-cr-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-CR")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-CR123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-CR.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-CR-123")).isFalse();
+
+ // Snapshot qualifier
+ assertThat(versionFilter.accept("1.2.3snapshot")).isFalse();
+ assertThat(versionFilter.accept("1.2.3snapshot123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3snapshot.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3snapshot-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3SNAPSHOT")).isFalse();
+ assertThat(versionFilter.accept("1.2.3SNAPSHOT123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3SNAPSHOT.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3SNAPSHOT-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.snapshot")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.snapshot123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.snapshot.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.snapshot-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.SNAPSHOT")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.SNAPSHOT123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.SNAPSHOT.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3.SNAPSHOT-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-snapshot")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-snapshot123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-snapshot.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-snapshot-123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-SNAPSHOT")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-SNAPSHOT123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-SNAPSHOT.123")).isFalse();
+ assertThat(versionFilter.accept("1.2.3-SNAPSHOT-123")).isFalse();
+ }
+
+ @Test
+ void testCreateAcceptInvalid() {
+ final var versionFilter = releaseVersionFilterFactory.create("1.0.0");
+ assertThatNullPointerException().isThrownBy(() -> versionFilter.accept(null));
+ assertThatIllegalArgumentException().isThrownBy(() -> versionFilter.accept(Strings.EMPTY));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryTest.java
new file mode 100644
index 0000000..5fb0d86
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryTest.java
@@ -0,0 +1,97 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.repository;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class RepositoryTest {
+
+ private static final RepositoryType TYPE = RepositoryType.NORMAL;
+ private static final String ID = "foo-id";
+ private static final String URL = "https://foo-host";
+ private static final RepositoryType OTHER_TYPE = RepositoryType.PLUGIN;
+ private static final String OTHER_ID = "bar-id";
+ private static final String OTHER_URL = "https://bar-host";
+
+ private final Repository repository = new Repository(TYPE, ID, URL);
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> new Repository(null, ID, URL));
+ assertThatNullPointerException().isThrownBy(() -> new Repository(TYPE, null, URL));
+ assertThatIllegalArgumentException().isThrownBy(() -> new Repository(TYPE, Strings.EMPTY, URL));
+ assertThatNullPointerException().isThrownBy(() -> new Repository(TYPE, ID, null));
+ assertThatIllegalArgumentException().isThrownBy(() -> new Repository(TYPE, ID, Strings.EMPTY));
+ }
+
+ @Test
+ void testEqualsAndHashCodeAndToString() {
+ assertThat(repository.equals(repository)).isTrue();
+ assertThat(repository).isNotEqualTo(new Object());
+ assertThat(new Repository(TYPE, ID, URL)).satisfies(otherRepository -> {
+ assertThat(repository).isNotSameAs(otherRepository);
+ assertThat(repository).isEqualTo(otherRepository);
+ assertThat(repository).hasSameHashCodeAs(otherRepository);
+ assertThat(repository).hasToString(otherRepository.toString());
+ });
+ assertThat(new Repository(OTHER_TYPE, ID, URL)).satisfies(otherRepository -> {
+ assertThat(repository).isNotSameAs(otherRepository);
+ assertThat(repository).isNotEqualTo(otherRepository);
+ assertThat(repository).doesNotHaveSameHashCodeAs(otherRepository);
+ assertThat(repository).doesNotHaveToString(otherRepository.toString());
+ });
+ assertThat(new Repository(TYPE, OTHER_ID, URL)).satisfies(otherRepository -> {
+ assertThat(repository).isNotSameAs(otherRepository);
+ assertThat(repository).isNotEqualTo(otherRepository);
+ assertThat(repository).doesNotHaveSameHashCodeAs(otherRepository);
+ assertThat(repository).doesNotHaveToString(otherRepository.toString());
+ });
+ assertThat(new Repository(TYPE, ID, OTHER_URL)).satisfies(otherRepository -> {
+ assertThat(repository).isNotSameAs(otherRepository);
+ assertThat(repository).isNotEqualTo(otherRepository);
+ assertThat(repository).doesNotHaveSameHashCodeAs(otherRepository);
+ assertThat(repository).doesNotHaveToString(otherRepository.toString());
+ });
+ }
+
+ @Test
+ void testGetType() {
+ assertThat(repository.getType()).isEqualTo(TYPE);
+ }
+
+ @Test
+ void testGetId() {
+ assertThat(repository.getId()).isEqualTo(ID);
+ }
+
+ @Test
+ void testGetUrl() {
+ assertThat(repository.getUrl()).isEqualTo(URL);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionExceptionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionExceptionTest.java
new file mode 100644
index 0000000..09459e4
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionExceptionTest.java
@@ -0,0 +1,50 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.session;
+
+import com.github.alexisjehan.javanilla.io.Serializables;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class MavenSessionExceptionTest {
+
+ private static final Exception CAUSE = new Exception("foo-cause");
+
+ private final MavenSessionException mavenSessionException = new MavenSessionException(CAUSE);
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> {
+ throw new MavenSessionException(null);
+ });
+ }
+
+ @Test
+ void testSerializable() {
+ assertThat(Serializables.deserialize(Serializables.serialize(mavenSessionException)))
+ .hasSameClassAs(mavenSessionException);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionTest.java
new file mode 100644
index 0000000..852b2ee
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionTest.java
@@ -0,0 +1,112 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.component.session;
+
+import com.github.alexisjehan.mavencheck.core.util.MavenUtils;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.resolution.VersionRangeRequest;
+import org.eclipse.aether.resolution.VersionRangeResolutionException;
+import org.eclipse.aether.resolution.VersionRangeResult;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+@ExtendWith(MockitoExtension.class)
+final class MavenSessionTest {
+
+ @Mock
+ private RepositorySystem mockedRepositorySystem;
+
+ @Test
+ void testConstructorInvalid() {
+ try (final var mockedMavenUtils = Mockito.mockStatic(MavenUtils.class)) {
+ mockedMavenUtils.when(MavenUtils::makeSettings)
+ .thenThrow(SettingsBuildingException.class);
+ assertThatExceptionOfType(MavenSessionException.class)
+ .isThrownBy(MavenSession::new)
+ .withCauseInstanceOf(SettingsBuildingException.class);
+ }
+ }
+
+ @Test
+ void testResolve() {
+ final var remoteRepositories = List.of(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"));
+ Mockito.when(mockedRepositorySystem.newResolutionRepositories(Mockito.any(), Mockito.any()))
+ .thenReturn(remoteRepositories);
+ try (final var mockedMavenUtils = Mockito.mockStatic(MavenUtils.class)) {
+ mockedMavenUtils.when(() -> MavenUtils.makeRepositorySystem(Mockito.any()))
+ .thenReturn(mockedRepositorySystem);
+ final var mavenSession = new MavenSession();
+ assertThat(mavenSession.resolve(List.of())).isSameAs(remoteRepositories);
+ }
+ }
+
+ @Test
+ void testResolveInvalid() {
+ final var mavenSession = new MavenSession();
+ assertThatNullPointerException().isThrownBy(() -> mavenSession.resolve(null));
+ assertThatNullPointerException().isThrownBy(() -> mavenSession.resolve(Collections.singletonList(null)));
+ }
+
+ @Test
+ void testRequest() throws VersionRangeResolutionException {
+ final var versionRangeResult = new VersionRangeResult(new VersionRangeRequest());
+ Mockito.when(mockedRepositorySystem.resolveVersionRange(Mockito.any(), Mockito.any()))
+ .thenReturn(versionRangeResult);
+ try (final var mockedMavenUtils = Mockito.mockStatic(MavenUtils.class)) {
+ mockedMavenUtils.when(() -> MavenUtils.makeRepositorySystem(Mockito.any()))
+ .thenReturn(mockedRepositorySystem);
+ final var mavenSession = new MavenSession();
+ assertThat(mavenSession.request(new VersionRangeRequest())).isSameAs(versionRangeResult);
+ }
+ }
+
+ @Test
+ void testRequestInvalid() {
+ final var mavenSession = new MavenSession();
+ assertThatNullPointerException().isThrownBy(() -> mavenSession.request(null));
+ }
+
+ @Test
+ void testGetModelResolver() {
+ final var mavenSession = new MavenSession();
+ assertThat(mavenSession.getModelResolver()).isNotNull();
+ }
+
+ @Test
+ void testGetModelCache() {
+ final var mavenSession = new MavenSession();
+ assertThat(mavenSession.getModelCache()).isNotNull();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListenerTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListenerTest.java
new file mode 100644
index 0000000..7c99a23
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListenerTest.java
@@ -0,0 +1,517 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.eclipse.aether.RepositoryEvent;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.metadata.DefaultMetadata;
+import org.eclipse.aether.metadata.Metadata;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class ConsoleRepositoryListenerTest {
+
+ private final ConsoleRepositoryListener consoleRepositoryListener = new ConsoleRepositoryListener();
+
+ @Test
+ void testArtifactDescriptorInvalid() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactDescriptorInvalid(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_DESCRIPTOR_INVALID
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .setException(new RuntimeException())
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactDescriptorInvalidInvalid() {
+ assertThatNullPointerException()
+ .isThrownBy(() -> consoleRepositoryListener.artifactDescriptorInvalid(null));
+ }
+
+ @Test
+ void testArtifactDescriptorMissing() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactDescriptorMissing(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_DESCRIPTOR_MISSING
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactDescriptorMissingInvalid() {
+ assertThatNullPointerException()
+ .isThrownBy(() -> consoleRepositoryListener.artifactDescriptorMissing(null));
+ }
+
+ @Test
+ void testArtifactResolving() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactResolving(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_RESOLVING
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactResolvingInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactResolving(null));
+ }
+
+ @Test
+ void testArtifactResolved() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactResolved(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_RESOLVED
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactResolvedInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactResolved(null));
+ }
+
+ @Test
+ void testArtifactDownloading() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactDownloading(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_DOWNLOADING
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactDownloadingInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactDownloading(null));
+ }
+
+ @Test
+ void testArtifactDownloaded() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactDownloaded(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_DOWNLOADED
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactDownloadedInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactDownloaded(null));
+ }
+
+ @Test
+ void testArtifactInstalling() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactInstalling(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_INSTALLING
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .setFile(new File("foo-file"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactInstallingInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactInstalling(null));
+ }
+
+ @Test
+ void testArtifactInstalled() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactInstalled(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_INSTALLED
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .setFile(new File("foo-file"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactInstalledInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactInstalled(null));
+ }
+
+ @Test
+ void testArtifactDeploying() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactDeploying(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_DEPLOYING
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactDeployingInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactDeploying(null));
+ }
+
+ @Test
+ void testArtifactDeployed() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.artifactDeployed(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.ARTIFACT_DEPLOYED
+ )
+ .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0"))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testArtifactDeployedInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactDeployed(null));
+ }
+
+ @Test
+ void testMetadataInvalid() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.metadataInvalid(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.METADATA_INVALID
+ )
+ .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE))
+ .setException(new RuntimeException())
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testMetadataInvalidInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataInvalid(null));
+ }
+
+ @Test
+ void testMetadataResolving() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.metadataResolving(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.METADATA_RESOLVING
+ )
+ .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testMetadataResolvingInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataResolving(null));
+ }
+
+ @Test
+ void testMetadataResolved() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.metadataResolved(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.METADATA_RESOLVED
+ )
+ .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testMetadataResolvedInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataResolved(null));
+ }
+
+ @Test
+ void testMetadataDownloading() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.metadataDownloading(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.METADATA_DOWNLOADING
+ )
+ .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testMetadataDownloadingInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataDownloading(null));
+ }
+
+ @Test
+ void testMetadataDownloaded() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.metadataDownloaded(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.METADATA_DOWNLOADED
+ )
+ .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testMetadataDownloadedInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataDownloaded(null));
+ }
+
+ @Test
+ void testMetadataInstalling() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.metadataInstalling(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.METADATA_INSTALLING
+ )
+ .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE))
+ .setFile(new File("foo-file"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testMetadataInstallingInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataInstalling(null));
+ }
+
+ @Test
+ void testMetadataInstalled() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.metadataInstalled(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.METADATA_INSTALLED
+ )
+ .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE))
+ .setFile(new File("foo-file"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testMetadataInstalledInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataInstalled(null));
+ }
+
+ @Test
+ void testMetadataDeploying() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.metadataDeploying(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.METADATA_DEPLOYING
+ )
+ .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testMetadataDeployingInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataDeploying(null));
+ }
+
+ @Test
+ void testMetadataDeployed() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings();
+ assertThatNoException().isThrownBy(
+ () -> consoleRepositoryListener.metadataDeployed(
+ new RepositoryEvent.Builder(
+ MavenUtils.makeRepositorySystemSession(
+ settings,
+ MavenUtils.makeDecryptedSettings(settings),
+ MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())
+ ),
+ RepositoryEvent.EventType.METADATA_DEPLOYED
+ )
+ .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE))
+ .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))
+ .build()
+ )
+ );
+ }
+
+ @Test
+ void testMetadataDeployedInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataDeployed(null));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettingsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettingsTest.java
new file mode 100644
index 0000000..19066e9
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettingsTest.java
@@ -0,0 +1,115 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class DecryptedSettingsTest {
+
+ private static final List PROXIES = List.of(new Proxy());
+ private static final List SERVERS = List.of(new Server());
+ private static final List OTHER_PROXIES = List.of();
+ private static final List OTHER_SERVERS = List.of();
+
+ private final DecryptedSettings decryptedSettings = new DecryptedSettings(PROXIES, SERVERS);
+
+ @Test
+ void testConstructorImmutable() {
+ final var proxies = new ArrayList<>(PROXIES);
+ final var servers = new ArrayList<>(SERVERS);
+ final var decryptedSettings = new DecryptedSettings(proxies, servers);
+ proxies.clear();
+ servers.clear();
+ assertThat(decryptedSettings.getProxies()).containsExactlyElementsOf(PROXIES);
+ assertThat(decryptedSettings.getServers()).containsExactlyElementsOf(SERVERS);
+ }
+
+ @Test
+ void testConstructorInvalid() {
+ assertThatNullPointerException()
+ .isThrownBy(() -> new DecryptedSettings(null, SERVERS));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new DecryptedSettings(Collections.singletonList(null), SERVERS));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new DecryptedSettings(PROXIES, null));
+ assertThatNullPointerException()
+ .isThrownBy(() -> new DecryptedSettings(PROXIES, Collections.singletonList(null)));
+ }
+
+ @Test
+ void testEqualsAndHashCodeAndToString() {
+ assertThat(decryptedSettings.equals(decryptedSettings)).isTrue();
+ assertThat(decryptedSettings).isNotEqualTo(new Object());
+ assertThat(new DecryptedSettings(PROXIES, SERVERS)).satisfies(otherDecryptedSettings -> {
+ assertThat(decryptedSettings).isNotSameAs(otherDecryptedSettings);
+ assertThat(decryptedSettings).isEqualTo(otherDecryptedSettings);
+ assertThat(decryptedSettings).hasSameHashCodeAs(otherDecryptedSettings);
+ assertThat(decryptedSettings).hasToString(otherDecryptedSettings.toString());
+ });
+ assertThat(new DecryptedSettings(OTHER_PROXIES, SERVERS)).satisfies(otherDecryptedSettings -> {
+ assertThat(decryptedSettings).isNotSameAs(otherDecryptedSettings);
+ assertThat(decryptedSettings).isNotEqualTo(otherDecryptedSettings);
+ assertThat(decryptedSettings).doesNotHaveSameHashCodeAs(otherDecryptedSettings);
+ assertThat(decryptedSettings).doesNotHaveToString(otherDecryptedSettings.toString());
+ });
+ assertThat(new DecryptedSettings(PROXIES, OTHER_SERVERS)).satisfies(otherDecryptedSettings -> {
+ assertThat(decryptedSettings).isNotSameAs(otherDecryptedSettings);
+ assertThat(decryptedSettings).isNotEqualTo(otherDecryptedSettings);
+ assertThat(decryptedSettings).doesNotHaveSameHashCodeAs(otherDecryptedSettings);
+ assertThat(decryptedSettings).doesNotHaveToString(otherDecryptedSettings.toString());
+ });
+ }
+
+ @Test
+ void testGetProxies() {
+ assertThat(decryptedSettings.getProxies()).isEqualTo(PROXIES);
+ }
+
+ @Test
+ void testGetProxiesImmutable() {
+ final var proxies = decryptedSettings.getProxies();
+ assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(proxies::clear);
+ }
+
+ @Test
+ void testGetServers() {
+ assertThat(decryptedSettings.getServers()).isEqualTo(SERVERS);
+ }
+
+ @Test
+ void testGetServersImmutable() {
+ final var servers = decryptedSettings.getServers();
+ assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(servers::clear);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/GradleUtilsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/GradleUtilsTest.java
new file mode 100644
index 0000000..18f7e0c
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/GradleUtilsTest.java
@@ -0,0 +1,98 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+final class GradleUtilsTest {
+
+ @Test
+ void testRetrieveOptionalHome() {
+ try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) {
+ mockedSystemUtils.when(() -> SystemUtils.getEnvironmentVariable("GRADLE_HOME"))
+ .thenReturn(Optional.empty());
+ mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable)
+ .thenReturn(
+ String.join(
+ File.pathSeparator,
+ "foo",
+ "bar"
+ )
+ );
+ assertThat(GradleUtils.retrieveOptionalHome()).isEmpty();
+ }
+ try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) {
+ mockedSystemUtils.when(() -> SystemUtils.getEnvironmentVariable("GRADLE_HOME"))
+ .thenReturn(Optional.empty());
+ mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable)
+ .thenReturn(
+ String.join(
+ File.pathSeparator,
+ "foo",
+ File.separator + "gradle-1.0" + File.separator + "bin",
+ "bar"
+ )
+ );
+ assertThat(GradleUtils.retrieveOptionalHome()).contains(File.separator + "gradle-1.0");
+ }
+ try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) {
+ mockedSystemUtils.when(() -> SystemUtils.getEnvironmentVariable("GRADLE_HOME"))
+ .thenReturn(Optional.of(File.separatorChar + "gradle-1.0"));
+ mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable)
+ .thenReturn(
+ String.join(
+ File.pathSeparator,
+ "foo",
+ "bar"
+ )
+ );
+ assertThat(GradleUtils.retrieveOptionalHome()).contains(File.separator + "gradle-1.0");
+ }
+ try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) {
+ mockedSystemUtils.when(() -> SystemUtils.getEnvironmentVariable("GRADLE_HOME"))
+ .thenReturn(Optional.of(File.separatorChar + "gradle-1.0"));
+ mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable)
+ .thenReturn(
+ String.join(
+ File.pathSeparator,
+ "foo",
+ File.separator + "gradle-1.0" + File.separator + "bin",
+ "bar"
+ )
+ );
+ assertThat(GradleUtils.retrieveOptionalHome()).contains(File.separator + "gradle-1.0");
+ }
+ }
+
+ @Test
+ void testGetVersion() {
+ assertThat(GradleUtils.getVersion()).matches("^\\d+\\.\\d+(?:\\.\\d+)?$");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/MavenUtilsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/MavenUtilsTest.java
new file mode 100644
index 0000000..dc3452f
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/MavenUtilsTest.java
@@ -0,0 +1,501 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.apache.maven.settings.Repository;
+import org.apache.maven.settings.RepositoryPolicy;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.Proxy;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.util.repository.AuthenticationBuilder;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class MavenUtilsTest {
+
+ @Test
+ void testRetrieveOptionalGlobalHome() {
+ try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) {
+ mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable)
+ .thenReturn(
+ String.join(
+ File.pathSeparator,
+ "foo",
+ "bar"
+ )
+ );
+ assertThat(MavenUtils.retrieveOptionalGlobalHome()).isEmpty();
+ }
+ try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) {
+ mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable)
+ .thenReturn(
+ String.join(
+ File.pathSeparator,
+ "foo",
+ File.separator + "apache-maven-1.0.0" + File.separator + "bin",
+ "bar"
+ )
+ );
+ assertThat(MavenUtils.retrieveOptionalGlobalHome()).contains(File.separator + "apache-maven-1.0.0");
+ }
+ }
+
+ @Test
+ void testRetrieveOptionalGlobalSettingsFile() {
+ try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) {
+ mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable)
+ .thenReturn(
+ String.join(
+ File.pathSeparator,
+ "foo",
+ "bar"
+ )
+ );
+ assertThat(MavenUtils.retrieveOptionalGlobalSettingsFile())
+ .isEmpty();
+ }
+ try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) {
+ mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable)
+ .thenReturn(
+ String.join(
+ File.pathSeparator,
+ "foo",
+ File.separator + "apache-maven-1.0.0" + File.separator + "bin",
+ "bar"
+ )
+ );
+ assertThat(MavenUtils.retrieveOptionalGlobalSettingsFile())
+ .contains(
+ Path.of(
+ File.separator + "apache-maven-1.0.0",
+ "conf",
+ "settings.xml"
+ )
+ );
+ }
+ }
+
+ @Test
+ void testCreateRemoteRepository() {
+ final var remoteRepository = MavenUtils.createRemoteRepository("foo-id", "foo-url");
+ assertThat(remoteRepository.getId()).isEqualTo("foo-id");
+ assertThat(remoteRepository.getUrl()).isEqualTo("foo-url");
+ }
+
+ @Test
+ void testCreateRemoteRepositoryInvalid() {
+ assertThatNullPointerException()
+ .isThrownBy(() -> MavenUtils.createRemoteRepository(null, "https://foo-host"));
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> MavenUtils.createRemoteRepository(Strings.EMPTY, "https://foo-host"));
+ assertThatNullPointerException()
+ .isThrownBy(() -> MavenUtils.createRemoteRepository("foo-id", null));
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> MavenUtils.createRemoteRepository("foo-id", Strings.EMPTY));
+ }
+
+ @Test
+ void testToRemoteRepository() {
+ final var repository = new Repository();
+ repository.setId("foo-id");
+ repository.setLayout("foo-layout");
+ repository.setUrl("https://foo-host");
+ final var releasesPolicy = new RepositoryPolicy();
+ releasesPolicy.setEnabled(true);
+ releasesPolicy.setUpdatePolicy("foo-update-releases-policy");
+ releasesPolicy.setChecksumPolicy("foo-checksum-releases-policy");
+ repository.setReleases(releasesPolicy);
+ final var snapshotsPolicy = new RepositoryPolicy();
+ snapshotsPolicy.setEnabled(false);
+ snapshotsPolicy.setUpdatePolicy("foo-update-snapshots-policy");
+ snapshotsPolicy.setChecksumPolicy("foo-checksum-snapshots-policy");
+ repository.setSnapshots(snapshotsPolicy);
+ final var remoteRepository = MavenUtils.toRemoteRepository(repository);
+ assertThat(remoteRepository.getId())
+ .isEqualTo("foo-id");
+ assertThat(remoteRepository.getContentType())
+ .isEqualTo("foo-layout");
+ assertThat(remoteRepository.getUrl())
+ .isEqualTo("https://foo-host");
+ assertThat(remoteRepository.getPolicy(false).isEnabled())
+ .isTrue();
+ assertThat(remoteRepository.getPolicy(false).getUpdatePolicy())
+ .isEqualTo("foo-update-releases-policy");
+ assertThat(remoteRepository.getPolicy(false).getChecksumPolicy())
+ .isEqualTo("foo-checksum-releases-policy");
+ assertThat(remoteRepository.getPolicy(true).isEnabled())
+ .isFalse();
+ assertThat(remoteRepository.getPolicy(true).getUpdatePolicy())
+ .isEqualTo("foo-update-snapshots-policy");
+ assertThat(remoteRepository.getPolicy(true).getChecksumPolicy())
+ .isEqualTo("foo-checksum-snapshots-policy");
+ }
+
+ @Test
+ void testToRemoteRepositoryInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> MavenUtils.toRemoteRepository(null));
+ }
+
+ @Test
+ void testMakeServiceLocator() {
+ assertThat(MavenUtils.makeServiceLocator()).isNotNull();
+ }
+
+ @Test
+ void testMakeRepositorySystem() {
+ assertThat(MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())).isNotNull();
+ }
+
+ @Test
+ void testMakeRepositorySystemInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeRepositorySystem(null));
+ }
+
+ @Test
+ void testMakeRemoteRepositoryManager() {
+ assertThat(MavenUtils.makeRemoteRepositoryManager(MavenUtils.makeServiceLocator())).isNotNull();
+ }
+
+ @Test
+ void testMakeRemoteRepositoryManagerInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeRemoteRepositoryManager(null));
+ }
+
+ @Test
+ void testMakeSettings() throws SettingsBuildingException {
+ assertThat(MavenUtils.makeSettings()).isNotNull();
+ assertThat(MavenUtils.makeSettings(null, null)).isNotNull();
+ assertThat(Path.of("src", "test", "resources", "settings_foo.xml")).satisfies(
+ settingsFile -> assertThat(MavenUtils.makeSettings(settingsFile, settingsFile)).isNotNull()
+ );
+ assertThat(Path.of("src", "test", "resources", "settings_warning.xml")).satisfies(
+ settingsFile -> assertThat(MavenUtils.makeSettings(settingsFile, settingsFile)).isNotNull()
+ );
+ assertThat(Path.of("src", "test", "resources", "settings_not-found.xml")).satisfies(
+ settingsFile -> assertThat(MavenUtils.makeSettings(settingsFile, settingsFile)).isNotNull()
+ );
+ }
+
+ @Test
+ void testMakeSettingsInvalid() {
+ final var settingsFile = Path.of("src", "test", "resources", "settings_error.xml");
+ assertThatExceptionOfType(SettingsBuildingException.class)
+ .isThrownBy(() -> MavenUtils.makeSettings(settingsFile, settingsFile));
+ }
+
+ @Test
+ void testMakeDecryptedSettings() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings(
+ null,
+ Path.of("src", "test", "resources", "settings_foo.xml")
+ );
+ assertThat(
+ MavenUtils.makeDecryptedSettings(settings)
+ ).satisfies(decryptedSettings -> {
+ assertThat(decryptedSettings.getProxies())
+ .anySatisfy(proxy -> assertThat(proxy.getPassword()).isNotEqualTo("foo-password"));
+ assertThat(decryptedSettings.getServers())
+ .anySatisfy(server -> assertThat(server.getPassword()).isNotEqualTo("foo-password"));
+ });
+ assertThat(
+ MavenUtils.makeDecryptedSettings(settings, null)
+ ).satisfies(decryptedSettings -> {
+ assertThat(decryptedSettings.getProxies())
+ .anySatisfy(proxy -> assertThat(proxy.getPassword()).isNotEqualTo("foo-password"));
+ assertThat(decryptedSettings.getServers())
+ .anySatisfy(server -> assertThat(server.getPassword()).isNotEqualTo("foo-password"));
+ });
+ assertThat(
+ MavenUtils.makeDecryptedSettings(
+ settings,
+ Path.of("src", "test", "resources", "settings-security.xml")
+ )
+ ).satisfies(decryptedSettings -> {
+ assertThat(decryptedSettings.getProxies())
+ .anySatisfy(proxy -> assertThat(proxy.getPassword()).isEqualTo("foo-password"));
+ assertThat(decryptedSettings.getServers())
+ .anySatisfy(server -> assertThat(server.getPassword()).isEqualTo("foo-password"));
+ });
+ assertThat(
+ MavenUtils.makeDecryptedSettings(
+ settings,
+ Path.of("src", "test", "resources", "settings-security_not-found.xml")
+ )
+ ).satisfies(decryptedSettings -> {
+ assertThat(decryptedSettings.getProxies())
+ .anySatisfy(proxy -> assertThat(proxy.getPassword()).isNotEqualTo("foo-password"));
+ assertThat(decryptedSettings.getServers())
+ .anySatisfy(server -> assertThat(server.getPassword()).isNotEqualTo("foo-password"));
+ });
+ }
+
+ @Test
+ void testMakeDecryptedSettingsInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeDecryptedSettings(null));
+ }
+
+ @Test
+ void testMakeLocalRepository() throws SettingsBuildingException {
+ final var localRepository = new LocalRepository("foo-directory");
+ assertThat(
+ MavenUtils.makeLocalRepository(
+ MavenUtils.makeSettings(null, null)
+ )
+ ).isNotEqualTo(localRepository);
+ assertThat(
+ MavenUtils.makeLocalRepository(
+ MavenUtils.makeSettings(
+ null,
+ Path.of("src", "test", "resources", "settings_foo.xml")
+ )
+ )
+ ).isEqualTo(localRepository);
+ }
+
+ @Test
+ void testMakeLocalRepositoryInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeLocalRepository(null));
+ }
+
+ @Test
+ void testMakeProxySelector() throws SettingsBuildingException {
+ final var proxy = new Proxy(
+ "http",
+ "foo-host",
+ 8080,
+ new AuthenticationBuilder()
+ .addUsername("foo-username")
+ .addPassword("foo-password")
+ .build()
+ );
+ assertThat(
+ MavenUtils.makeProxySelector(
+ MavenUtils.makeDecryptedSettings(
+ MavenUtils.makeSettings(null, null),
+ null
+ )
+ )
+ ).satisfies(proxySelector -> {
+ assertThat(proxySelector.getProxy(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")))
+ .isNull();
+ assertThat(proxySelector.getProxy(MavenUtils.createRemoteRepository("bar-id", "https://bar-host")))
+ .isNull();
+ });
+ assertThat(
+ MavenUtils.makeProxySelector(
+ MavenUtils.makeDecryptedSettings(
+ MavenUtils.makeSettings(
+ null,
+ Path.of("src", "test", "resources", "settings_foo.xml")
+ ),
+ Path.of("src", "test", "resources", "settings-security.xml")
+ )
+ )
+ ).satisfies(proxySelector -> {
+ assertThat(proxySelector.getProxy(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")))
+ .isEqualTo(proxy);
+ assertThat(proxySelector.getProxy(MavenUtils.createRemoteRepository("bar-id", "https://bar-host")))
+ .isNull();
+ });
+ }
+
+ @Test
+ void testMakeProxySelectorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeProxySelector(null));
+ }
+
+ @Test
+ void testMakeAuthenticationSelector() throws SettingsBuildingException {
+ final var authentication = new AuthenticationBuilder()
+ .addUsername("foo-username")
+ .addPassword("foo-password")
+ .build();
+ assertThat(
+ MavenUtils.makeAuthenticationSelector(
+ MavenUtils.makeDecryptedSettings(
+ MavenUtils.makeSettings(null, null),
+ null
+ )
+ )
+ ).satisfies(authenticationSelector -> {
+ assertThat(
+ authenticationSelector.getAuthentication(
+ MavenUtils.createRemoteRepository("foo-id", "https://foo-host")
+ )
+ ).isNull();
+ assertThat(
+ authenticationSelector.getAuthentication(
+ MavenUtils.createRemoteRepository("bar-id", "https://bar-host")
+ )
+ ).isNull();
+ });
+ assertThat(
+ MavenUtils.makeAuthenticationSelector(
+ MavenUtils.makeDecryptedSettings(
+ MavenUtils.makeSettings(
+ null,
+ Path.of("src", "test", "resources", "settings_foo.xml")
+ ),
+ Path.of("src", "test", "resources", "settings-security.xml")
+ )
+ )
+ ).satisfies(authenticationSelector -> {
+ assertThat(
+ authenticationSelector.getAuthentication(
+ MavenUtils.createRemoteRepository("foo-id", "https://foo-host")
+ )
+ ).isEqualTo(authentication);
+ assertThat(
+ authenticationSelector.getAuthentication(
+ MavenUtils.createRemoteRepository("bar-id", "https://bar-host")
+ )
+ ).isNull();
+ });
+ }
+
+ @Test
+ void testMakeAuthenticationSelectorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeAuthenticationSelector(null));
+ }
+
+ @Test
+ void testMakeMirrorSelector() throws SettingsBuildingException {
+ final var remoteRepositoryBuilder = new RemoteRepository.Builder(
+ "default",
+ "default",
+ "https://foo-mirror-host"
+ );
+ assertThat(
+ MavenUtils.makeMirrorSelector(
+ MavenUtils.makeSettings(null, null)
+ )
+ ).satisfies(mirrorSelector -> {
+ assertThat(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")).satisfies(
+ remoteRepository -> assertThat(mirrorSelector.getMirror(remoteRepository)).isNull()
+ );
+ assertThat(MavenUtils.createRemoteRepository("bar-id", "https://bar-host")).satisfies(
+ remoteRepository -> assertThat(mirrorSelector.getMirror(remoteRepository)).isNull()
+ );
+ });
+ assertThat(
+ MavenUtils.makeMirrorSelector(
+ MavenUtils.makeSettings(
+ null,
+ Path.of("src", "test", "resources", "settings_foo.xml")
+ )
+ )
+ ).satisfies(mirrorSelector -> {
+ assertThat(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")).satisfies(
+ remoteRepository -> assertThat(mirrorSelector.getMirror(remoteRepository)).isEqualTo(
+ remoteRepositoryBuilder.setMirroredRepositories(List.of(remoteRepository)).build()
+ )
+ );
+ assertThat(MavenUtils.createRemoteRepository("bar-id", "https://bar-host")).satisfies(
+ remoteRepository -> assertThat(mirrorSelector.getMirror(remoteRepository)).isNull()
+ );
+ });
+ }
+
+ @Test
+ void testMakeMirrorSelectorInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeMirrorSelector(null));
+ }
+
+ @Test
+ void testMakeRepositorySystemSession() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings(
+ null,
+ Path.of("src", "test", "resources", "settings_foo.xml")
+ );
+ final var decryptedSettings = MavenUtils.makeDecryptedSettings(
+ settings,
+ Path.of("src", "test", "resources", "settings-security.xml")
+ );
+ final var repositorySystem = MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator());
+ assertThat(MavenUtils.makeRepositorySystemSession(settings, decryptedSettings, repositorySystem)).isNotNull();
+ }
+
+ @Test
+ void testMakeRepositorySystemSessionInvalid() throws SettingsBuildingException {
+ final var settings = MavenUtils.makeSettings(
+ null,
+ Path.of("src", "test", "resources", "settings_foo.xml")
+ );
+ final var decryptedSettings = MavenUtils.makeDecryptedSettings(
+ settings,
+ Path.of("src", "test", "resources", "settings-security.xml")
+ );
+ final var repositorySystem = MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator());
+ assertThatNullPointerException().isThrownBy(
+ () -> MavenUtils.makeRepositorySystemSession(null, decryptedSettings, repositorySystem)
+ );
+ assertThatNullPointerException().isThrownBy(
+ () -> MavenUtils.makeRepositorySystemSession(settings, null, repositorySystem)
+ );
+ assertThatNullPointerException().isThrownBy(
+ () -> MavenUtils.makeRepositorySystemSession(settings, decryptedSettings, null)
+ );
+ }
+
+ @Test
+ void testMakeRemoteRepositories() throws SettingsBuildingException {
+ assertThat(
+ MavenUtils.makeRemoteRepositories(
+ MavenUtils.makeSettings(null, null)
+ )
+ ).isEmpty();
+ assertThat(
+ MavenUtils.makeRemoteRepositories(
+ MavenUtils.makeSettings(
+ null,
+ Path.of("src", "test", "resources", "settings_foo.xml")
+ )
+ )
+ ).containsExactly(
+ MavenUtils.createRemoteRepository("foo-id", "https://foo-host"),
+ MavenUtils.createRemoteRepository("foo-plugin-id", "https://foo-plugin-host")
+ );
+ }
+
+ @Test
+ void testMakeRemoteRepositoriesInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeRemoteRepositories(null));
+ }
+
+ @Test
+ void testGetVersion() {
+ assertThat(MavenUtils.getVersion()).matches("^\\d+\\.\\d+\\.\\d+$");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/SystemUtilsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/SystemUtilsTest.java
new file mode 100644
index 0000000..4d013db
--- /dev/null
+++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/SystemUtilsTest.java
@@ -0,0 +1,56 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Alexis Jehan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.alexisjehan.mavencheck.core.util;
+
+import com.github.alexisjehan.javanilla.lang.Strings;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+final class SystemUtilsTest {
+
+ @Test
+ void testGetEnvironmentVariable() {
+ assertThat(SystemUtils.getEnvironmentVariable("PATH")).isPresent();
+ assertThat(SystemUtils.getEnvironmentVariable("NOT_FOUND")).isEmpty();
+ }
+
+ @Test
+ void testGetEnvironmentVariableInvalid() {
+ assertThatNullPointerException().isThrownBy(() -> SystemUtils.getEnvironmentVariable(null));
+ assertThatIllegalArgumentException().isThrownBy(() -> SystemUtils.getEnvironmentVariable(Strings.EMPTY));
+ }
+
+ @Test
+ void testGetPathEnvironmentVariable() {
+ assertThat(SystemUtils.getPathEnvironmentVariable()).isNotEmpty();
+ }
+
+ @Test
+ void testGetUserHomeDirectory() {
+ assertThat(SystemUtils.getUserHomeDirectory()).isDirectory();
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/.mvnchk-ignore_error b/src/test/resources/.mvnchk-ignore_error
new file mode 100644
index 0000000..760589c
--- /dev/null
+++ b/src/test/resources/.mvnchk-ignore_error
@@ -0,0 +1 @@
+error
\ No newline at end of file
diff --git a/src/test/resources/.mvnchk-ignore_foo b/src/test/resources/.mvnchk-ignore_foo
new file mode 100644
index 0000000..1bac4f1
--- /dev/null
+++ b/src/test/resources/.mvnchk-ignore_foo
@@ -0,0 +1,10 @@
+# comment
+foo-group-id:foo-artifact-id
+foo-group-id:foo-artifact-id:foo-version
+foo-group-id:foo-artifact-id:FOO-VERSION
+foo-group-id:foo-artifact-id:foo-version?
+foo-group-id:foo-artifact-id:foo-?
+foo-group-id:foo-artifact-id:foo-???????
+foo-group-id:foo-artifact-id:foo-version*
+foo-group-id:foo-artifact-id:foo-*
+foo-group-id:foo-artifact-id:foo-*******
\ No newline at end of file
diff --git a/src/test/resources/build_error.gradle b/src/test/resources/build_error.gradle
new file mode 100644
index 0000000..d97a38e
--- /dev/null
+++ b/src/test/resources/build_error.gradle
@@ -0,0 +1,5 @@
+plugins {
+ id 'java-library'
+}
+
+error
\ No newline at end of file
diff --git a/src/test/resources/build_error.gradle.kts b/src/test/resources/build_error.gradle.kts
new file mode 100644
index 0000000..6aca9b6
--- /dev/null
+++ b/src/test/resources/build_error.gradle.kts
@@ -0,0 +1,5 @@
+plugins {
+ `java-library`
+}
+
+error
\ No newline at end of file
diff --git a/src/test/resources/build_foo.gradle b/src/test/resources/build_foo.gradle
new file mode 100644
index 0000000..c744adc
--- /dev/null
+++ b/src/test/resources/build_foo.gradle
@@ -0,0 +1,28 @@
+plugins {
+ id 'java-library'
+}
+
+repositories {
+ mavenCentral()
+ maven {
+ name 'foo-repository-name'
+ url 'https://foo-repository-host'
+ }
+ ivy {
+ name 'bar-repository-name'
+ url 'https://bar-repository-host'
+ }
+}
+
+dependencies {
+ annotationProcessor 'foo-annotation-processor-group-id:foo-annotation-processor-artifact-id:foo-annotation-processor-version'
+ api 'foo-api-group-id:foo-api-artifact-id:foo-api-version'
+ compileOnly 'foo-compile-only-group-id:foo-compile-only-artifact-id:foo-compile-only-version'
+ compileOnlyApi 'foo-compile-only-api-group-id:foo-compile-only-api-artifact-id:foo-compile-only-api-version'
+ implementation 'foo-implementation-group-id:foo-implementation-artifact-id:foo-implementation-version'
+ runtimeOnly 'foo-runtime-only-group-id:foo-runtime-only-artifact-id:foo-runtime-only-version'
+ testAnnotationProcessor 'foo-test-annotation-processor-group-id:foo-test-annotation-processor-artifact-id:foo-test-annotation-processor-version'
+ testCompileOnly 'foo-test-compile-only-group-id:foo-test-compile-only-artifact-id:foo-test-compile-only-version'
+ testImplementation 'foo-test-implementation-group-id:foo-test-implementation-artifact-id:foo-test-implementation-version'
+ testRuntimeOnly 'foo-test-runtime-only-group-id:foo-test-runtime-only-artifact-id:foo-test-runtime-only-version'
+}
\ No newline at end of file
diff --git a/src/test/resources/build_foo.gradle.kts b/src/test/resources/build_foo.gradle.kts
new file mode 100644
index 0000000..f892aeb
--- /dev/null
+++ b/src/test/resources/build_foo.gradle.kts
@@ -0,0 +1,28 @@
+plugins {
+ `java-library`
+}
+
+repositories {
+ mavenCentral()
+ maven {
+ name = "foo-repository-name"
+ url = uri("https://foo-repository-host")
+ }
+ ivy {
+ name = "bar-repository-name"
+ url = uri("https://bar-repository-host")
+ }
+}
+
+dependencies {
+ annotationProcessor("foo-annotation-processor-group-id:foo-annotation-processor-artifact-id:foo-annotation-processor-version")
+ api("foo-api-group-id:foo-api-artifact-id:foo-api-version")
+ compileOnly("foo-compile-only-group-id:foo-compile-only-artifact-id:foo-compile-only-version")
+ compileOnlyApi("foo-compile-only-api-group-id:foo-compile-only-api-artifact-id:foo-compile-only-api-version")
+ implementation("foo-implementation-group-id:foo-implementation-artifact-id:foo-implementation-version")
+ runtimeOnly("foo-runtime-only-group-id:foo-runtime-only-artifact-id:foo-runtime-only-version")
+ testAnnotationProcessor("foo-test-annotation-processor-group-id:foo-test-annotation-processor-artifact-id:foo-test-annotation-processor-version")
+ testCompileOnly("foo-test-compile-only-group-id:foo-test-compile-only-artifact-id:foo-test-compile-only-version")
+ testImplementation("foo-test-implementation-group-id:foo-test-implementation-artifact-id:foo-test-implementation-version")
+ testRuntimeOnly("foo-test-runtime-only-group-id:foo-test-runtime-only-artifact-id:foo-test-runtime-only-version")
+}
\ No newline at end of file
diff --git a/src/test/resources/build_it.gradle b/src/test/resources/build_it.gradle
new file mode 100644
index 0000000..f4ee7a9
--- /dev/null
+++ b/src/test/resources/build_it.gradle
@@ -0,0 +1,22 @@
+plugins {
+ id 'java-library'
+}
+
+repositories {
+ mavenCentral()
+ maven {
+ name 'google'
+ url 'https://maven.google.com'
+ }
+ ivy {
+ url 'https://ivy.example.com'
+ }
+}
+
+dependencies {
+ implementation 'com.google.android.material:material:1.0.0'
+ implementation 'com.google.guava:guava:10.0'
+ implementation 'com.google.guava:guava:23.1-jre'
+ implementation 'com.google.guava:guava:23.1-android'
+ implementation 'org.springframework:spring-core:3.0.0.RELEASE'
+}
\ No newline at end of file
diff --git a/src/test/resources/build_it.gradle.kts b/src/test/resources/build_it.gradle.kts
new file mode 100644
index 0000000..ebdcbee
--- /dev/null
+++ b/src/test/resources/build_it.gradle.kts
@@ -0,0 +1,22 @@
+plugins {
+ `java-library`
+}
+
+repositories {
+ mavenCentral()
+ maven {
+ name = "google"
+ url = uri("https://maven.google.com")
+ }
+ ivy {
+ url = uri("https://ivy.example.com")
+ }
+}
+
+dependencies {
+ implementation("com.google.android.material:material:1.0.0")
+ implementation("com.google.guava:guava:10.0")
+ implementation("com.google.guava:guava:23.1-jre")
+ implementation("com.google.guava:guava:23.1-android")
+ implementation("org.springframework:spring-core:3.0.0.RELEASE")
+}
\ No newline at end of file
diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml
new file mode 100644
index 0000000..b36ad10
--- /dev/null
+++ b/src/test/resources/log4j2.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/pom_empty.xml b/src/test/resources/pom_empty.xml
new file mode 100644
index 0000000..03b8d61
--- /dev/null
+++ b/src/test/resources/pom_empty.xml
@@ -0,0 +1,20 @@
+
+
+ 4.0.0
+
+ foo-group-id
+ foo-artifact-id
+ foo-version
+
+
+
+
+
+ foo-profile-id
+
+
+ bar-profile-id
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/pom_error.xml b/src/test/resources/pom_error.xml
new file mode 100644
index 0000000..001a664
--- /dev/null
+++ b/src/test/resources/pom_error.xml
@@ -0,0 +1,6 @@
+
+
+ 4.0.0
+
+
\ No newline at end of file
diff --git a/src/test/resources/pom_foo.xml b/src/test/resources/pom_foo.xml
new file mode 100644
index 0000000..82a32ee
--- /dev/null
+++ b/src/test/resources/pom_foo.xml
@@ -0,0 +1,158 @@
+
+
+ 4.0.0
+
+
+
+ foo-repository-id
+ https://foo-repository-host
+
+
+
+
+
+ foo-plugin-repository-id
+ https://foo-plugin-repository-host
+
+
+
+
+ foo-parent-group-id
+ foo-parent-artifact-id
+ foo-parent-version
+ pom_foo_parent.xml
+
+
+ foo-artifact-id
+
+
+
+
+ foo-dependency-management-dependency-group-id
+ foo-dependency-management-dependency-artifact-id
+ foo-dependency-management-dependency-version
+
+
+
+
+
+
+ foo-dependency-group-id
+ foo-dependency-artifact-id
+ foo-dependency-version
+
+
+
+
+
+
+ foo-build-extension-group-id
+ foo-build-extension-artifact-id
+ foo-build-extension-version
+
+
+
+
+
+ foo-build-plugin-management-plugin-group-id
+ foo-build-plugin-management-plugin-artifact-id
+ foo-build-plugin-management-plugin-version
+
+
+ foo-build-plugin-management-plugin-dependency-group-id
+ foo-build-plugin-management-plugin-dependency-artifact-id
+ foo-build-plugin-management-plugin-dependency-version
+
+
+
+
+
+
+
+ foo-build-plugin-group-id
+ foo-build-plugin-artifact-id
+ foo-build-plugin-version
+
+
+ foo-build-plugin-dependency-group-id
+ foo-build-plugin-dependency-artifact-id
+ foo-build-plugin-dependency-version
+
+
+
+
+
+
+
+
+
+ foo-reporting-plugin-group-id
+ foo-reporting-plugin-artifact-id
+ foo-reporting-plugin-version
+
+
+
+
+
+
+ foo-profile-id
+
+
+
+ foo-profile-dependency-management-dependency-group-id
+ foo-profile-dependency-management-dependency-artifact-id
+ foo-profile-dependency-management-dependency-version
+
+
+
+
+
+ foo-profile-dependency-group-id
+ foo-profile-dependency-artifact-id
+ foo-profile-dependency-version
+
+
+
+
+
+
+ foo-profile-build-plugin-management-plugin-group-id
+ foo-profile-build-plugin-management-plugin-artifact-id
+ foo-profile-build-plugin-management-plugin-version
+
+
+ foo-profile-build-plugin-management-plugin-dependency-group-id
+ foo-profile-build-plugin-management-plugin-dependency-artifact-id
+ foo-profile-build-plugin-management-plugin-dependency-version
+
+
+
+
+
+
+
+ foo-profile-build-plugin-group-id
+ foo-profile-build-plugin-artifact-id
+ foo-profile-build-plugin-version
+
+
+ foo-profile-build-plugin-dependency-group-id
+ foo-profile-build-plugin-dependency-artifact-id
+ foo-profile-build-plugin-dependency-version
+
+
+
+
+
+
+
+
+ foo-profile-reporting-plugin-group-id
+ foo-profile-reporting-plugin-artifact-id
+ foo-profile-reporting-plugin-version
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/pom_foo_parent.xml b/src/test/resources/pom_foo_parent.xml
new file mode 100644
index 0000000..b5e336a
--- /dev/null
+++ b/src/test/resources/pom_foo_parent.xml
@@ -0,0 +1,9 @@
+
+
+ 4.0.0
+
+ foo-parent-group-id
+ foo-parent-artifact-id
+ foo-parent-version
+ pom
+
\ No newline at end of file
diff --git a/src/test/resources/pom_it.xml b/src/test/resources/pom_it.xml
new file mode 100644
index 0000000..0bb5fc3
--- /dev/null
+++ b/src/test/resources/pom_it.xml
@@ -0,0 +1,57 @@
+
+
+ 4.0.0
+
+ repository-maven
+ repository-maven
+ 1.0.0-SNAPSHOT
+
+
+
+ google
+ Google
+ https://maven.google.com
+
+
+
+
+
+ com.google.android.material
+ material
+ 1.0.0
+
+
+ com.google.guava
+ guava
+ 10.0
+
+
+ org.springframework
+ spring-core
+ 3.0.0.RELEASE
+
+
+
+
+
+ jre
+
+
+ com.google.guava
+ guava
+ 23.1-jre
+
+
+
+
+ android
+
+
+ com.google.guava
+ guava
+ 23.1-android
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/settings-security.xml b/src/test/resources/settings-security.xml
new file mode 100644
index 0000000..f0872ff
--- /dev/null
+++ b/src/test/resources/settings-security.xml
@@ -0,0 +1,4 @@
+
+
+ {aYVAWydUmZUHOanaKCcasd0+ZXjD8EZotUV/cWLgW2I=}
+
\ No newline at end of file
diff --git a/src/test/resources/settings_error.xml b/src/test/resources/settings_error.xml
new file mode 100644
index 0000000..0d19cab
--- /dev/null
+++ b/src/test/resources/settings_error.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/settings_foo.xml b/src/test/resources/settings_foo.xml
new file mode 100644
index 0000000..0d2da19
--- /dev/null
+++ b/src/test/resources/settings_foo.xml
@@ -0,0 +1,72 @@
+
+
+ foo-directory
+
+
+ foo-host
+ foo-username
+ {yEMdGzgwNvAHEqBqqJ0td2W8uGxr3mRr+BQayeeKfvs=}
+ bar-host
+
+
+
+
+ foo-id
+ foo-username
+ {yEMdGzgwNvAHEqBqqJ0td2W8uGxr3mRr+BQayeeKfvs=}
+
+
+
+
+ https://foo-mirror-host
+ foo-id
+
+
+
+
+ foo-id
+
+ true
+
+
+
+ foo-id
+ https://foo-host
+
+
+
+
+ foo-plugin-id
+
+
+ foo-plugin-id
+ https://foo-plugin-host
+
+
+
+
+ bar-id
+
+ false
+
+
+
+ bar-id
+ https://bar-host
+
+
+
+
+ bar-plugin-id
+
+
+ bar-plugin-id
+ https://bar-plugin-host
+
+
+
+
+
+ foo-plugin-id
+
+
\ No newline at end of file
diff --git a/src/test/resources/settings_it_since-6.8.gradle b/src/test/resources/settings_it_since-6.8.gradle
new file mode 100644
index 0000000..5e82d35
--- /dev/null
+++ b/src/test/resources/settings_it_since-6.8.gradle
@@ -0,0 +1,15 @@
+pluginManagement {
+ repositories {
+ maven {
+ url 'https://plugin-management.example.com'
+ }
+ }
+}
+
+dependencyResolutionManagement {
+ repositories {
+ maven {
+ url 'https://dependency-resolution-management.example.com'
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/settings_it_since-6.8.gradle.kts b/src/test/resources/settings_it_since-6.8.gradle.kts
new file mode 100644
index 0000000..8dd18d5
--- /dev/null
+++ b/src/test/resources/settings_it_since-6.8.gradle.kts
@@ -0,0 +1,15 @@
+pluginManagement {
+ repositories {
+ maven {
+ url = uri("https://plugin-management.example.com")
+ }
+ }
+}
+
+dependencyResolutionManagement {
+ repositories {
+ maven {
+ url = uri("https://dependency-resolution-management.example.com")
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/settings_it_until-6.7.gradle b/src/test/resources/settings_it_until-6.7.gradle
new file mode 100644
index 0000000..64d96e1
--- /dev/null
+++ b/src/test/resources/settings_it_until-6.7.gradle
@@ -0,0 +1,7 @@
+pluginManagement {
+ repositories {
+ maven {
+ url 'https://plugin-management.example.com'
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/settings_it_until-6.7.gradle.kts b/src/test/resources/settings_it_until-6.7.gradle.kts
new file mode 100644
index 0000000..de770ab
--- /dev/null
+++ b/src/test/resources/settings_it_until-6.7.gradle.kts
@@ -0,0 +1,7 @@
+pluginManagement {
+ repositories {
+ maven {
+ url = uri("https://plugin-management.example.com")
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/settings_warning.xml b/src/test/resources/settings_warning.xml
new file mode 100644
index 0000000..ac88dcc
--- /dev/null
+++ b/src/test/resources/settings_warning.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file