001/* 002 * Copyright (C) 2022 - 2023, the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.github.ascopes.jct.workspaces; 017 018import java.io.File; 019import java.io.InputStream; 020import java.net.URL; 021import java.nio.charset.Charset; 022import java.nio.file.Path; 023import org.apiguardian.api.API; 024import org.apiguardian.api.API.Status; 025 026/** 027 * Chainable builder for creating individual files. 028 * 029 * @author Ashley Scopes 030 * @since 0.0.1 031 */ 032@API(since = "0.0.1", status = Status.STABLE) 033@SuppressWarnings("unused") 034public interface FileBuilder { 035 036 /** 037 * Create the file with the given contents as UTF-8. 038 * 039 * <p>If you are using multi-line strings, an example of usage would be: 040 * 041 * <pre><code> 042 * directory 043 * .createFile("org", "example", "HelloWorld.java") 044 * .withContents(""" 045 * package org.example; 046 * 047 * public class HelloWorld { 048 * public static void main(String[] args) { 049 * System.out.println("Hello, World!"); 050 * } 051 * } 052 * """); 053 * </code></pre> 054 * 055 * <p>If the Java language level of your tests does not support multi-line strings, you can 056 * alternatively pass each line of text to write as a separate string. These will be written 057 * to the file using line-feed {@code '\n'} separators. For example: 058 * 059 * <pre><code> 060 * directory 061 * .createFile("org", "example", "HelloWorld.java") 062 * .withContents( 063 * "package org.example;", 064 * "", 065 * "public class HelloWorld {", 066 * " public static void main(String[] args) {", 067 * " System.out.println(\"Hello, World!\");", 068 * " }", 069 * "}" 070 * ); 071 * </code></pre> 072 * 073 * @param lines the lines to write using the default charset. 074 * @return the root managed directory for further configuration. 075 * @see #withContents(Charset, String...) 076 * @see #withContents(byte[]) 077 */ 078 ManagedDirectory withContents(String... lines); 079 080 /** 081 * Create the file with the given contents. 082 * 083 * <pre><code> 084 * directory 085 * .createFile("org", "example", "HelloWorld.java") 086 * .withContents(StandardCharsets.US_ASCII, """ 087 * package org.example; 088 * 089 * public class HelloWorld { 090 * public static void main(String[] args) { 091 * System.out.println("Hello, World!"); 092 * } 093 * } 094 * """); 095 * </code></pre> 096 * 097 * <p>If the Java language level of your tests does not support multi-line strings, you can 098 * alternatively pass each line of text to write as a separate string. These will be written 099 * to the file using line-feed {@code '\n'} separators. For example: 100 * 101 * <pre><code> 102 * directory 103 * .createFile("org", "example", "HelloWorld.java") 104 * .withContents( 105 * StandardCharsets.US_ASCII, 106 * "package org.example;", 107 * "", 108 * "public class HelloWorld {", 109 * " public static void main(String[] args) {", 110 * " System.out.println(\"Hello, World!\");", 111 * " }", 112 * "}" 113 * ); 114 * </code></pre> 115 * 116 * @param charset the character encoding to use. 117 * @param lines the lines to write. 118 * @return the root managed directory for further configuration. 119 * @see #withContents(String...) 120 * @see #withContents(byte[]) 121 */ 122 ManagedDirectory withContents(Charset charset, String... lines); 123 124 /** 125 * Create the file with the given byte contents. 126 * 127 * <pre><code> 128 * var classFile = new byte[]{ 129 * -54, -2, -70, -66, 0, 0, 0, 63, 0, 29, 10, 0, 2, 0, 3, 7, 0, 4, 12, 0, 5, 0, 6, 1, 0, 130 * 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, 6, 131 * 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 9, 0, 8, 0, 9, 7, 0, 10, 12, 0, 11, 132 * 0, 12, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 121, 115, 116, 101, 133 * 109, 1, 0, 3, 111, 117, 116, 1, 0, 21, 76, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 134 * 105, 110, 116, 83, 116, 114, 101, 97, 109, 59, 8, 0, 14, 1, 0, 13, 72, 101, 108, 108, 135 * 111, 44, 32, 87, 111, 114, 108, 100, 33, 10, 0, 16, 0, 17, 7, 0, 18, 12, 0, 19, 0, 20, 136 * 1, 0, 19, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 105, 110, 116, 83, 116, 114, 101, 137 * 97, 109, 1, 0, 7, 112, 114, 105, 110, 116, 108, 110, 1, 0, 21, 40, 76, 106, 97, 118, 97, 138 * 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 7, 0, 22, 1, 0, 10, 139 * 72, 101, 108, 108, 111, 87, 111, 114, 108, 100, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 140 * 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 4, 109, 97, 105, 141 * 110, 1, 0, 22, 40, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 142 * 105, 110, 103, 59, 41, 86, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 143 * 0, 15, 72, 101, 108, 108, 111, 87, 111, 114, 108, 100, 46, 106, 97, 118, 97, 0, 33, 0, 144 * 21, 0, 2, 0, 0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 23, 0, 0, 0, 29, 0, 1, 0, 1, 0, 145 * 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 1, 0, 24, 0, 0, 0, 6, 0, 1, 0, 0, 0, 1, 0, 9, 0, 146 * 25, 0, 26, 0, 1, 0, 23, 0, 0, 0, 37, 0, 2, 0, 1, 0, 0, 0, 9, -78, 0, 7, 18, 13, -74, 0, 147 * 15, -79, 0, 0, 0, 1, 0, 24, 0, 0, 0, 10, 0, 2, 0, 0, 0, 3, 0, 8, 0, 4, 0, 1, 0, 27, 0, 148 * 0, 0, 2, 0, 28 149 * }; 150 * 151 * directory 152 * .createFile("HelloWorld.class") 153 * .withContents(classFile); 154 * </code></pre> 155 * 156 * @param contents the bytes to write. 157 * @return the root managed directory for further configuration. 158 */ 159 ManagedDirectory withContents(byte[] contents); 160 161 /** 162 * Copy a resource from the class loader on the current thread into the file system. 163 * 164 * <pre><code> 165 * directory 166 * .createFile("org", "example", "HelloWorld.class") 167 * .copiedFromClassPath("org/example/HelloWorld.class"); 168 * </code></pre> 169 * 170 * @param resource the resource to copy. 171 * @return the root managed directory for further configuration. 172 */ 173 ManagedDirectory copiedFromClassPath(String resource); 174 175 /** 176 * Copy a resource from the given class loader into the file system. 177 * 178 * <pre><code> 179 * var classLoader = getClass().getClassLoader(); 180 * 181 * directory 182 * .createFile("org", "example", "HelloWorld.class") 183 * .copiedFromClassPath(classLoader, "org/example/HelloWorld.class"); 184 * </code></pre> 185 * 186 * @param classLoader the class loader to use. 187 * @param resource the resource to copy. 188 * @return the root managed directory for further configuration. 189 */ 190 ManagedDirectory copiedFromClassPath(ClassLoader classLoader, String resource); 191 192 /** 193 * Copy the contents from the given file into the file system. 194 * 195 * <pre><code> 196 * var file = new File("src/test/resources/code/HelloWorld.java"); 197 * 198 * directory 199 * .createFile("org", "example", "HelloWorld.java") 200 * .copiedFromFile(file); 201 * </code></pre> 202 * 203 * @param file the file to read. 204 * @return the root managed directory for further configuration. 205 */ 206 ManagedDirectory copiedFromFile(File file); 207 208 /** 209 * Copy the contents from the given path into the file system. 210 * 211 * <pre><code> 212 * var file = Path.of("src", "test", "resources", "code", "HelloWorld.java"); 213 * 214 * directory 215 * .createFile("org", "example", "HelloWorld.java") 216 * .copiedFromFile(file); 217 * </code></pre> 218 * 219 * @param file the file to read. 220 * @return the root managed directory for further configuration. 221 */ 222 ManagedDirectory copiedFromFile(Path file); 223 224 /** 225 * Copy the contents from the given URL into the file system. 226 * 227 * <pre><code> 228 * var url = URI.create("file:///code/org/example/HelloWorld.java").toURI(); 229 * 230 * directory 231 * .createFile("org", "example", "HelloWorld.java") 232 * .copiedFromUrl(url); 233 * </code></pre> 234 * 235 * @param url the URL to read. 236 * @return the root managed directory for further configuration. 237 */ 238 ManagedDirectory copiedFromUrl(URL url); 239 240 /** 241 * Create the file but do not put anything in it. 242 * 243 * <p>The resultant file will be 0 bytes long. 244 * 245 * <pre><code> 246 * directory 247 * .createFile(".gitkeep") 248 * .thatIsEmpty(); 249 * </code></pre> 250 * 251 * @return the root managed directory for further configuration. 252 */ 253 ManagedDirectory thatIsEmpty(); 254 255 /** 256 * Copy the contents from the given input stream into the file system. 257 * 258 * <p>The input stream will be closed when reading completes. 259 * 260 * <pre><code> 261 * try (var is = getClass().getResourceAsStream("code/examples/HelloWorld.java")) { 262 * directory 263 * .createFile("org", "example", "HelloWorld.java") 264 * .fromInputStream(is); 265 * } 266 * </code></pre> 267 * 268 * @param inputStream the input stream to read. 269 * @return the root managed directory for further configuration. 270 */ 271 ManagedDirectory fromInputStream(InputStream inputStream); 272}