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 }