1 /* 2 * ************************************************************************************************************************************************************* 3 * 4 * TheseFoolishThings: Miscellaneous utilities 5 * http://tidalwave.it/projects/thesefoolishthings 6 * 7 * Copyright (C) 2009 - 2024 by Tidalwave s.a.s. (http://tidalwave.it) 8 * 9 * ************************************************************************************************************************************************************* 10 * 11 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 12 * You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 17 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 18 * 19 * ************************************************************************************************************************************************************* 20 * 21 * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src 22 * git clone https://github.com/tidalwave-it/thesefoolishthings-src 23 * 24 * ************************************************************************************************************************************************************* 25 */ 26 package it.tidalwave.util.test; 27 28 import javax.annotation.Nonnull; 29 import java.util.List; 30 import java.io.FileNotFoundException; 31 import java.io.IOException; 32 import java.nio.file.Files; 33 import java.nio.file.Path; 34 import java.nio.file.Paths; 35 import lombok.RequiredArgsConstructor; 36 import lombok.extern.slf4j.Slf4j; 37 import static java.nio.charset.StandardCharsets.UTF_8; 38 import static it.tidalwave.util.test.FileComparisonUtils.assertSameContents; 39 import static lombok.AccessLevel.PRIVATE; 40 41 /*************************************************************************************************************************************************************** 42 * 43 * A facility that provides some common tasks for testing, such as manipulating test files. 44 * 45 * @author Fabrizio Giudici 46 * @since 3.2-ALPHA-18 47 * 48 **************************************************************************************************************************************************************/ 49 @RequiredArgsConstructor @Slf4j 50 public class BaseTestHelper 51 { 52 @Nonnull 53 protected final Object test; 54 55 /*********************************************************************************************************************************************************** 56 * Returns a {@link Path} for a resource file. The resource should be placed under 57 * {@code src/test/resources/test-class-simple-name/test-resources/resource-name}. Note that the file actually 58 * loaded is the one under {@code target/test-classes} copied there (and eventually filtered) by Maven. 59 * 60 * @param resourceName the resource name 61 * @return the {@code Path} 62 **********************************************************************************************************************************************************/ 63 @Nonnull 64 public Path resourceFileFor (@Nonnull final String resourceName) 65 { 66 final var testName = test.getClass().getSimpleName(); 67 return Paths.get("target/test-classes", testName, "test-resources", resourceName); 68 } 69 70 /*********************************************************************************************************************************************************** 71 * Reads the content from the resource file as a single string. See {@link #resourceFileFor(String)} for 72 * further info. 73 * 74 * @param resourceName the resource name 75 * @return the string 76 * @throws IOException in case of error 77 **********************************************************************************************************************************************************/ 78 @Nonnull 79 public String readStringFromResource (@Nonnull final String resourceName) 80 throws IOException 81 { 82 final var file = resourceFileFor(resourceName); 83 final var buffer = new StringBuilder(); 84 var separator = ""; 85 86 for (final var string : Files.readAllLines(file, UTF_8)) 87 { 88 buffer.append(separator).append(string); 89 separator = "\n"; 90 } 91 92 return buffer.toString(); 93 // return String.join("\n", Files.readAllLines(path, UTF_8)); TODO JDK 8 94 } 95 96 /*********************************************************************************************************************************************************** 97 * Create a {@link TestResource} for the given name. The actual file will be created under 98 * {@code target/test-artifacts/test-class-simple-name/resourceName}. The expected file should be 99 * placed in {@code src/test/resources/test-class-simple-name/expected-results/resource-name}. Note that the file 100 * actually loaded is the one under {@code target/test-classes} copied there (and eventually filtered) by Maven. 101 * The {@code test-class-simple-name} is tried first with the current test, and then with its eventual 102 * super-classes; this allows to extend existing test suites. Note that if the resource files for a super class are 103 * not in the current project module, they should be explicitly copied here (for instance, by means of the 104 * Maven dependency plugin). 105 * 106 * @param resourceName the name 107 * @return the {@code TestResource} 108 * @throws IOException in case of error 109 **********************************************************************************************************************************************************/ 110 @Nonnull 111 public TestResource testResourceFor (@Nonnull final String resourceName) 112 throws IOException 113 { 114 final var testName = test.getClass().getSimpleName(); 115 final var expectedFile = findExpectedFilePath(resourceName); 116 final var actualFile = Paths.get("target/test-artifacts", testName, resourceName); 117 Files.createDirectories(actualFile.getParent()); 118 return new TestResource(resourceName, actualFile, expectedFile); 119 } 120 121 /*********************************************************************************************************************************************************** 122 * 123 **********************************************************************************************************************************************************/ 124 @Nonnull 125 private Path findExpectedFilePath (@Nonnull final String resourceName) 126 throws IOException 127 { 128 for (var testClass = test.getClass(); testClass != null; testClass = testClass.getSuperclass()) 129 { 130 final var expectedFile = 131 Paths.get("target/test-classes", testClass.getSimpleName(), "expected-results", resourceName); 132 133 if (Files.exists(expectedFile)) 134 { 135 return expectedFile; 136 } 137 } 138 139 throw new FileNotFoundException("Expected file for test " + resourceName); 140 } 141 142 /*********************************************************************************************************************************************************** 143 * A manipulator of a pair of (actual file, expected file). 144 **********************************************************************************************************************************************************/ 145 @RequiredArgsConstructor(access = PRIVATE) 146 public final class TestResource 147 { 148 @Nonnull 149 private final String name; 150 151 @Nonnull 152 private final Path actualFile; 153 154 @Nonnull 155 private final Path expectedFile; 156 157 /*************************************************************************************************************** 158 * 159 * Assert that the content of the actual file are the same as the expected file. 160 * 161 * @throws IOException in case of error 162 * 163 **************************************************************************************************************/ 164 public void assertActualFileContentSameAsExpected () 165 throws IOException 166 { 167 assertSameContents(expectedFile.toFile(), actualFile.toFile()); 168 } 169 170 /*************************************************************************************************************** 171 * 172 * Writes the given strings to the actual file. 173 * 174 * @param strings the strings 175 * @throws IOException in case of error 176 * 177 **************************************************************************************************************/ 178 public void writeToActualFile (@Nonnull final String... strings) 179 throws IOException 180 { 181 writeToActualFile(List.of(strings)); 182 } 183 184 /*************************************************************************************************************** 185 * 186 * Writes the given strings to the actual file. 187 * 188 * @param strings the strings 189 * @throws IOException in case of error 190 * 191 **************************************************************************************************************/ 192 public void writeToActualFile (@Nonnull final Iterable<String> strings) 193 throws IOException 194 { 195 Files.write(actualFile, strings, UTF_8); 196 } 197 198 /*************************************************************************************************************** 199 * 200 * Writes the given bytes to the actual file. 201 * 202 * @param bytes the bytes 203 * @throws IOException in case of error 204 * 205 **************************************************************************************************************/ 206 public void writeToActualFile (@Nonnull final byte[] bytes) 207 throws IOException 208 { 209 Files.write(actualFile, bytes); 210 } 211 212 /*************************************************************************************************************** 213 * 214 * Reads the content from the resource file as a single string. 215 * 216 * @return the string 217 * @throws IOException in case of error 218 * 219 **************************************************************************************************************/ 220 @Nonnull 221 public String readStringFromResource () 222 throws IOException 223 { 224 return BaseTestHelper.this.readStringFromResource(name); 225 } 226 } 227 }