From 118f74cc4fc24b53d048f0466ec253082ee737c9 Mon Sep 17 00:00:00 2001 From: Abel Salgado Romero Date: Thu, 25 Jan 2024 00:35:38 +0100 Subject: [PATCH 1/2] WIP --- asciidoctor-maven-plugin/pom.xml | 6 + .../asciidoctor/maven/AsciidoctorMojo.java | 51 +++++--- .../maven/AsciidoctorZipMojoTest.java | 9 +- .../maven/ParametersInitializer.java | 89 +++++++++++++ .../maven/ParametersInitializerTest.java | 123 ++++++++++++++++++ .../java/org/asciidoctor/maven/TestUtils.java | 18 ++- 6 files changed, 270 insertions(+), 26 deletions(-) create mode 100644 asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializer.java create mode 100644 asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializerTest.java diff --git a/asciidoctor-maven-plugin/pom.xml b/asciidoctor-maven-plugin/pom.xml index ee4200cc..81f247ce 100644 --- a/asciidoctor-maven-plugin/pom.xml +++ b/asciidoctor-maven-plugin/pom.xml @@ -62,6 +62,12 @@ netty-codec-http 4.1.106.Final + + net.bytebuddy + byte-buddy + 1.14.11 + test + diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java index 0bd4b88a..c80bc91f 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java @@ -7,7 +7,12 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; -import org.asciidoctor.*; +import org.asciidoctor.Asciidoctor; +import org.asciidoctor.Attributes; +import org.asciidoctor.AttributesBuilder; +import org.asciidoctor.Options; +import org.asciidoctor.OptionsBuilder; +import org.asciidoctor.SafeMode; import org.asciidoctor.jruby.AsciidoctorJRuby; import org.asciidoctor.jruby.internal.JRubyRuntimeContext; import org.asciidoctor.maven.commons.AsciidoctorHelper; @@ -29,10 +34,18 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.logging.Logger; import static org.asciidoctor.maven.commons.StringUtils.isBlank; +import static org.asciidoctor.maven.commons.StringUtils.isNotBlank; import static org.asciidoctor.maven.process.SourceDirectoryFinder.DEFAULT_SOURCE_DIR; @@ -52,10 +65,10 @@ public class AsciidoctorMojo extends AbstractMojo { protected File outputFile; @Parameter(property = AsciidoctorMaven.PREFIX + "preserveDirectories", defaultValue = "false") - protected boolean preserveDirectories = false; + protected boolean preserveDirectories; @Parameter(property = AsciidoctorMaven.PREFIX + "relativeBaseDir", defaultValue = "false") - protected boolean relativeBaseDir = false; + protected boolean relativeBaseDir; @Parameter(property = AsciidoctorMaven.PREFIX + "projectDirectory", defaultValue = "${basedir}") protected File projectDirectory; @@ -66,8 +79,8 @@ public class AsciidoctorMojo extends AbstractMojo { @Parameter(property = AsciidoctorMaven.PREFIX + "baseDir") protected File baseDir; - @Parameter(property = AsciidoctorMaven.PREFIX + "skip") - protected boolean skip = false; + @Parameter(property = AsciidoctorMaven.PREFIX + "skip", defaultValue = "false") + protected boolean skip; @Parameter(property = AsciidoctorMaven.PREFIX + "gemPath") protected String gemPath; @@ -79,10 +92,10 @@ public class AsciidoctorMojo extends AbstractMojo { protected Map attributes = new HashMap<>(); @Parameter(property = AsciidoctorMaven.PREFIX + Options.ATTRIBUTES) - protected String attributesChain = ""; + protected String attributesChain; @Parameter(property = AsciidoctorMaven.PREFIX + Options.BACKEND, defaultValue = "html5") - protected String backend = "html5"; + protected String backend; @Parameter(property = AsciidoctorMaven.PREFIX + Options.DOCTYPE) protected String doctype; @@ -91,7 +104,7 @@ public class AsciidoctorMojo extends AbstractMojo { protected String eruby; @Parameter(property = AsciidoctorMaven.PREFIX + "standalone", defaultValue = "true") - protected boolean standalone = true; + protected boolean standalone; @Parameter(property = AsciidoctorMaven.PREFIX + "templateDirs") protected List templateDirs = new ArrayList<>(); @@ -99,8 +112,8 @@ public class AsciidoctorMojo extends AbstractMojo { @Parameter(property = AsciidoctorMaven.PREFIX + "templateEngine") protected String templateEngine; - @Parameter(property = AsciidoctorMaven.PREFIX + "templateCache") - protected boolean templateCache = true; + @Parameter(property = AsciidoctorMaven.PREFIX + "templateCache", defaultValue = "true") + protected boolean templateCache; @Parameter(property = AsciidoctorMaven.PREFIX + "sourceDocumentName") protected String sourceDocumentName; @@ -108,24 +121,24 @@ public class AsciidoctorMojo extends AbstractMojo { @Parameter(property = AsciidoctorMaven.PREFIX + "sourceDocumentExtensions") protected List sourceDocumentExtensions = new ArrayList<>(); - @Parameter(property = AsciidoctorMaven.PREFIX + "sourcemap") - protected boolean sourcemap = false; + @Parameter(property = AsciidoctorMaven.PREFIX + "sourcemap", defaultValue = "false") + protected boolean sourcemap; - @Parameter(property = AsciidoctorMaven.PREFIX + "catalogAssets") - protected boolean catalogAssets = false; + @Parameter(property = AsciidoctorMaven.PREFIX + "catalogAssets", defaultValue = "false") + protected boolean catalogAssets; @Parameter protected List extensions = new ArrayList<>(); @Parameter(property = AsciidoctorMaven.PREFIX + "embedAssets", defaultValue = "false") - protected boolean embedAssets = false; + protected boolean embedAssets; - // List of resources to copy to the output directory (e.g., images, css). By default everything is copied + // List of resources to copy to the output directory (e.g., images, css). By default, everything is copied @Parameter protected List resources; @Parameter(property = AsciidoctorMaven.PREFIX + "verbose", defaultValue = "false") - protected boolean enableVerbose = false; + protected boolean enableVerbose; @Parameter private LogHandler logHandler = new LogHandler(); @@ -455,7 +468,7 @@ protected AttributesBuilder createAttributesBuilder(AsciidoctorMojo configuratio AsciidoctorHelper.addProperties(mavenProject.getProperties(), attributesBuilder); AsciidoctorHelper.addAttributes(configuration.getAttributes(), attributesBuilder); - if (!configuration.getAttributesChain().isEmpty()) { + if (isNotBlank(configuration.getAttributesChain())) { getLog().info("Attributes: " + attributesChain); attributesBuilder.arguments(attributesChain); } diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorZipMojoTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorZipMojoTest.java index eaeadac7..db60562f 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorZipMojoTest.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorZipMojoTest.java @@ -41,11 +41,10 @@ void should_create_simple_zip() throws IOException, MojoFailureException, MojoEx "= Title\n\ntest", UTF_8); AsciidoctorZipMojo mojo = mockAsciidoctorZipMojo(); - mojo.backend = "html"; mojo.sourceDirectory = srcDir; mojo.outputDirectory = outputDir; mojo.zipDestination = zip; - mojo.zip = true; + mojo.attach = false; mojo.execute(); // then: a zip is created @@ -72,13 +71,12 @@ void should_replicate_source_structure_in_zip_standard_paths() throws MojoFailur // when AsciidoctorZipMojo mojo = mockAsciidoctorZipMojo(); - mojo.backend = "html5"; mojo.sourceDirectory = srcDir; mojo.outputDirectory = outputDir; mojo.preserveDirectories = true; mojo.relativeBaseDir = true; mojo.zipDestination = zip; - mojo.zip = true; + mojo.attach = false; mojo.execute(); // then @@ -118,11 +116,10 @@ void should_not_replicate_source_structure_in_zip_standard_paths() throws IOExce // when AsciidoctorZipMojo mojo = mockAsciidoctorZipMojo(); - mojo.backend = "html5"; mojo.sourceDirectory = srcDir; mojo.outputDirectory = outputDir; mojo.zipDestination = zip; - mojo.zip = true; + mojo.attach = false; mojo.execute(); // then diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializer.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializer.java new file mode 100644 index 00000000..b868a514 --- /dev/null +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializer.java @@ -0,0 +1,89 @@ +package org.asciidoctor.maven; + +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.annotation.AnnotationValue; +import net.bytebuddy.description.field.FieldDescription; +import net.bytebuddy.description.field.FieldList; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.pool.TypePool; +import org.apache.maven.plugins.annotations.Parameter; + +import static org.asciidoctor.maven.commons.StringUtils.isBlank; +import static org.codehaus.plexus.util.ReflectionUtils.setVariableValueInObject; + +/** + * + */ +class ParametersInitializer { + + private static final ClassLoader CLASS_LOADER = ParametersInitializer.class.getClassLoader(); + + /** + * Returns instance of input class with fields initialized according to its + * respective {@link org.apache.maven.plugins.annotations.Parameter}. + */ + public T initialize(T instance) { + try { + // Use ByteBuddy because annotations is Class retention, not Runtime + TypePool typePool = TypePool.Default.of(CLASS_LOADER); + TypeDescription typeDescription = typePool.describe(instance.getClass().getName()).resolve(); + + initParameterFields(instance, typeDescription); + return instance; + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private void initParameterFields(T instance, TypeDescription typeDescription) throws IllegalAccessException { + + FieldList declaredFields = typeDescription.getDeclaredFields(); + + for (FieldDescription field : declaredFields) { + String value = getAnnotationByType(field); + if (value != null) { + if (field.getType().getTypeName().equals(String.class.getName())) { + if (value.length() > 0 && !value.startsWith("$")) { + // TODO support Maven variable: pass Map ? + setVariableValueInObject(instance, field.getName(), value); + } + } + if (field.getType().getTypeName().equals("boolean")) { + // false is already the default + // TODO for PR, the booleans default should appear in XML plugin descriptor now + if (value.equals("true")) { + setVariableValueInObject(instance, field.getName(), Boolean.TRUE); + } else if (!value.equals("false")) { + throw new RuntimeException("Invalid boolean default: not-a-boolean"); + } + } + // TODO + // if (field.getType().getTypeName().equals(File.class.getName())) { + } + } + + TypeDescription superClass = typeDescription.getSuperClass().asErasure(); + + if (hasParent(superClass)) { + initParameterFields(instance, superClass); + } + } + + private boolean hasParent(TypeDescription superClass) { + return superClass != null && !superClass.getTypeName().equals(Object.class.getName()); + } + + // Make MojoReader + private String getAnnotationByType(FieldDescription field) { + for (AnnotationDescription declaredAnnotation : field.getDeclaredAnnotations()) { + String annotationTypeName = declaredAnnotation.getAnnotationType().getName(); + if (annotationTypeName.equals(Parameter.class.getCanonicalName())) { + AnnotationValue defaultValue = declaredAnnotation.getValue("defaultValue"); + String stringValue = defaultValue.toString(); + stringValue = stringValue.substring(1, stringValue.length() - 1).trim(); + return isBlank(stringValue) ? null : stringValue; + } + } + return null; + } +} diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializerTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializerTest.java new file mode 100644 index 00000000..92ba43c1 --- /dev/null +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializerTest.java @@ -0,0 +1,123 @@ +package org.asciidoctor.maven; + +import org.apache.maven.plugins.annotations.Parameter; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +class ParametersInitializerTest { + + private final ParametersInitializer initializer = new ParametersInitializer(); + + @Test + void should_return_same_instance() { + final var instance = new Simple(); + var actual = initializer.initialize(instance); + assertThat(actual).isEqualTo(instance); + } + + @Nested + class ShouldInitialize { + + @Test + void string_with_default_value() { + final var instance = new StringExampleMojo(); + var initialized = initializer.initialize(instance); + assertThat(initialized.defaultValue).isEqualTo("a-value"); + } + + @Test + void boolean_with_default_value() { + final var instance = new BooleanExampleMojo(); + var initialized = initializer.initialize(instance); + assertThat(initialized.defaultValue).isTrue(); + } + + @Test + void properties_in_class_and_parent() { + final var instance = new SubclassExampleMojo(); + var initialized = initializer.initialize(instance); + assertThat(initialized.getDefaultValue()).isEqualTo("a-value"); + assertThat(initialized.getNonDefaultValue()).isNull(); + assertThat(initialized.anotherValue).isEqualTo("from-subclass"); + } + } + + @Nested + class ShouldNotInitialize { + + @Test + void string_without_default_value() { + final var instance = new StringExampleMojo(); + var initialized = initializer.initialize(instance); + assertThat(initialized.nonDefaultValue).isNull(); + } + + @Test + void boolean_without_default_value() { + final var instance = new BooleanExampleMojo(); + var initialized = initializer.initialize(instance); + assertThat(initialized.nonDefaultValue).isFalse(); + } + } + + @Nested + class ShouldFail { + @Test + void boolean_with_invalid_value() { + final var instance = new FailingExampleMojo(); + Throwable t = catchThrowable(() -> initializer.initialize(instance)); + + assertThat(t).isInstanceOf(RuntimeException.class) + .hasMessage("Invalid boolean default: not-a-boolean"); + } + } + + + class Simple { + + Simple() { + } + + } + + class StringExampleMojo { + + @Parameter(defaultValue = "a-value") + private String defaultValue; + + @Parameter + private String nonDefaultValue; + + public String getDefaultValue() { + return defaultValue; + } + + public String getNonDefaultValue() { + return nonDefaultValue; + } + } + + class BooleanExampleMojo { + + @Parameter(defaultValue = "true") + private boolean defaultValue; + + @Parameter + private boolean nonDefaultValue; + } + + class FailingExampleMojo { + + @Parameter(defaultValue = "not-a-boolean") + private boolean invalidValue; + } + + class SubclassExampleMojo extends StringExampleMojo { + + @Parameter(defaultValue = "from-subclass") + private String anotherValue; + } +} diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/TestUtils.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/TestUtils.java index 49379fd9..05e6683d 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/TestUtils.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/TestUtils.java @@ -1,8 +1,16 @@ package org.asciidoctor.maven; import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.ClassFileVersion; +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.annotation.AnnotationValue; +import net.bytebuddy.description.field.FieldDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.pool.TypePool; import org.apache.commons.io.IOUtils; import org.apache.maven.plugin.logging.SystemStreamLog; +import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.asciidoctor.maven.log.LogHandler; import org.asciidoctor.maven.model.Resource; @@ -12,17 +20,24 @@ import java.io.FileOutputStream; import java.io.FileReader; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Properties; import java.util.stream.Collectors; import static java.util.Collections.singletonList; import static org.asciidoctor.maven.process.SourceDocumentFinder.STANDARD_FILE_EXTENSIONS_PATTERN; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatPath; import static org.codehaus.plexus.util.ReflectionUtils.setVariableValueInObject; import static org.mockito.Mockito.when; public class TestUtils { + private static final ParametersInitializer parametersInitializer = new ParametersInitializer(); + @SneakyThrows public static AsciidoctorRefreshMojo newFakeRefreshMojo() { return mockAsciidoctorMojo(AsciidoctorRefreshMojo.class, null, null); @@ -65,6 +80,7 @@ private static T mockAsciidoctorMojo(Class clazz, Map mav } final AsciidoctorMojo mojo = (AsciidoctorMojo) clazz.getConstructor(new Class[]{}).newInstance(); + parametersInitializer.initialize(mojo); setVariableValueInObject(mojo, "log", new SystemStreamLog()); mojo.project = mavenProject; if (logHandler != null) From d3fa92f150f72674e7824857a53d6d9e3f1fe668 Mon Sep 17 00:00:00 2001 From: Abel Salgado Romero Date: Thu, 25 Jan 2024 21:22:19 +0100 Subject: [PATCH 2/2] Extract MojoMocker + reduce TestUtils methods --- CHANGELOG.adoc | 2 + .../maven/AsciidoctorHttpMojo.java | 4 +- .../maven/AsciidoctorRefreshMojo.java | 20 +++-- .../maven/AsciidoctorAsserter.java | 5 +- .../maven/AsciidoctorHttpMojoTest.java | 2 +- .../maven/AsciidoctorIntegrationTest.java | 4 +- .../maven/AsciidoctorMojoExtensionsTest.java | 2 +- .../maven/AsciidoctorMojoLogHandlerTest.java | 2 +- .../maven/AsciidoctorMojoTest.java | 30 ++++--- .../maven/AsciidoctorRefreshMojoTest.java | 4 +- .../maven/AsciidoctorZipMojoTest.java | 2 +- .../process/CopyResourcesProcessorTest.java | 2 +- .../asciidoctor/maven/test/MojoMocker.java | 46 ++++++++++ .../maven/test/MojoMockerTest.java | 36 ++++++++ .../{ => test}/ParametersInitializer.java | 22 +++-- .../{ => test}/ParametersInitializerTest.java | 45 +++++++++- .../maven/{ => test}/TestUtils.java | 88 ++++--------------- 17 files changed, 206 insertions(+), 110 deletions(-) create mode 100644 asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/MojoMocker.java create mode 100644 asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/MojoMockerTest.java rename asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/{ => test}/ParametersInitializer.java (83%) rename asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/{ => test}/ParametersInitializerTest.java (71%) rename asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/{ => test}/TestUtils.java (56%) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index e14f59b6..f0fc5ba0 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -64,6 +64,8 @@ Build / Infrastructure:: * Use latest Maven and remove Dependabot exclusion (CI test ensure backward compatibility) (#722) * Test artifact's signature with Maven in CI (#736) * Automate release using GH Actions (#141) + * Ensure Mojos use correct default values in unit tests (#609) + Maintenance:: * Replace use of reflection by direct JavaExtensionRegistry calls to register extensions (#596) diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorHttpMojo.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorHttpMojo.java index cb95b5fd..c5d31303 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorHttpMojo.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorHttpMojo.java @@ -11,8 +11,8 @@ public class AsciidoctorHttpMojo extends AsciidoctorRefreshMojo { public static final String PREFIX = AsciidoctorMaven.PREFIX + "http."; - @Parameter(property = PREFIX + "port") - protected int port = 2000; + @Parameter(property = PREFIX + "port", defaultValue = "2000") + protected int port; @Parameter(property = PREFIX + "home", defaultValue = "index") protected String home; diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorRefreshMojo.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorRefreshMojo.java index 854a4f22..88ba4626 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorRefreshMojo.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorRefreshMojo.java @@ -11,22 +11,32 @@ import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -import org.asciidoctor.maven.refresh.*; +import org.asciidoctor.maven.refresh.AdditionalSourceFileAlterationListenerAdaptor; +import org.asciidoctor.maven.refresh.AsciidoctorConverterFileAlterationListenerAdaptor; +import org.asciidoctor.maven.refresh.ResourceCopyFileAlterationListenerAdaptor; +import org.asciidoctor.maven.refresh.ResourcesPatternBuilder; +import org.asciidoctor.maven.refresh.TimeCounter; import java.io.File; import java.io.FileFilter; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Scanner; +import java.util.StringJoiner; import static org.asciidoctor.maven.commons.StringUtils.isNotBlank; -import static org.asciidoctor.maven.process.SourceDocumentFinder.*; +import static org.asciidoctor.maven.process.SourceDocumentFinder.CUSTOM_FILE_EXTENSIONS_PATTERN_PREFIX; +import static org.asciidoctor.maven.process.SourceDocumentFinder.CUSTOM_FILE_EXTENSIONS_PATTERN_SUFFIX; +import static org.asciidoctor.maven.process.SourceDocumentFinder.STANDARD_FILE_EXTENSIONS_PATTERN; @Mojo(name = "auto-refresh") public class AsciidoctorRefreshMojo extends AsciidoctorMojo { public static final String PREFIX = AsciidoctorMaven.PREFIX + "refresher."; - @Parameter(property = PREFIX + "interval") - protected int interval = 2000; // 2s + @Parameter(property = PREFIX + "interval", defaultValue = "2000") + protected int interval; @Parameter(property = PREFIX + "refreshOn") protected String refreshOn; diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorAsserter.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorAsserter.java index b713688a..cb6ce454 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorAsserter.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorAsserter.java @@ -1,19 +1,22 @@ package org.asciidoctor.maven; +import lombok.SneakyThrows; import org.assertj.core.api.AbstractFileAssert; import org.assertj.core.api.AbstractStringAssert; import org.assertj.core.api.Assertions; import java.io.File; +import java.nio.file.Files; public class AsciidoctorAsserter { private final AbstractFileAssert fileAssert; private final AbstractStringAssert contentAssert; + @SneakyThrows private AsciidoctorAsserter(File generatedFile) { this.fileAssert = Assertions.assertThat(generatedFile); - this.contentAssert = Assertions.assertThat(TestUtils.readAsString(generatedFile)); + this.contentAssert = Assertions.assertThat(Files.readString(generatedFile.toPath())); } public static AsciidoctorAsserter assertThat(File file) { diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorHttpMojoTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorHttpMojoTest.java index d5c21701..9fde57d5 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorHttpMojoTest.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorHttpMojoTest.java @@ -18,7 +18,7 @@ import java.net.URL; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.asciidoctor.maven.TestUtils.mockAsciidoctorHttpMojo; +import static org.asciidoctor.maven.test.TestUtils.mockAsciidoctorHttpMojo; import static org.assertj.core.api.Assertions.assertThat; class AsciidoctorHttpMojoTest { diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorIntegrationTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorIntegrationTest.java index d2cafad2..642b5ef8 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorIntegrationTest.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorIntegrationTest.java @@ -10,8 +10,8 @@ import java.util.Map; import static org.asciidoctor.maven.AsciidoctorAsserter.assertThat; -import static org.asciidoctor.maven.TestUtils.ResourceBuilder.excludeAll; -import static org.asciidoctor.maven.TestUtils.mockAsciidoctorMojo; +import static org.asciidoctor.maven.test.TestUtils.ResourceBuilder.excludeAll; +import static org.asciidoctor.maven.test.TestUtils.mockAsciidoctorMojo; import static org.asciidoctor.maven.io.TestFilesHelper.newOutputTestDirectory; /** diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoExtensionsTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoExtensionsTest.java index 8f57f4be..b93763bf 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoExtensionsTest.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoExtensionsTest.java @@ -15,7 +15,7 @@ import java.util.Map; import static java.util.Collections.singletonList; -import static org.asciidoctor.maven.TestUtils.mockAsciidoctorMojo; +import static org.asciidoctor.maven.test.TestUtils.mockAsciidoctorMojo; import static org.asciidoctor.maven.io.TestFilesHelper.newOutputTestDirectory; import static org.assertj.core.api.Assertions.assertThat; diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoLogHandlerTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoLogHandlerTest.java index f626319e..f684b62d 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoLogHandlerTest.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoLogHandlerTest.java @@ -16,7 +16,7 @@ import static org.asciidoctor.log.Severity.ERROR; import static org.asciidoctor.log.Severity.WARN; -import static org.asciidoctor.maven.TestUtils.mockAsciidoctorMojo; +import static org.asciidoctor.maven.test.TestUtils.mockAsciidoctorMojo; import static org.asciidoctor.maven.io.TestFilesHelper.newOutputTestDirectory; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoTest.java index 64f72aac..784d4e90 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoTest.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/AsciidoctorMojoTest.java @@ -10,17 +10,28 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; import java.util.stream.Collectors; +import static java.nio.file.Files.writeString; import static java.util.Collections.singletonList; import static org.asciidoctor.maven.AsciidoctorAsserter.assertThat; -import static org.asciidoctor.maven.TestUtils.*; -import static org.asciidoctor.maven.TestUtils.ResourceBuilder.excludeAll; import static org.asciidoctor.maven.io.TestFilesHelper.newOutputTestDirectory; +import static org.asciidoctor.maven.test.TestUtils.ResourceBuilder; +import static org.asciidoctor.maven.test.TestUtils.ResourceBuilder.excludeAll; +import static org.asciidoctor.maven.test.TestUtils.assertEqualsStructure; +import static org.asciidoctor.maven.test.TestUtils.mockAsciidoctorMojo; class AsciidoctorMojoTest { @@ -156,7 +167,6 @@ void should_convert_to_html_with_attributes() throws MojoFailureException, MojoE mojo.sourceDocumentName = "sample.asciidoc"; mojo.resources = excludeAll(); mojo.outputDirectory = outputDir; - mojo.standalone = true; mojo.attributes = Map.of("toc", "", "linkcss!", "", "source-highlighter", "coderay"); @@ -283,15 +293,16 @@ void should_override_output_directory_with_output_file_with_absolute_path() thro } @Test - void should_set_file_extension() throws MojoFailureException, MojoExecutionException { + void should_set_file_extension() throws MojoFailureException, MojoExecutionException, IOException { // given File outputDir = newOutputTestDirectory(); Assertions.assertThat(outputDir).doesNotExist(); File srcDir = new File(DEFAULT_SOURCE_DIRECTORY); outputDir.mkdirs(); - writeToFile(srcDir, "sample1.foo", "= Document Title\n\nfoo"); - writeToFile(srcDir, "sample2.bar", "= Document Title\n\nbar"); + + writeString(Path.of(DEFAULT_SOURCE_DIRECTORY, "sample1.foo"), "= Document Title\n\nfoo"); + writeString(Path.of(DEFAULT_SOURCE_DIRECTORY, "sample2.bar"), "= Document Title\n\nbar"); // when AsciidoctorMojo mojo = mockAsciidoctorMojo(); @@ -795,7 +806,6 @@ void should_embed_resources() throws MojoFailureException, MojoExecutionExceptio .contains("i class=\"fa icon-tip\""); } - // issue-78 @Test void should_embed_image_in_included_adoc() throws MojoFailureException, MojoExecutionException { @@ -817,7 +827,7 @@ void should_embed_image_in_included_adoc() throws MojoFailureException, MojoExec assertThat(outputDir, "main.html") .contains("

Here’s an image:

") .contains(" T mock(Class clazz, Map mavenProperties, LogHandler logHandler) { + + final AsciidoctorMojo mojo = (AsciidoctorMojo) clazz.getConstructor(new Class[]{}).newInstance(); + + parametersInitializer.initialize(mojo); + setVariableValueInObject(mojo, "log", new SystemStreamLog()); + setVariableValueInObject(mojo, "project", mockMavenProject(mavenProperties)); + if (logHandler != null) + setVariableValueInObject(mojo, "logHandler", logHandler); + + return (T) mojo; + } + + private MavenProject mockMavenProject(Map mavenProperties) { + final MavenProject mavenProject = Mockito.mock(MavenProject.class); + when(mavenProject.getBasedir()).thenReturn(new File(".")); + if (mavenProperties != null) { + final Properties properties = new Properties(); + properties.putAll(mavenProperties); + when(mavenProject.getProperties()).thenReturn(properties); + } + return mavenProject; + } +} diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/MojoMockerTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/MojoMockerTest.java new file mode 100644 index 00000000..f18a6928 --- /dev/null +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/MojoMockerTest.java @@ -0,0 +1,36 @@ +package org.asciidoctor.maven.test; + +import org.asciidoctor.maven.AsciidoctorMojo; +import org.asciidoctor.maven.log.LogHandler; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class MojoMockerTest { + + private final MojoMocker mojoMocker = new MojoMocker(); + + @Test + void should_mock_mojo() { + AsciidoctorMojo mock = mojoMocker.mock(AsciidoctorMojo.class, null, null); + + assertThat(mock).isNotNull(); + } + + @Test + void should_mock_mojo_with_properties() { + Map properties = Map.of("a-key", "a-value"); + AsciidoctorMojo mock = mojoMocker.mock(AsciidoctorMojo.class, properties, null); + + assertThat(mock).isNotNull(); + } + + @Test + void should_mock_mojo_with_logHandler() { + AsciidoctorMojo mock = mojoMocker.mock(AsciidoctorMojo.class, null, new LogHandler()); + + assertThat(mock).isNotNull(); + } +} diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializer.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/ParametersInitializer.java similarity index 83% rename from asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializer.java rename to asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/ParametersInitializer.java index b868a514..0707238a 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializer.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/ParametersInitializer.java @@ -1,4 +1,4 @@ -package org.asciidoctor.maven; +package org.asciidoctor.maven.test; import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.annotation.AnnotationValue; @@ -12,7 +12,7 @@ import static org.codehaus.plexus.util.ReflectionUtils.setVariableValueInObject; /** - * + * Initialize values for properties in class using {@link Parameter} annotation. */ class ParametersInitializer { @@ -22,7 +22,7 @@ class ParametersInitializer { * Returns instance of input class with fields initialized according to its * respective {@link org.apache.maven.plugins.annotations.Parameter}. */ - public T initialize(T instance) { + T initialize(T instance) { try { // Use ByteBuddy because annotations is Class retention, not Runtime TypePool typePool = TypePool.Default.of(CLASS_LOADER); @@ -42,19 +42,25 @@ private void initParameterFields(T instance, TypeDescription typeDescription for (FieldDescription field : declaredFields) { String value = getAnnotationByType(field); if (value != null) { - if (field.getType().getTypeName().equals(String.class.getName())) { + final String typeName = field.getType().getTypeName(); + if (typeName.equals(String.class.getName())) { if (value.length() > 0 && !value.startsWith("$")) { // TODO support Maven variable: pass Map ? setVariableValueInObject(instance, field.getName(), value); } } - if (field.getType().getTypeName().equals("boolean")) { - // false is already the default - // TODO for PR, the booleans default should appear in XML plugin descriptor now + if (typeName.equals("boolean")) { if (value.equals("true")) { setVariableValueInObject(instance, field.getName(), Boolean.TRUE); } else if (!value.equals("false")) { - throw new RuntimeException("Invalid boolean default: not-a-boolean"); + throw new RuntimeException("Invalid boolean default: " + value); + } + } + if (typeName.equals("int")) { + try { + setVariableValueInObject(instance, field.getName(), Integer.valueOf(value)); + } catch (Exception e) { + throw new RuntimeException("Invalid boolean default: " + value); } } // TODO diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializerTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/ParametersInitializerTest.java similarity index 71% rename from asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializerTest.java rename to asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/ParametersInitializerTest.java index 92ba43c1..8cd1b329 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/ParametersInitializerTest.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/ParametersInitializerTest.java @@ -1,4 +1,4 @@ -package org.asciidoctor.maven; +package org.asciidoctor.maven.test; import org.apache.maven.plugins.annotations.Parameter; import org.junit.jupiter.api.Nested; @@ -35,6 +35,13 @@ void boolean_with_default_value() { assertThat(initialized.defaultValue).isTrue(); } + @Test + void int_with_default_value() { + final var instance = new IntExampleMojo(); + var initialized = initializer.initialize(instance); + assertThat(initialized.defaultValue).isEqualTo(1243); + } + @Test void properties_in_class_and_parent() { final var instance = new SubclassExampleMojo(); @@ -61,18 +68,35 @@ void boolean_without_default_value() { var initialized = initializer.initialize(instance); assertThat(initialized.nonDefaultValue).isFalse(); } + + @Test + void int_without_default_value() { + final var instance = new IntExampleMojo(); + var initialized = initializer.initialize(instance); + assertThat(initialized.nonDefaultValue).isEqualTo(0); + } } @Nested class ShouldFail { + @Test void boolean_with_invalid_value() { - final var instance = new FailingExampleMojo(); + final var instance = new FailingBooleanExampleMojo(); Throwable t = catchThrowable(() -> initializer.initialize(instance)); assertThat(t).isInstanceOf(RuntimeException.class) .hasMessage("Invalid boolean default: not-a-boolean"); } + + @Test + void int_with_invalid_value() { + final var instance = new FailingIntExampleMojo(); + Throwable t = catchThrowable(() -> initializer.initialize(instance)); + + assertThat(t).isInstanceOf(RuntimeException.class) + .hasMessage("Invalid boolean default: not-an-int"); + } } @@ -109,12 +133,27 @@ class BooleanExampleMojo { private boolean nonDefaultValue; } - class FailingExampleMojo { + class IntExampleMojo { + + @Parameter(defaultValue = "1243") + private int defaultValue; + + @Parameter + private int nonDefaultValue; + } + + class FailingBooleanExampleMojo { @Parameter(defaultValue = "not-a-boolean") private boolean invalidValue; } + class FailingIntExampleMojo { + + @Parameter(defaultValue = "not-an-int") + private int invalidValue; + } + class SubclassExampleMojo extends StringExampleMojo { @Parameter(defaultValue = "from-subclass") diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/TestUtils.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/TestUtils.java similarity index 56% rename from asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/TestUtils.java rename to asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/TestUtils.java index 05e6683d..08d148d1 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/TestUtils.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/TestUtils.java @@ -1,105 +1,49 @@ -package org.asciidoctor.maven; - -import lombok.SneakyThrows; -import net.bytebuddy.ByteBuddy; -import net.bytebuddy.ClassFileVersion; -import net.bytebuddy.description.annotation.AnnotationDescription; -import net.bytebuddy.description.annotation.AnnotationValue; -import net.bytebuddy.description.field.FieldDescription; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.pool.TypePool; -import org.apache.commons.io.IOUtils; -import org.apache.maven.plugin.logging.SystemStreamLog; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.MavenProject; +package org.asciidoctor.maven.test; + +import org.asciidoctor.maven.AsciidoctorHttpMojo; +import org.asciidoctor.maven.AsciidoctorMojo; +import org.asciidoctor.maven.AsciidoctorRefreshMojo; +import org.asciidoctor.maven.AsciidoctorZipMojo; import org.asciidoctor.maven.log.LogHandler; import org.asciidoctor.maven.model.Resource; -import org.mockito.Mockito; import java.io.File; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.stream.Collectors; import static java.util.Collections.singletonList; import static org.asciidoctor.maven.process.SourceDocumentFinder.STANDARD_FILE_EXTENSIONS_PATTERN; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatPath; -import static org.codehaus.plexus.util.ReflectionUtils.setVariableValueInObject; -import static org.mockito.Mockito.when; public class TestUtils { - private static final ParametersInitializer parametersInitializer = new ParametersInitializer(); + private static final MojoMocker mojoMocker = new MojoMocker(); - @SneakyThrows public static AsciidoctorRefreshMojo newFakeRefreshMojo() { - return mockAsciidoctorMojo(AsciidoctorRefreshMojo.class, null, null); + return mojoMocker.mock(AsciidoctorRefreshMojo.class, null, null); } - @SneakyThrows public static AsciidoctorMojo mockAsciidoctorMojo() { - return mockAsciidoctorMojo(AsciidoctorMojo.class, null, null); + return mojoMocker.mock(AsciidoctorMojo.class, null, null); } - @SneakyThrows public static AsciidoctorHttpMojo mockAsciidoctorHttpMojo() { - return mockAsciidoctorMojo(AsciidoctorHttpMojo.class, null, null); + return mojoMocker.mock(AsciidoctorHttpMojo.class, null, null); } - @SneakyThrows public static AsciidoctorZipMojo mockAsciidoctorZipMojo() { - return mockAsciidoctorMojo(AsciidoctorZipMojo.class, null, null); + return mojoMocker.mock(AsciidoctorZipMojo.class, null, null); } - @SneakyThrows public static AsciidoctorMojo mockAsciidoctorMojo(Map mavenProperties) { - return mockAsciidoctorMojo(AsciidoctorMojo.class, mavenProperties, null); + return mojoMocker.mock(AsciidoctorMojo.class, mavenProperties, null); } - @SneakyThrows public static AsciidoctorMojo mockAsciidoctorMojo(LogHandler logHandler) { - return mockAsciidoctorMojo(AsciidoctorMojo.class, null, logHandler); - } - - @SneakyThrows - @SuppressWarnings("unchecked") - private static T mockAsciidoctorMojo(Class clazz, Map mavenProperties, LogHandler logHandler) { - final MavenProject mavenProject = Mockito.mock(MavenProject.class); - when(mavenProject.getBasedir()).thenReturn(new File(".")); - if (mavenProperties != null) { - final Properties properties = new Properties(); - properties.putAll(mavenProperties); - when(mavenProject.getProperties()).thenReturn(properties); - } - - final AsciidoctorMojo mojo = (AsciidoctorMojo) clazz.getConstructor(new Class[]{}).newInstance(); - parametersInitializer.initialize(mojo); - setVariableValueInObject(mojo, "log", new SystemStreamLog()); - mojo.project = mavenProject; - if (logHandler != null) - setVariableValueInObject(mojo, "logHandler", logHandler); - - return (T) mojo; - } - - @SneakyThrows - public static String readAsString(File file) { - return IOUtils.toString(new FileReader(file)); - } - - @SneakyThrows - public static void writeToFile(File parent, String filename, String... lines) { - FileOutputStream fileOutputStream = new FileOutputStream(new File(parent, filename)); - for (String line : lines) { - IOUtils.write(line, fileOutputStream, StandardCharsets.UTF_8); - } + return mojoMocker.mock(AsciidoctorMojo.class, null, logHandler); } public static class ResourceBuilder { @@ -152,7 +96,7 @@ public static List excludeAll() { public static void assertEqualsStructure(File[] expected, File[] actual) { List sanitizedExpected = Arrays.stream(expected) - .filter(TestUtils::isHidden) + .filter(TestUtils::isNotHidden) .collect(Collectors.toList()); List expectedNames = sanitizedExpected.stream().map(File::getName).collect(Collectors.toList()); @@ -180,8 +124,8 @@ public static void assertEqualsStructure(File[] expected, File[] actual) { } } - private static boolean isHidden(File file) { - char firstChar = file.getName().charAt(0); + private static boolean isNotHidden(File file) { + final char firstChar = file.getName().charAt(0); return firstChar != '_' && firstChar != '.'; } }