View Javadoc
1   /*
2    * SPDX-License-Identifier: LGPL-2.1-or-later
3    * See LICENSE file for details.
4    *
5    * Copyright 2012-2026 Hazendaz.
6    */
7   package com.github.hazendaz.maven.yuicompressor_maven_plugin;
8   
9   import java.lang.reflect.Field;
10  
11  import org.apache.maven.plugin.MojoExecutionException;
12  import org.junit.jupiter.api.Assertions;
13  import org.junit.jupiter.api.Test;
14  
15  /**
16   * Tests for the generated {@link HelpMojo}.
17   * <p>
18   * The HelpMojo is generated by maven-plugin-tools and loads its metadata from
19   * {@code /META-INF/maven/com.github.hazendaz.maven/yuicompressor-maven-plugin/plugin-help.xml} which is present on the
20   * test classpath via {@code target/classes}.
21   */
22  class HelpMojoTest {
23  
24      // ---------------------------------------------------------------- helpers
25  
26      /**
27       * Creates a HelpMojo with its fields set via reflection.
28       *
29       * @param goal
30       *            goal filter (may be null/empty to list all goals)
31       * @param detail
32       *            whether to show all parameters
33       * @param lineLength
34       *            display line length
35       * @param indentSize
36       *            indent size in spaces
37       *
38       * @return configured HelpMojo
39       *
40       * @throws Exception
41       *             if reflection fails
42       */
43      private HelpMojo createMojo(String goal, boolean detail, int lineLength, int indentSize) throws Exception {
44          final var mojo = new HelpMojo();
45          setField(mojo, "goal", goal);
46          setField(mojo, "detail", detail);
47          setField(mojo, "lineLength", lineLength);
48          setField(mojo, "indentSize", indentSize);
49          return mojo;
50      }
51  
52      /**
53       * Sets a private field on an object via reflection.
54       *
55       * @param target
56       *            the object to modify
57       * @param fieldName
58       *            the field name
59       * @param value
60       *            the value to set
61       *
62       * @throws Exception
63       *             if reflection fails
64       */
65      private static void setField(Object target, String fieldName, Object value) throws Exception {
66          Class<?> clazz = target.getClass();
67          Field field = null;
68          while (clazz != null) {
69              try {
70                  field = clazz.getDeclaredField(fieldName);
71                  break;
72              } catch (NoSuchFieldException e) {
73                  clazz = clazz.getSuperclass();
74              }
75          }
76          if (field == null) {
77              throw new NoSuchFieldException(fieldName);
78          }
79          field.setAccessible(true);
80          field.set(target, value);
81      }
82  
83      // ------------------------------------------------------------------ tests
84  
85      /**
86       * Execute with default parameters (no goal filter, no detail) should list all plugin goals without error.
87       *
88       * @throws Exception
89       *             if execution fails
90       */
91      @Test
92      void testExecute_defaultParams_listsAllGoals() throws Exception {
93          final var mojo = createMojo(null, false, 80, 2);
94          Assertions.assertDoesNotThrow(mojo::execute, "execute() with default params should not throw");
95      }
96  
97      /**
98       * Execute with goal="compress" should display help for that specific goal only.
99       *
100      * @throws Exception
101      *             if execution fails
102      */
103     @Test
104     void testExecute_withSpecificGoal_compress() throws Exception {
105         final var mojo = createMojo("compress", false, 80, 2);
106         Assertions.assertDoesNotThrow(mojo::execute, "execute() with goal='compress' should not throw");
107     }
108 
109     /**
110      * Execute with goal="jslint" should display help for that specific goal.
111      *
112      * @throws Exception
113      *             if execution fails
114      */
115     @Test
116     void testExecute_withSpecificGoal_jslint() throws Exception {
117         final var mojo = createMojo("jslint", false, 80, 2);
118         Assertions.assertDoesNotThrow(mojo::execute, "execute() with goal='jslint' should not throw");
119     }
120 
121     /**
122      * Execute with goal="help" should display help for the help goal.
123      *
124      * @throws Exception
125      *             if execution fails
126      */
127     @Test
128     void testExecute_withSpecificGoal_help() throws Exception {
129         final var mojo = createMojo("help", false, 80, 2);
130         Assertions.assertDoesNotThrow(mojo::execute, "execute() with goal='help' should not throw");
131     }
132 
133     /**
134      * Execute with detail=true and no goal filter should show all parameters for all goals.
135      *
136      * @throws Exception
137      *             if execution fails
138      */
139     @Test
140     void testExecute_detailTrue_allGoals() throws Exception {
141         final var mojo = createMojo(null, true, 80, 2);
142         Assertions.assertDoesNotThrow(mojo::execute, "execute() with detail=true should not throw");
143     }
144 
145     /**
146      * Execute with detail=true and a specific goal should show all parameters for that goal.
147      *
148      * @throws Exception
149      *             if execution fails
150      */
151     @Test
152     void testExecute_detailTrue_specificGoal() throws Exception {
153         final var mojo = createMojo("compress", true, 80, 2);
154         Assertions.assertDoesNotThrow(mojo::execute, "execute() with detail=true and goal='compress' should not throw");
155     }
156 
157     /**
158      * Execute with detail=true for jslint goal should show all parameters.
159      *
160      * @throws Exception
161      *             if execution fails
162      */
163     @Test
164     void testExecute_detailTrue_jslintGoal() throws Exception {
165         final var mojo = createMojo("jslint", true, 80, 2);
166         Assertions.assertDoesNotThrow(mojo::execute, "execute() with detail=true and goal='jslint' should not throw");
167     }
168 
169     /**
170      * Execute with lineLength &lt;= 0 should log a warning and use the default of 80.
171      *
172      * @throws Exception
173      *             if execution fails
174      */
175     @Test
176     void testExecute_invalidLineLength_usesDefault() throws Exception {
177         final var mojo = createMojo(null, false, 0, 2);
178         Assertions.assertDoesNotThrow(mojo::execute, "execute() with lineLength=0 should not throw");
179     }
180 
181     /**
182      * Execute with indentSize &lt;= 0 should log a warning and use the default of 2.
183      *
184      * @throws Exception
185      *             if execution fails
186      */
187     @Test
188     void testExecute_invalidIndentSize_usesDefault() throws Exception {
189         final var mojo = createMojo(null, false, 80, 0);
190         Assertions.assertDoesNotThrow(mojo::execute, "execute() with indentSize=0 should not throw");
191     }
192 
193     /**
194      * Execute with both lineLength and indentSize invalid.
195      *
196      * @throws Exception
197      *             if execution fails
198      */
199     @Test
200     void testExecute_bothInvalid_usesDefaults() throws Exception {
201         final var mojo = createMojo(null, false, -1, -1);
202         Assertions.assertDoesNotThrow(mojo::execute,
203                 "execute() with both lineLength and indentSize invalid should not throw");
204     }
205 
206     /**
207      * Execute with a non-existent goal still completes but outputs nothing for that goal.
208      *
209      * @throws Exception
210      *             if execution fails
211      */
212     @Test
213     void testExecute_unknownGoal_noOutput() throws Exception {
214         final var mojo = createMojo("nonexistent-goal", false, 80, 2);
215         Assertions.assertDoesNotThrow(mojo::execute, "execute() with unknown goal should not throw");
216     }
217 
218     /**
219      * Execute with a very short lineLength to exercise line-wrapping.
220      *
221      * @throws Exception
222      *             if execution fails
223      */
224     @Test
225     void testExecute_shortLineLength_wrapsLines() throws Exception {
226         final var mojo = createMojo(null, false, 40, 2);
227         Assertions.assertDoesNotThrow(mojo::execute, "execute() with short lineLength should not throw");
228     }
229 
230     /**
231      * Execute with a large indentSize and detail enabled to exercise the parameter output.
232      *
233      * @throws Exception
234      *             if execution fails
235      */
236     @Test
237     void testExecute_largeIndentSize_detail() throws Exception {
238         final var mojo = createMojo("compress", true, 120, 4);
239         Assertions.assertDoesNotThrow(mojo::execute, "execute() with large indent and detail should not throw");
240     }
241 
242     /**
243      * Execute with an empty string goal (same as null – lists all goals).
244      *
245      * @throws Exception
246      *             if execution fails
247      */
248     @Test
249     void testExecute_emptyGoal_listsAllGoals() throws Exception {
250         final var mojo = createMojo("", false, 80, 2);
251         Assertions.assertDoesNotThrow(mojo::execute, "execute() with empty goal should not throw");
252     }
253 
254     /**
255      * Verify that execute succeeds when the plugin-help.xml resource is on the classpath.
256      *
257      * @throws MojoExecutionException
258      *             if execution fails unexpectedly
259      */
260     @Test
261     void testExecute_pluginHelpXmlPresent_doesNotThrow() throws MojoExecutionException {
262         final var mojo = new HelpMojo();
263         Assertions.assertDoesNotThrow(mojo::execute,
264                 "Normal execute should succeed when plugin-help.xml is on classpath");
265     }
266 }