View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   */
19  package org.apache.rat.testhelpers.data;
20  
21  import java.nio.file.Path;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.List;
25  import java.util.Objects;
26  import java.util.function.Consumer;
27  import org.apache.commons.cli.Option;
28  import org.apache.commons.lang3.tuple.ImmutablePair;
29  import org.apache.commons.lang3.tuple.Pair;
30  import org.apache.commons.text.WordUtils;
31  import org.apache.rat.ui.ArgumentTracker;
32  import org.apache.rat.utils.CasedString;
33  import org.apache.rat.utils.FileUtils;
34  
35  /**
36   * The definition of a test.
37   */
38  public final class TestData implements Comparable<TestData> {
39      /** If set, the expected exception from the test. */
40      private Exception expectedException;
41      /** The sub name of the test. */
42      private final String name;
43      /**
44       * The command line for the test.
45       * It is encoded as an option followed by an array of String arguments of that option.
46       */
47      private final List<ImmutablePair<Option, String[]>> commandLine;
48      /** A function to set up the test in a specific path. */
49      private final Consumer<Path> setupFiles;
50      /** A function to test the results of the test. */
51      private final Consumer<ValidatorData> validator;
52  
53      /**
54       * Constructs the Test data
55       * @param name the sub name of the test. Must not be {@code null} but may be an empty string. Should
56       * be specified in Camel case for multiple words.
57       * @param commandLine the command line for the test. May not be {@code null} but may consist of a single {@link ImmutablePair#nullPair()}.
58       * @param setupFiles the method to set up the files for the test. Must not be {@code null}.
59       * @param validator the validator for the results of the test. Must not be {@code null}.
60       */
61      public TestData(String name, List<ImmutablePair<Option, String[]>> commandLine,
62               Consumer<Path> setupFiles,
63               Consumer<ValidatorData> validator) {
64          Objects.requireNonNull(name, " name must not be null");
65          Objects.requireNonNull(commandLine, "commandLine must not be null");
66          Objects.requireNonNull(setupFiles, "setupFiles must not be null");
67          Objects.requireNonNull(validator, "validator must not be null");
68          if (name.contains("/")) {
69              throw new IllegalArgumentException("name must not contain '/', use camel case instead");
70          }
71          if (commandLine.isEmpty()) {
72              throw new IllegalArgumentException("commandLine may not be empty but must contain an ImmutablePair.nullPair()");
73          }
74          this.name = name;
75          this.commandLine = commandLine;
76          this.setupFiles = setupFiles;
77          this.validator = validator;
78          this.expectedException = null;
79      }
80  
81      @Override
82      public String toString() {
83          return getTestName();
84      }
85  
86      /**
87       * Sets the exception expected from this test.
88       * @param expectedException the expected exception.
89       */
90      void setException(Exception expectedException) {
91          this.expectedException = expectedException;
92      }
93  
94      /**
95       * The option for the test. This is the first option specified in the command line.
96       * If the command line is empty this returns {@code null}.
97       * @return the first option in the command line or {@code null} if there is no option.
98       */
99      public Option getOption() {
100         return commandLine.get(0).getLeft();
101     }
102 
103     /**
104      * Get the sub name for this test.
105      * @return the sub name for this test.
106      */
107     public String getName() {
108         return name;
109     }
110 
111     /**
112      * Gets the expected exception or {@code null} if no exception is expected.
113      * @return the expected exception or {@code null} if no exception is expected.
114      */
115     public Exception getExpectedException() {
116         return expectedException;
117     }
118 
119     /**
120      * Determines if the test is expecting an exception.
121      * @return {@code true} if the test is expecting to throw an exception.
122      */
123     public boolean expectingException() {
124         return expectedException != null;
125     }
126 
127     /**
128      * Gets the command line as the string objects that are normally parsed by the
129      * command line parser.
130      * @return the command line strings.
131      */
132     public String[] getCommandLine() {
133         return getCommandLine(null);
134     }
135 
136     /**
137      * Gets the command line as the string objects that are normally parsed by the
138      * command line parser. The result will include {@code "--"} to terminate a trailing multi
139      * argument option.
140      * @param workingDir the directory to add to the command line. May be {@code null}.
141      * @return the command line strings.
142      */
143     public String[] getCommandLine(String workingDir) {
144         List<String> args = new ArrayList<>(commandLine.size());
145         final boolean[] lastWasMultiArg = {false};
146         commandLine.forEach(pair -> {
147             if (pair.getKey() != null) {
148                 if (pair.getKey().hasLongOpt()) {
149                     args.add("--" + pair.getKey().getLongOpt());
150                 } else {
151                     args.add("-" + pair.getKey().getOpt());
152                 }
153                 if (pair.getValue() != null) {
154                     args.addAll(Arrays.asList(pair.getValue()));
155                 }
156                 lastWasMultiArg[0] = pair.getKey().hasArgs();
157             } else {
158                 lastWasMultiArg[0] = false;
159             }
160         });
161         if (lastWasMultiArg[0]) {
162             args.add("--");
163         }
164         if (workingDir != null) {
165             args.add(workingDir);
166         }
167         return args.toArray(new String[0]);
168     }
169 
170     /**
171      * Get the arguments for the command line.
172      * @return the arguments for the command line as Option, String[] pairs.
173      */
174     public List<? extends Pair<Option, String[]>> getArgs() {
175         return commandLine;
176     }
177 
178     /**
179      * Gets the validator for the test.
180      * @return the validator for the test.
181      */
182     public Consumer<ValidatorData> getValidator() {
183         return validator;
184     }
185 
186     /**
187      * Sets up the files for the test.
188      * @param path the path to use as the base directory. Subdirectories and files may be added
189      * to this path.
190      */
191     public void setupFiles(Path path) {
192         FileUtils.mkDir(path.toFile());
193         setupFiles.accept(path);
194     }
195 
196     /**
197      * Gets the test name. This is the option concatenated with the name.
198      * @return the unique test name
199      */
200     public String getTestName() {
201          new ArrayList<>();
202         String result = null;
203         if (getOption() == null) {
204             result = name + "_DefaultTest";
205         } else {
206             result = new CasedString(CasedString.StringCase.KEBAB, ArgumentTracker.extractKey(getOption())).toString();
207             if (!name.isEmpty()) {
208                 result += "/" + name;
209             }
210         }
211         return result;
212     }
213 
214     /**
215      * Gets the test name as a class name. This is based on the option concatenated with the name.
216      * @return the unique Java class name
217      */
218     public String getClassName() {
219         if (getOption() == null) {
220             return WordUtils.capitalize(name) + "_DefaultTest";
221         } else {
222             List<String> parts = new ArrayList<>(Arrays.asList(new CasedString(CasedString.StringCase.KEBAB, ArgumentTracker.extractKey(getOption())).getSegments()));
223             if (!name.isEmpty()) {
224                 parts.addAll(Arrays.asList(new CasedString(CasedString.StringCase.CAMEL, name).getSegments()));
225             }
226             return CasedString.StringCase.PASCAL.assemble(parts.toArray(new String[0]));
227         }
228     }
229 
230     @Override
231     public int compareTo(TestData other) {
232         return getTestName().compareTo(other.getTestName());
233     }
234 }