001/*
002 * Copyright (C) 2022 - 2024, 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 io.github.ascopes.jct.workspaces.impl.AbstractManagedDirectory;
019import io.github.ascopes.jct.workspaces.impl.RamDirectoryImpl;
020import io.github.ascopes.jct.workspaces.impl.TempDirectoryImpl;
021import java.io.File;
022import java.nio.file.Path;
023import java.util.function.Function;
024import javax.annotation.processing.Filer;
025import org.apiguardian.api.API;
026import org.apiguardian.api.API.Status;
027
028/**
029 * Strategy to use for creating new test directories.
030 *
031 * <p>This is used to define whether to use a totally isolated in-memory file system,
032 * or whether to use temporary directories on the default file system.
033 *
034 * @author Ashley Scopes
035 * @since 0.0.1
036 */
037@API(since = "0.0.1", status = Status.STABLE)
038public enum PathStrategy {
039  /**
040   * Use RAM-based directories for any created directories.
041   *
042   * <p>This is faster as everything remains in-memory. It also prevents the risk of resources
043   * not being tidied up correctly if the JVM is suddenly shut down. Test directories are also kept
044   * isolated from other tests that may be running in parallel, and isolated from the host operating
045   * system.
046   *
047   * <p>If any annotation processors rely on being run in the {@link File default file system}
048   * rather than using {@link Path the NIO path API} or {@link Filer filers} directly, then they
049   * will not be compatible with reading files from this implementation of test directory. In this
050   * situation, users should opt to use {@link #TEMP_DIRECTORIES} instead.
051   *
052   * <p>Some non-Javac compiler implementations (such as ECJ) may also have some difficulties
053   * dealing with these paths.
054   */
055  RAM_DIRECTORIES(RamDirectoryImpl::newRamDirectory),
056
057  /**
058   * Use OS-level temporary directories for any created directories.
059   *
060   * <p>This will write files to the OS temporary directory. These files will be deleted once the
061   * owning workspace is closed, but may be missed if the JVM is forcefully terminated or crashes.
062   *
063   * <p>There are fewer guarantees of speed and isolation compared to using
064   * {@link #RAM_DIRECTORIES}. However, you do gain the ability to set a breakpoint and inspect the
065   * contents of the directory in a file explorer.
066   *
067   * <p>Since the temporary directories are usually created on the
068   * {@link File default file system}, they are compatible with any annotation processors or
069   * compiler implementations that expect to be run on the default file system only.
070   *
071   * <p>Some restrictions regarding file naming may be present depending on the platform that
072   * is in use, such as file name lengths on Windows. See your system documentation for more
073   * details.
074   */
075  TEMP_DIRECTORIES(TempDirectoryImpl::newTempDirectory);
076
077  private final Function<String, AbstractManagedDirectory> constructor;
078
079  PathStrategy(Function<String, AbstractManagedDirectory> constructor) {
080    this.constructor = constructor;
081  }
082
083  /**
084   * Create a new instance of the test directory type with the given name.
085   *
086   * <p>Note that calling this directly will return an object that you will have to manually
087   * manage the lifetime for. Failing to do so will result in resources being leaked.
088   *
089   * <p><strong>Users should not call this method by default unless they know what they are
090   * doing.</strong> As a result of this constraint, this method is not part of the public API and
091   * may be subject to change without notice.
092   *
093   * @param name the name to use.
094   * @return the new test directory.
095   */
096  @API(since = "0.0.1", status = Status.INTERNAL)
097  public ManagedDirectory newInstance(String name) {
098    return constructor.apply(name);
099  }
100
101  /**
102   * Determine the default strategy to fall back onto.
103   *
104   * <p>This will be {@link #RAM_DIRECTORIES} by default, but this may be subject to change between
105   * minor versions without notice, so do not rely on this if you are testing code that may be
106   * sensitive to the type of file system being used.
107   *
108   * @return the path strategy to use by default.
109   */
110  public static PathStrategy defaultStrategy() {
111    return RAM_DIRECTORIES;
112  }
113}