Class |
Line # |
Actions |
|||||
---|---|---|---|---|---|---|---|
Approvals | 50 | 42 | 0% | 19 | 28 | ||
Approvals.IsEqualCompressingWhiteSpace | 222 | 14 | 0% | 9 | 13 |
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.devacfr.testing.util; | |
20 | ||
21 | import javax.annotation.Nonnull; | |
22 | import javax.annotation.Nullable; | |
23 | ||
24 | import java.io.File; | |
25 | import java.io.IOException; | |
26 | import java.io.StringReader; | |
27 | import java.nio.file.Path; | |
28 | import java.util.function.Function; | |
29 | ||
30 | import com.cloudbees.diff.Diff; | |
31 | import com.cloudbees.diff.provider.BuiltInDiffProvider; | |
32 | import com.google.common.base.Charsets; | |
33 | import com.google.common.base.Strings; | |
34 | import com.google.common.io.CharSink; | |
35 | import com.google.common.io.Files; | |
36 | import com.google.common.io.Resources; | |
37 | import org.hamcrest.Description; | |
38 | import org.hamcrest.Matcher; | |
39 | import org.hamcrest.StringDescription; | |
40 | import org.hamcrest.TypeSafeMatcher; | |
41 | ||
42 | import static com.google.common.base.Throwables.throwIfUnchecked; | |
43 | import static org.hamcrest.MatcherAssert.assertThat; | |
44 | import static org.hamcrest.Matchers.equalToCompressingWhiteSpace; | |
45 | ||
46 | /** | |
47 | * @author Christophe Friederich | |
48 | * @since 1.0 | |
49 | */ | |
50 | public final class Approvals { | |
51 | ||
52 | public static final Function<String, String> REMOVE_CARRIAGE_RETURN_LINEFEED = text -> text.replaceAll("\r", ""); | |
53 | ||
54 | 0 | private Approvals() { |
55 | 0 | throw new UnsupportedOperationException(); |
56 | } | |
57 | ||
58 | /** | |
59 | * @param location | |
60 | * path location of actual fil. | |
61 | * @param testClass | |
62 | * the executed test class. | |
63 | * @param testName | |
64 | * the testname | |
65 | * @param extension | |
66 | * the extension file | |
67 | * @return | |
68 | * @throws IOException | |
69 | */ | |
70 | 31 | public static String getActualResource(@Nonnull final Path location, |
71 | @Nonnull final Class<?> testClass, | |
72 | @Nonnull final String testName, | |
73 | @Nullable final String extension) { | |
74 | 31 | final String suf = !Strings.isNullOrEmpty(extension) ? "." + extension : ""; |
75 | 31 | final String fileName = String.format("%s.%s.actual%s", testClass.getSimpleName(), testName, suf); |
76 | 31 | return readFile(location.resolve(fileName)); |
77 | } | |
78 | ||
79 | /** | |
80 | * @param location | |
81 | * path location of expected file. | |
82 | * @param testClass | |
83 | * the executed test class. | |
84 | * @param testName | |
85 | * the testname. | |
86 | * @param extension | |
87 | * the extension file. | |
88 | * @return | |
89 | * @throws IOException | |
90 | */ | |
91 | 23 | public static String getExpectedResource(@Nonnull final Path location, |
92 | @Nonnull final Class<?> testClass, | |
93 | @Nonnull final String testName, | |
94 | @Nullable final String extension, | |
95 | @Nullable final Function<String, String> transformer) { | |
96 | 23 | final String ext = !Strings.isNullOrEmpty(extension) ? "." + extension : ""; |
97 | 23 | final String fileName = String.format("%s.%s.approved%s", testClass.getSimpleName(), testName, ext); |
98 | 23 | final String text = Approvals.REMOVE_CARRIAGE_RETURN_LINEFEED.apply(readFile(location.resolve(fileName))); |
99 | 23 | if (transformer != null) { |
100 | 0 | return transformer.apply(text); |
101 | } | |
102 | 23 | return text; |
103 | } | |
104 | ||
105 | /** | |
106 | * Verify the {@code actual} text is equals to expected text stored in file [testClass].[testName].approved. | |
107 | * | |
108 | * @param location | |
109 | * path location of expected file. | |
110 | * @param testClass | |
111 | * the executed test class. | |
112 | * @param testName | |
113 | * the test name. | |
114 | * @param actual | |
115 | * the actual value to test. | |
116 | * @param extension | |
117 | * the extension file. | |
118 | */ | |
119 | 0 | public static void verify(@Nonnull final Path location, |
120 | @Nonnull final Class<?> testClass, | |
121 | @Nonnull final String testName, | |
122 | @Nullable final String actual, | |
123 | @Nullable final String extension) { | |
124 | 0 | final String expected = getExpectedResource(location, testClass, testName, extension, null); |
125 | 0 | assertThat(actual, equalToCompressingWhiteSpace(expected)); |
126 | } | |
127 | ||
128 | 0 | public static void verify(final Path actualFile, final Path expectedFile) { |
129 | 0 | try { |
130 | 0 | final String actual = Files.asCharSource(actualFile.toFile(), Charsets.UTF_8).read(); |
131 | 0 | final String expected = Approvals.REMOVE_CARRIAGE_RETURN_LINEFEED.apply(readFile(expectedFile)); |
132 | 0 | final Matcher<String> matcher = IsEqualCompressingWhiteSpace.equalToCompressingWhiteSpace(expected); |
133 | 0 | if (!matcher.matches(actual)) { |
134 | 0 | final Description description = new StringDescription(); |
135 | 0 | matcher.describeMismatch(actual, description); |
136 | ||
137 | 0 | throw new AssertionError(description.toString()); |
138 | } | |
139 | } catch (final IOException e) { | |
140 | 0 | throwIfUnchecked(e); |
141 | } | |
142 | } | |
143 | ||
144 | /** | |
145 | * Verify the {@code actual} text is equals to expected text stored in file [testClass].[testName].approved. | |
146 | * | |
147 | * @param location | |
148 | * path location of expected file. | |
149 | * @param testClass | |
150 | * the executed test class. | |
151 | * @param testName | |
152 | * the test name | |
153 | * @param transform | |
154 | * transform function | |
155 | * @param extension | |
156 | * the extension file. | |
157 | */ | |
158 | 22 | public static void verify(@Nonnull final Path location, |
159 | @Nonnull final Class<?> testClass, | |
160 | @Nonnull final String testName, | |
161 | final Function<String, String> transform, | |
162 | @Nullable final String extension) { | |
163 | 22 | String actual = getActualResource(location, testClass, testName, extension); |
164 | 22 | if (actual != null && transform != null) { |
165 | 22 | actual = transform.apply(actual); |
166 | } | |
167 | 22 | final String expected = getExpectedResource(location, testClass, testName, extension, null); |
168 | ||
169 | 22 | final File path = new File("target/approval/actual/"); |
170 | 22 | if (!path.exists()) { |
171 | 1 | path.mkdirs(); |
172 | } | |
173 | 22 | final File file = new File(path, testClass.getSimpleName() + "." + testName); |
174 | ||
175 | 22 | final CharSink sink = Files.asCharSink(file, Charsets.UTF_8); |
176 | 22 | try { |
177 | 22 | sink.write(actual); |
178 | } catch (final IOException e) { | |
179 | 0 | throwIfUnchecked(e); |
180 | } | |
181 | ||
182 | 22 | final Matcher<String> matcher = IsEqualCompressingWhiteSpace.equalToCompressingWhiteSpace(expected); |
183 | 22 | if (!matcher.matches(actual)) { |
184 | 0 | final Description description = new StringDescription(); |
185 | 0 | matcher.describeMismatch(actual, description); |
186 | ||
187 | 0 | throw new AssertionError(description.toString()); |
188 | } | |
189 | } | |
190 | ||
191 | /** | |
192 | * Verify the {@code actual} text is equals to expected text stored in file [testClass].[testName].approved. | |
193 | * | |
194 | * @param location | |
195 | * path location of expected file. | |
196 | * @param testClass | |
197 | * the executed test class. | |
198 | * @param testName | |
199 | * the testname | |
200 | * @param actualFile | |
201 | * the actual value stored in file to test | |
202 | * @param extension | |
203 | * the extension file | |
204 | */ | |
205 | 0 | public static void verify(@Nonnull final Path location, |
206 | @Nonnull final Class<?> testClass, | |
207 | @Nonnull final String testName, | |
208 | @Nonnull final Path actualFile, | |
209 | @Nullable final String extension) { | |
210 | ||
211 | 0 | verify(location, testClass, testName, readFile(location.resolve(actualFile)), extension); |
212 | } | |
213 | ||
214 | 54 | private static String readFile(final Path path) { |
215 | 54 | try { |
216 | 54 | return Resources.toString(Resources.getResource(path.toString()), Charsets.UTF_8); |
217 | } catch (final IOException e) { | |
218 | 0 | throw new RuntimeException(e.getMessage(), e); |
219 | } | |
220 | } | |
221 | ||
222 | public static class IsEqualCompressingWhiteSpace extends TypeSafeMatcher<String> { | |
223 | ||
224 | // TODO: Replace String with CharSequence to allow for easy interoperability between | |
225 | // String, StringBuffer, StringBuilder, CharBuffer, etc (joe). | |
226 | ||
227 | private final String string; | |
228 | ||
229 | 22 | public IsEqualCompressingWhiteSpace(final String string) { |
230 | 22 | if (string == null) { |
231 | 0 | throw new IllegalArgumentException("Non-null value required"); |
232 | } | |
233 | 22 | this.string = string; |
234 | } | |
235 | ||
236 | 22 | @Override |
237 | public boolean matchesSafely(final String item) { | |
238 | 22 | return stripSpaces(string).equals(stripSpaces(item)); |
239 | } | |
240 | ||
241 | 0 | @Override |
242 | public void describeMismatchSafely(final String item, final Description mismatchDescription) { | |
243 | 0 | mismatchDescription.appendText(getInternalDiff(item, string)); |
244 | } | |
245 | ||
246 | 0 | @Override |
247 | public void describeTo(final Description description) { | |
248 | 0 | description.appendText("a string equal to ").appendValue(string).appendText(" compressing white space"); |
249 | } | |
250 | ||
251 | 44 | public String stripSpaces(final String toBeStripped) { |
252 | 44 | return toBeStripped.replaceAll("\\s+", " ").trim(); |
253 | } | |
254 | ||
255 | 22 | public static Matcher<String> equalToCompressingWhiteSpace(final String expectedString) { |
256 | 22 | return new IsEqualCompressingWhiteSpace(expectedString); |
257 | } | |
258 | ||
259 | 0 | private String getInternalDiff(final String expected, final String actual) { |
260 | 0 | final BuiltInDiffProvider provider = new BuiltInDiffProvider(); |
261 | 0 | Diff diffs = null; |
262 | 0 | try { |
263 | 0 | diffs = provider.computeDiff(new StringReader(actual), new StringReader(expected)); |
264 | 0 | return diffs |
265 | .toUnifiedDiff("actual", "expected", new StringReader(actual), new StringReader(expected), 10); | |
266 | } catch (final IOException e) { | |
267 | 0 | throw new RuntimeException(e.getMessage(), e); |
268 | } | |
269 | } | |
270 | } | |
271 | } |