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