diff --git a/.gitattributes b/.gitattributes index cbac638a7..51769a21f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,4 @@ src/test/resources/edu/ie3/datamodel/io/source/influxdb/_weather/cosmo/weather.txt eol=lf src/test/resources/edu/ie3/datamodel/io/source/influxdb/_weather/icon/weather.txt eol=lf +gradlew eol=lf diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b3875666..74b272ccf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removing deprecated classes and methods [#540](https://github.com/ie3-institute/PowerSystemDataModel/issues/540) - Refactor CSV data sources [#716](https://github.com/ie3-institute/PowerSystemDataModel/issues/716) - Deleted parameter initFiles, set parameter append to false by default [#791](https://github.com/ie3-institute/PowerSystemDataModel/issues/791) +- Use nio paths instead of strings for file path [#723](https://github.com/ie3-institute/PowerSystemDataModel/issues/723) ## [3.0.0] - 2023-02-16 diff --git a/src/main/java/edu/ie3/datamodel/io/IoUtil.java b/src/main/java/edu/ie3/datamodel/io/IoUtil.java index ddda0c8fa..0968b4f28 100644 --- a/src/main/java/edu/ie3/datamodel/io/IoUtil.java +++ b/src/main/java/edu/ie3/datamodel/io/IoUtil.java @@ -6,6 +6,8 @@ package edu.ie3.datamodel.io; import java.io.File; +import java.nio.file.Path; +import java.util.Optional; public class IoUtil { public static final String FILE_SEPARATOR_REGEX = "[\\\\/]"; @@ -17,8 +19,8 @@ private IoUtil() { } /** - * Ensure to have harmonized file separator across the whole String. Will replace all occurences - * if "\" and "/" by the systems file separator + * Ensure to have harmonized file separator across the whole String. Will replace all occurrences + * of "\" and "/" by the systems file separator. * * @param in The String to harmonize * @return The harmonized String @@ -26,4 +28,25 @@ private IoUtil() { public static String harmonizeFileSeparator(String in) { return in.replaceAll(FILE_SEPARATOR_REGEX, FILE_SEPARATOR_REPLACEMENT); } + + /** + * Ensure to have harmonized file separator across the whole path. Will replace all occurrences * + * of "\" and "/" by the systems file separator. + * + * @param path the path to harmonize + * @return the harmonized path + */ + public static Path harmonizeFileSeparator(Path path) { + return Path.of(IoUtil.harmonizeFileSeparator(path.toString())); + } + + /** + * Method to wrap a string of a path in an option for a path. + * + * @param in string of the path + * @return option of the path + */ + public static Optional pathOption(String in) { + return Optional.of(Path.of(in)); + } } diff --git a/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java b/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java index e635a5f7d..71147a7db 100644 --- a/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java +++ b/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java @@ -20,12 +20,10 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,11 +42,11 @@ public class CsvFileConnector implements DataConnector { private final Map timeSeriesWriters = new HashMap<>(); private final FileNamingStrategy fileNamingStrategy; - private final String baseDirectoryName; + private final Path baseDirectoryName; private static final String FILE_ENDING = ".csv"; - public CsvFileConnector(String baseDirectoryName, FileNamingStrategy fileNamingStrategy) { + public CsvFileConnector(Path baseDirectoryName, FileNamingStrategy fileNamingStrategy) { this.baseDirectoryName = baseDirectoryName; this.fileNamingStrategy = fileNamingStrategy; } @@ -102,16 +100,15 @@ BufferedCsvWriter getOrInitWriter(T timeSeries, String[] headerElements, String * @throws ConnectorException If the base folder is a file * @throws IOException If the writer cannot be initialized correctly */ - private BufferedCsvWriter initWriter(String baseDirectory, CsvFileDefinition fileDefinition) + private BufferedCsvWriter initWriter(Path baseDirectory, CsvFileDefinition fileDefinition) throws ConnectorException, IOException { /* Join the full DIRECTORY path (excluding file name) */ - String baseDirectoryHarmonized = IoUtil.harmonizeFileSeparator(baseDirectory); - String fullDirectoryPath = - FilenameUtils.concat(baseDirectoryHarmonized, fileDefinition.directoryPath()); - String fullPath = FilenameUtils.concat(baseDirectoryHarmonized, fileDefinition.getFilePath()); + Path baseDirectoryHarmonized = IoUtil.harmonizeFileSeparator(baseDirectory); + Path fullDirectoryPath = baseDirectoryHarmonized.resolve(fileDefinition.getDirectoryPath()); + Path fullPath = baseDirectoryHarmonized.resolve(fileDefinition.getFilePath()); /* Create missing directories */ - File directories = new File(fullDirectoryPath); + File directories = fullDirectoryPath.toFile(); if (directories.isFile()) throw new ConnectorException("Directory '" + directories + "' already exists and is a file!"); if (!directories.exists() && !directories.mkdirs()) @@ -169,10 +166,10 @@ public synchronized void closeEntityWriter(Class clz * @return the reader that contains information about the file to be read in * @throws FileNotFoundException If the matching file cannot be found */ - public BufferedReader initReader(Class clz) throws FileNotFoundException { - String filePath = null; + public BufferedReader initReader(Class clz) + throws FileNotFoundException, ConnectorException { try { - filePath = + Path filePath = fileNamingStrategy .getFilePath(clz) .orElseThrow( @@ -181,13 +178,11 @@ public BufferedReader initReader(Class clz) throws FileN "Cannot find a naming strategy for class '" + clz.getSimpleName() + "'.")); + return initReader(filePath); } catch (ConnectorException e) { - log.error( - "Cannot get reader for entity '{}' as no file naming strategy for this file exists. Exception: {}", - clz.getSimpleName(), - e); + throw new ConnectorException( + "Cannot initialize reader for entity '" + clz.getSimpleName() + "'.", e); } - return initReader(filePath); } /** @@ -198,8 +193,8 @@ public BufferedReader initReader(Class clz) throws FileN * @return the reader that contains information about the file to be read in * @throws FileNotFoundException if no file with the provided file name can be found */ - public BufferedReader initReader(String filePath) throws FileNotFoundException { - File fullPath = new File(baseDirectoryName + File.separator + filePath + FILE_ENDING); + public BufferedReader initReader(Path filePath) throws FileNotFoundException { + File fullPath = baseDirectoryName.resolve(filePath.toString() + FILE_ENDING).toFile(); return new BufferedReader( new InputStreamReader(new FileInputStream(fullPath), StandardCharsets.UTF_8), 16384); } @@ -219,9 +214,9 @@ public BufferedReader initReader(String filePath) throws FileNotFoundException { filePath -> { /* Extract meta information from file path and enhance it with the file path itself */ IndividualTimeSeriesMetaInformation metaInformation = - fileNamingStrategy.individualTimeSeriesMetaInformation(filePath); + fileNamingStrategy.individualTimeSeriesMetaInformation(filePath.toString()); return new CsvIndividualTimeSeriesMetaInformation( - metaInformation, FileNamingStrategy.removeFileNameEnding(filePath)); + metaInformation, FileNamingStrategy.removeFileNameEnding(filePath.getFileName())); }) .filter( metaInformation -> @@ -238,23 +233,20 @@ public BufferedReader initReader(String filePath) throws FileNotFoundException { * * @return A set of relative paths to time series files, with respect to the base folder path */ - private Set getIndividualTimeSeriesFilePaths() { - Path baseDirectoryPath = - Paths.get( - FilenameUtils.getFullPath(baseDirectoryName) - + FilenameUtils.getName(baseDirectoryName)); + private Set getIndividualTimeSeriesFilePaths() { + Path baseDirectoryPath = baseDirectoryName.resolve(baseDirectoryName); try (Stream pathStream = Files.walk(baseDirectoryPath)) { return pathStream .map(baseDirectoryPath::relativize) .filter( path -> { - String withoutEnding = FileNamingStrategy.removeFileNameEnding(path.toString()); + Path withoutEnding = + Path.of(FileNamingStrategy.removeFileNameEnding(path.toString())); return fileNamingStrategy .getIndividualTimeSeriesPattern() - .matcher(withoutEnding) + .matcher(withoutEnding.toString()) .matches(); }) - .map(Path::toString) .collect(Collectors.toSet()); } catch (IOException e) { log.error("Unable to determine time series files readers for time series.", e); @@ -270,7 +262,7 @@ private Set getIndividualTimeSeriesFilePaths() { * @throws FileNotFoundException If the file is not present */ public BufferedReader initIdCoordinateReader() throws FileNotFoundException { - String filePath = fileNamingStrategy.getIdCoordinateEntityName(); + Path filePath = Path.of(fileNamingStrategy.getIdCoordinateEntityName()); return initReader(filePath); } @@ -286,7 +278,7 @@ public BufferedReader initIdCoordinateReader() throws FileNotFoundException { private , E extends TimeSeriesEntry, V extends Value> CsvFileDefinition buildFileDefinition(T timeSeries, String[] headLineElements, String csvSep) throws ConnectorException { - String directoryPath = fileNamingStrategy.getDirectoryPath(timeSeries).orElse(""); + Path directoryPath = fileNamingStrategy.getDirectoryPath(timeSeries).orElse(Path.of("")); String fileName = fileNamingStrategy .getEntityName(timeSeries) @@ -309,7 +301,7 @@ CsvFileDefinition buildFileDefinition(T timeSeries, String[] headLineElements, S private CsvFileDefinition buildFileDefinition( Class clz, String[] headLineElements, String csvSep) throws ConnectorException { - String directoryPath = fileNamingStrategy.getDirectoryPath(clz).orElse(""); + Path directoryPath = fileNamingStrategy.getDirectoryPath(clz).orElse(Path.of("")); String fileName = fileNamingStrategy .getEntityName(clz) diff --git a/src/main/java/edu/ie3/datamodel/io/csv/BufferedCsvWriter.java b/src/main/java/edu/ie3/datamodel/io/csv/BufferedCsvWriter.java index d091d310b..b62170ac8 100644 --- a/src/main/java/edu/ie3/datamodel/io/csv/BufferedCsvWriter.java +++ b/src/main/java/edu/ie3/datamodel/io/csv/BufferedCsvWriter.java @@ -9,6 +9,7 @@ import edu.ie3.util.StringUtils; import java.io.*; import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.util.Arrays; import java.util.Map; import java.util.Objects; @@ -39,10 +40,11 @@ public class BufferedCsvWriter extends BufferedWriter { * if no file exists, a new one will be created in both cases * @throws IOException If the FileOutputStream cannot be established. */ - public BufferedCsvWriter( - String filePath, String[] headLineElements, String csvSep, boolean append) + public BufferedCsvWriter(Path filePath, String[] headLineElements, String csvSep, boolean append) throws IOException { - super(new OutputStreamWriter(new FileOutputStream(filePath, append), StandardCharsets.UTF_8)); + super( + new OutputStreamWriter( + new FileOutputStream(filePath.toFile(), append), StandardCharsets.UTF_8)); this.headLineElements = headLineElements; this.csvSep = csvSep; } @@ -59,10 +61,10 @@ public BufferedCsvWriter( * if no file exists, a new one will be created in both cases * @throws IOException If the FileOutputStream cannot be established. */ - public BufferedCsvWriter(String baseFolder, CsvFileDefinition fileDefinition, boolean append) + public BufferedCsvWriter(Path baseFolder, CsvFileDefinition fileDefinition, boolean append) throws IOException { this( - baseFolder + File.separator + fileDefinition.getFilePath(), + baseFolder.resolve(fileDefinition.getFilePath()), fileDefinition.headLineElements(), fileDefinition.csvSep(), append); diff --git a/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java b/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java index 9980bc064..6e2429a45 100644 --- a/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java +++ b/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java @@ -5,63 +5,36 @@ */ package edu.ie3.datamodel.io.csv; -import edu.ie3.datamodel.io.IoUtil; +import edu.ie3.datamodel.utils.FileUtils; +import java.nio.file.Path; import java.util.Arrays; import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.apache.commons.io.FilenameUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public record CsvFileDefinition( - String fileName, String directoryPath, String[] headLineElements, String csvSep) { - private static final Logger logger = LoggerFactory.getLogger(CsvFileDefinition.class); - - private static final Pattern FILE_NAME_PATTERN = - Pattern.compile( - "^(?[^\\\\/\\s.]{0,255})(?:\\.(?[a-zA-Z0-9]{0,10}(?:\\.[a-zA-Z0-9]{0,10})?))?$"); - - private static final String FILE_EXTENSION = "csv"; +/** + * A definition of a csv file. + * + * @param filePath the path of the csv file (including filename and relative path) + * @param headLineElements elements of the headline of the defined file + * @param csvSep the separator that is used in this csv file + */ +public record CsvFileDefinition(Path filePath, String[] headLineElements, String csvSep) { public CsvFileDefinition( - String fileName, String directoryPath, String[] headLineElements, String csvSep) { - /* Remove all file separators at the beginning and end of a directory path and ensure harmonized file separator */ - this.directoryPath = - Objects.nonNull(directoryPath) - ? IoUtil.harmonizeFileSeparator( - directoryPath - .replaceFirst("^" + IoUtil.FILE_SEPARATOR_REGEX, "") - .replaceAll(IoUtil.FILE_SEPARATOR_REGEX + "$", "")) - : ""; - - /* Check the given information of the file name */ - Matcher matcher = FILE_NAME_PATTERN.matcher(fileName); - if (matcher.matches()) { - String extension = matcher.group("extension"); - if (Objects.nonNull(extension) && !extension.equalsIgnoreCase(FILE_EXTENSION)) - logger.warn( - "You provided a file name with extension '{}'. It will be overridden to '{}'.", - extension, - FILE_EXTENSION); - this.fileName = matcher.group("fileName") + "." + FILE_EXTENSION; - } else { - throw new IllegalArgumentException( - "The file name '" - + fileName - + "' is no valid file name. It may contain everything, except '/', '\\', '.' and any white space character."); - } - - this.headLineElements = headLineElements; - this.csvSep = csvSep; + String fileName, Path directoryPath, String[] headLineElements, String csvSep) { + this(FileUtils.ofCsv(fileName, directoryPath), headLineElements, csvSep); } /** * @return The path to the file relative to a not explicitly defined base directory, including the * file extension */ - public String getFilePath() { - return !directoryPath.isEmpty() ? FilenameUtils.concat(directoryPath, fileName) : fileName; + public Path getFilePath() { + return filePath; + } + + /** Returns the directory path of this file. */ + public Path getDirectoryPath() { + Path parent = filePath.getParent(); + return parent != null ? parent : Path.of(""); } @Override @@ -70,15 +43,14 @@ public boolean equals(Object o) { // records' equals method and array fields don't play together nicely if (this == o) return true; if (!(o instanceof CsvFileDefinition that)) return false; - return directoryPath.equals(that.directoryPath) - && fileName.equals(that.fileName) + return filePath.equals(that.filePath) && Arrays.equals(headLineElements, that.headLineElements) && csvSep.equals(that.csvSep); } @Override public int hashCode() { - int result = Objects.hash(directoryPath, fileName, csvSep); + int result = Objects.hash(filePath, csvSep); result = 31 * result + Arrays.hashCode(headLineElements); return result; } @@ -86,11 +58,8 @@ public int hashCode() { @Override public String toString() { return "CsvFileDefinition{" - + "directoryPath='" - + directoryPath - + '\'' - + ", fileName='" - + fileName + + "fullPath='" + + filePath + '\'' + ", headLineElements=" + Arrays.toString(headLineElements) diff --git a/src/main/java/edu/ie3/datamodel/io/csv/CsvIndividualTimeSeriesMetaInformation.java b/src/main/java/edu/ie3/datamodel/io/csv/CsvIndividualTimeSeriesMetaInformation.java index 078071503..49a5630d6 100644 --- a/src/main/java/edu/ie3/datamodel/io/csv/CsvIndividualTimeSeriesMetaInformation.java +++ b/src/main/java/edu/ie3/datamodel/io/csv/CsvIndividualTimeSeriesMetaInformation.java @@ -7,25 +7,26 @@ import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme; import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation; +import java.nio.file.Path; import java.util.Objects; import java.util.UUID; /** Enhancing the {@link IndividualTimeSeriesMetaInformation} with the full path to csv file */ public class CsvIndividualTimeSeriesMetaInformation extends IndividualTimeSeriesMetaInformation { - private final String fullFilePath; + private final Path fullFilePath; public CsvIndividualTimeSeriesMetaInformation( - UUID uuid, ColumnScheme columnScheme, String fullFilePath) { + UUID uuid, ColumnScheme columnScheme, Path fullFilePath) { super(uuid, columnScheme); this.fullFilePath = fullFilePath; } public CsvIndividualTimeSeriesMetaInformation( - IndividualTimeSeriesMetaInformation metaInformation, String fullFilePath) { + IndividualTimeSeriesMetaInformation metaInformation, Path fullFilePath) { this(metaInformation.getUuid(), metaInformation.getColumnScheme(), fullFilePath); } - public String getFullFilePath() { + public Path getFullFilePath() { return fullFilePath; } diff --git a/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java b/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java index c4b3e7ab6..522222b2c 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java @@ -31,7 +31,6 @@ import edu.ie3.datamodel.models.result.thermal.ThermalUnitResult; import edu.ie3.datamodel.models.timeseries.TimeSeries; import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -47,9 +46,6 @@ public class DefaultDirectoryHierarchy implements FileHierarchy { private static final Logger logger = LoggerFactory.getLogger(DefaultDirectoryHierarchy.class); - /** Use the unix file separator here. */ - protected static final String FILE_SEPARATOR = File.separator; - /** Base directory for this specific grid model. The base path should be a directory. */ private final Path baseDirectory; @@ -64,37 +60,23 @@ public class DefaultDirectoryHierarchy implements FileHierarchy { private final Path resultTree; - public DefaultDirectoryHierarchy(String baseDirectory, String gridName) { + public DefaultDirectoryHierarchy(Path baseDirectory, String gridName) { /* Prepare the base path */ - String baseDirectoryNormalized = - FilenameUtils.normalizeNoEndSeparator(baseDirectory, true) + FILE_SEPARATOR; - this.baseDirectory = Paths.get(baseDirectoryNormalized).toAbsolutePath(); - this.projectDirectory = - Paths.get( - baseDirectoryNormalized - + FilenameUtils.normalizeNoEndSeparator(gridName, true) - + FILE_SEPARATOR) - .toAbsolutePath(); + Path baseDirectoryNormalized = + Path.of(FilenameUtils.normalizeNoEndSeparator(String.valueOf(baseDirectory), true)); + this.baseDirectory = baseDirectoryNormalized.toAbsolutePath(); + this.projectDirectory = baseDirectoryNormalized.resolve(gridName).toAbsolutePath(); /* Prepare the sub directories by appending the relative path to base path and mapping to information about being mandatory */ this.subDirectories = Arrays.stream(SubDirectories.values()) .collect( Collectors.toMap( - subDirectory -> - Paths.get( - FilenameUtils.concat( - this.projectDirectory.toString(), subDirectory.getRelPath())), + subDirectory -> this.projectDirectory.resolve(subDirectory.getRelPath()), SubDirectories::isMandatory)); - inputTree = - Paths.get( - FilenameUtils.concat( - projectDirectory.toString(), SubDirectories.Constants.INPUT_SUB_TREE)); - resultTree = - Paths.get( - FilenameUtils.concat( - projectDirectory.toString(), SubDirectories.Constants.RESULT_SUB_TREE)); + inputTree = projectDirectory.resolve(SubDirectories.Constants.INPUT_SUB_TREE); + resultTree = projectDirectory.resolve(SubDirectories.Constants.RESULT_SUB_TREE); } /** @@ -199,19 +181,18 @@ public void createDirs(boolean withOptionals) throws IOException { */ @Deprecated(since = "3.0", forRemoval = true) @Override - public Optional getBaseDirectory() { - return Optional.of(this.baseDirectory.toString()); + public Optional getBaseDirectory() { + return Optional.of(this.baseDirectory); } /** * Gives the correct sub directory (w.r.t. {@link #baseDirectory}) for the provided class. * * @param cls Class to define the sub directory for - * @param fileSeparator The file separator to use * @return An Option to the regarding sub directory as a string */ @Override - public Optional getSubDirectory(Class cls, String fileSeparator) { + public Optional getSubDirectory(Class cls) { /* Go through all sub directories and check, if the given class belongs to one of the classes mapped to the sub directories. */ Optional maybeSubDirectory = Arrays.stream(SubDirectories.values()) @@ -226,11 +207,8 @@ public Optional getSubDirectory(Class cls, Strin return Optional.empty(); } else { /* Build the full path and then refer it to the base directory */ - Path fullPath = - Paths.get( - FilenameUtils.concat( - this.projectDirectory.toString(), maybeSubDirectory.get().getRelPath())); - String relPath = this.baseDirectory.relativize(fullPath).toString(); + Path fullPath = this.projectDirectory.resolve(maybeSubDirectory.get().getRelPath()); + Path relPath = this.baseDirectory.relativize(fullPath); return Optional.of(relPath); } @@ -238,7 +216,7 @@ public Optional getSubDirectory(Class cls, Strin private enum SubDirectories { GRID_INPUT( - Constants.INPUT_SUB_TREE + FILE_SEPARATOR + "grid" + FILE_SEPARATOR, + Constants.INPUT_SUB_TREE.resolve("grid"), true, Stream.of( LineInput.class, @@ -249,7 +227,7 @@ private enum SubDirectories { NodeInput.class) .collect(Collectors.toSet())), GRID_RESULT( - Constants.RESULT_SUB_TREE + FILE_SEPARATOR + "grid" + FILE_SEPARATOR, + Constants.RESULT_SUB_TREE.resolve("grid"), false, Stream.of( LineResult.class, @@ -259,7 +237,7 @@ private enum SubDirectories { NodeResult.class) .collect(Collectors.toSet())), GLOBAL( - Constants.INPUT_SUB_TREE + FILE_SEPARATOR + "global" + FILE_SEPARATOR, + Constants.INPUT_SUB_TREE.resolve("global"), true, Stream.of( LineTypeInput.class, @@ -277,7 +255,7 @@ private enum SubDirectories { LoadProfileInput.class) .collect(Collectors.toSet())), PARTICIPANTS_INPUT( - Constants.INPUT_SUB_TREE + FILE_SEPARATOR + "participants" + FILE_SEPARATOR, + Constants.INPUT_SUB_TREE.resolve("participants"), true, Stream.of( BmInput.class, @@ -292,7 +270,7 @@ private enum SubDirectories { WecInput.class) .collect(Collectors.toSet())), PARTICIPANTS_RESULTS( - Constants.RESULT_SUB_TREE + FILE_SEPARATOR + "participants" + FILE_SEPARATOR, + Constants.RESULT_SUB_TREE.resolve("participants"), false, Stream.of( BmResult.class, @@ -309,27 +287,27 @@ private enum SubDirectories { FlexOptionsResult.class) .collect(Collectors.toSet())), TIME_SERIES( - PARTICIPANTS_INPUT.relPath + "time_series" + FILE_SEPARATOR, + PARTICIPANTS_INPUT.relPath.resolve("time_series"), false, Stream.of(TimeSeries.class, TimeSeriesMappingSource.MappingEntry.class) .collect(Collectors.toSet())), THERMAL_INPUT( - Constants.INPUT_SUB_TREE + FILE_SEPARATOR + "thermal" + FILE_SEPARATOR, + Constants.INPUT_SUB_TREE.resolve("thermal"), false, Stream.of(ThermalUnitInput.class, ThermalBusInput.class).collect(Collectors.toSet())), THERMAL_RESULTS( - Constants.RESULT_SUB_TREE + FILE_SEPARATOR + "thermal" + FILE_SEPARATOR, + Constants.RESULT_SUB_TREE.resolve("thermal"), false, Stream.of(ThermalUnitResult.class).collect(Collectors.toSet())), GRAPHICS( - Constants.INPUT_SUB_TREE + FILE_SEPARATOR + "graphics" + FILE_SEPARATOR, + Constants.INPUT_SUB_TREE.resolve("graphics"), false, Stream.of(GraphicInput.class).collect(Collectors.toSet())); - private final String relPath; + private final Path relPath; private final boolean mandatory; private final Set> relevantClasses; - public String getRelPath() { + public Path getRelPath() { return relPath; } @@ -341,15 +319,15 @@ public Set> getRelevantClasses() { return relevantClasses; } - SubDirectories(String relPath, boolean mandatory, Set> relevantClasses) { + SubDirectories(Path relPath, boolean mandatory, Set> relevantClasses) { this.relPath = relPath; this.mandatory = mandatory; this.relevantClasses = Collections.unmodifiableSet(relevantClasses); } private static class Constants { - private static final String INPUT_SUB_TREE = "input"; - private static final String RESULT_SUB_TREE = "results"; + private static final Path INPUT_SUB_TREE = Paths.get("input"); + private static final Path RESULT_SUB_TREE = Paths.get("results"); } } } diff --git a/src/main/java/edu/ie3/datamodel/io/naming/FileHierarchy.java b/src/main/java/edu/ie3/datamodel/io/naming/FileHierarchy.java index 01b71e1b2..d98747fe0 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/FileHierarchy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/FileHierarchy.java @@ -6,7 +6,7 @@ package edu.ie3.datamodel.io.naming; import edu.ie3.datamodel.models.UniqueEntity; -import java.io.File; +import java.nio.file.Path; import java.util.Optional; /** @@ -16,24 +16,13 @@ public interface FileHierarchy { /** * Determines the correct subdirectory (w.r.t. an arbitrary base directory) for a certain given - * class using the provided file separator for delimiting between directories and files. + * class using the file separator provided by {@link Path} for delimiting between directories and + * files. * * @param cls Class to define the sub directory for - * @param fileSeparator The file separator to use * @return An Option to the regarding sub directory as a string */ - Optional getSubDirectory(Class cls, String fileSeparator); - - /** - * Determines the correct subdirectory (w.r.t. an arbitrary base directory) for a certain given - * class using the Unix file separator for delimiting between directories and files. - * - * @param cls Class to define the sub directory for - * @return An Option to the regarding sub directory as a string - */ - default Optional getSubDirectory(Class cls) { - return getSubDirectory(cls, File.separator); - } + Optional getSubDirectory(Class cls); /** * Determines the base directory. @@ -42,5 +31,5 @@ default Optional getSubDirectory(Class cls) { * @deprecated Use {@link edu.ie3.datamodel.io.connectors.CsvFileConnector} instead */ @Deprecated(since = "3.0", forRemoval = true) - Optional getBaseDirectory(); + Optional getBaseDirectory(); } diff --git a/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java b/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java index 2c278fd06..100aace7a 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java @@ -13,6 +13,7 @@ import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries; import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput; import edu.ie3.datamodel.models.value.Value; +import edu.ie3.datamodel.utils.FileUtils; import java.nio.file.Path; import java.util.Optional; import java.util.regex.Pattern; @@ -70,11 +71,8 @@ public FileNamingStrategy() { * @param cls Targeted class of the given file * @return An optional sub path to the actual file */ - public Optional getFilePath(Class cls) { - // do not adapt orElseGet, see https://www.baeldung.com/java-optional-or-else-vs-or-else-get for - // details - return getFilePath( - getEntityName(cls).orElseGet(() -> ""), getDirectoryPath(cls).orElseGet(() -> "")); + public Optional getFilePath(Class cls) { + return FileUtils.of(getEntityName(cls), getDirectoryPath(cls)); } /** @@ -88,12 +86,9 @@ public Optional getFilePath(Class cls) { * @return An optional sub path to the actual file */ public , E extends TimeSeriesEntry, V extends Value> - Optional getFilePath(T timeSeries) { - // do not adapt orElseGet, see https://www.baeldung.com/java-optional-or-else-vs-or-else-get for - // details - return getFilePath( - entityPersistenceNamingStrategy.getEntityName(timeSeries).orElseGet(() -> ""), - getDirectoryPath(timeSeries).orElseGet(() -> "")); + Optional getFilePath(T timeSeries) { + return FileUtils.of( + entityPersistenceNamingStrategy.getEntityName(timeSeries), getDirectoryPath(timeSeries)); } /** @@ -103,12 +98,14 @@ Optional getFilePath(T timeSeries) { * @param fileName File name * @param subDirectories Sub directory path * @return Concatenation of sub directory structure and file name + * @deprecated replaced with {@link FileUtils#of(String, Optional)} */ - private Optional getFilePath(String fileName, String subDirectories) { + @Deprecated(since = "3.0", forRemoval = true) + private Optional getFilePath(String fileName, Optional subDirectories) { if (fileName.isEmpty()) return Optional.empty(); - if (!subDirectories.isEmpty()) - return Optional.of(FilenameUtils.concat(subDirectories, fileName)); - else return Optional.of(fileName); + return subDirectories + .map(path -> path.resolve(fileName)) + .or(() -> Optional.of(Path.of(fileName))); } /** @@ -118,19 +115,14 @@ private Optional getFilePath(String fileName, String subDirectories) { * @param cls Targeted class of the given file * @return An optional sub directory path */ - public Optional getDirectoryPath(Class cls) { - Optional maybeDirectoryName = fileHierarchy.getSubDirectory(cls); + public Optional getDirectoryPath(Class cls) { + Optional maybeDirectoryName = fileHierarchy.getSubDirectory(cls); if (maybeDirectoryName.isEmpty()) { logger.debug("Cannot determine directory name for class '{}'.", cls); return Optional.empty(); } else { /* Make sure, the directory path does not start or end with file separator and in between the separator is harmonized */ - return Optional.of( - IoUtil.harmonizeFileSeparator( - maybeDirectoryName - .get() - .replaceFirst("^" + IoUtil.FILE_SEPARATOR_REGEX, "") - .replaceAll(IoUtil.FILE_SEPARATOR_REGEX + "$", ""))); + return maybeDirectoryName.map(IoUtil::harmonizeFileSeparator); } } @@ -145,19 +137,14 @@ public Optional getDirectoryPath(Class cls) { * @return An optional sub directory path */ public , E extends TimeSeriesEntry, V extends Value> - Optional getDirectoryPath(T timeSeries) { - Optional maybeDirectoryName = fileHierarchy.getSubDirectory(timeSeries.getClass()); + Optional getDirectoryPath(T timeSeries) { + Optional maybeDirectoryName = fileHierarchy.getSubDirectory(timeSeries.getClass()); if (maybeDirectoryName.isEmpty()) { logger.debug("Cannot determine directory name for time series '{}'.", timeSeries); return Optional.empty(); } else { /* Make sure, the directory path does not start or end with file separator and in between the separator is harmonized */ - return Optional.of( - IoUtil.harmonizeFileSeparator( - maybeDirectoryName - .get() - .replaceFirst("^" + IoUtil.FILE_SEPARATOR_REGEX, "") - .replaceAll(IoUtil.FILE_SEPARATOR_REGEX + "$", ""))); + return maybeDirectoryName.map(IoUtil::harmonizeFileSeparator); } } @@ -168,8 +155,7 @@ Optional getDirectoryPath(T timeSeries) { * @return An individual time series pattern */ public Pattern getIndividualTimeSeriesPattern() { - String subDirectory = - fileHierarchy.getSubDirectory(IndividualTimeSeries.class).orElseGet(() -> ""); + Optional subDirectory = fileHierarchy.getSubDirectory(IndividualTimeSeries.class); if (subDirectory.isEmpty()) { return entityPersistenceNamingStrategy.getIndividualTimeSeriesPattern(); @@ -178,7 +164,7 @@ public Pattern getIndividualTimeSeriesPattern() { * finally escaping them */ String joined = FilenameUtils.concat( - subDirectory, + subDirectory.get().toString(), entityPersistenceNamingStrategy.getIndividualTimeSeriesPattern().pattern()); String harmonized = IoUtil.harmonizeFileSeparator(joined); String escaped = harmonized.replace("\\", "\\\\"); @@ -194,7 +180,7 @@ public Pattern getIndividualTimeSeriesPattern() { * @return A load profile time series pattern */ public Pattern getLoadProfileTimeSeriesPattern() { - String subDirectory = fileHierarchy.getSubDirectory(LoadProfileInput.class).orElseGet(() -> ""); + Optional subDirectory = fileHierarchy.getSubDirectory(LoadProfileInput.class); if (subDirectory.isEmpty()) { return entityPersistenceNamingStrategy.getLoadProfileTimeSeriesPattern(); @@ -203,7 +189,7 @@ public Pattern getLoadProfileTimeSeriesPattern() { * finally escaping them */ String joined = FilenameUtils.concat( - subDirectory, + subDirectory.get().toString(), entityPersistenceNamingStrategy.getLoadProfileTimeSeriesPattern().pattern()); String harmonized = IoUtil.harmonizeFileSeparator(joined); String escaped = harmonized.replace("\\", "\\\\"); @@ -255,6 +241,10 @@ public static String removeFileNameEnding(String fileName) { return fileName.replaceAll("(?:\\.[^.\\\\/\\s]{1,255}){1,2}$", ""); } + public static Path removeFileNameEnding(Path filename) { + return Path.of(removeFileNameEnding(filename.toString())); + } + /** * Get the entity name for coordinates * @@ -273,11 +263,10 @@ public String getIdCoordinateEntityName() { * @deprecated unused, no substitute */ @Deprecated(since = "3.0", forRemoval = true) - public Optional getIdCoordinateFilePath() { + public Optional getIdCoordinateFilePath() { // do not adapt orElseGet, see https://www.baeldung.com/java-optional-or-else-vs-or-else-get for // details - return getFilePath( - getIdCoordinateEntityName(), fileHierarchy.getBaseDirectory().orElseGet(() -> "")); + return Optional.of(FileUtils.of(getIdCoordinateEntityName(), fileHierarchy.getBaseDirectory())); } /** diff --git a/src/main/java/edu/ie3/datamodel/io/naming/FlatDirectoryHierarchy.java b/src/main/java/edu/ie3/datamodel/io/naming/FlatDirectoryHierarchy.java index b567c6b11..9e7e352d3 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/FlatDirectoryHierarchy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/FlatDirectoryHierarchy.java @@ -6,6 +6,7 @@ package edu.ie3.datamodel.io.naming; import edu.ie3.datamodel.models.UniqueEntity; +import java.nio.file.Path; import java.util.Optional; /** Default directory hierarchy for input models */ @@ -15,11 +16,10 @@ public class FlatDirectoryHierarchy implements FileHierarchy { * Gives empty sub directory. * * @param cls Class to define the sub directory for - * @param fileSeparator The file separator to use * @return An Option to the regarding sub directory as a string */ @Override - public Optional getSubDirectory(Class cls, String fileSeparator) { + public Optional getSubDirectory(Class cls) { return Optional.empty(); } @@ -31,7 +31,7 @@ public Optional getSubDirectory(Class cls, Strin */ @Deprecated(since = "3.0", forRemoval = true) @Override - public Optional getBaseDirectory() { + public Optional getBaseDirectory() { return Optional.empty(); } } diff --git a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java index 45dc40ccc..a5eecb105 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java @@ -33,6 +33,7 @@ import edu.ie3.datamodel.models.value.Value; import edu.ie3.util.StringUtils; import java.io.IOException; +import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -58,7 +59,7 @@ public class CsvFileSink implements InputDataSink, OutputDataSink { private final String csvSep; - public CsvFileSink(String baseFolderPath) { + public CsvFileSink(Path baseFolderPath) { this(baseFolderPath, new FileNamingStrategy(), ","); } @@ -71,7 +72,7 @@ public CsvFileSink(String baseFolderPath) { * @param fileNamingStrategy the data sink file naming strategy that should be used * @param csvSep the csv file separator that should be use */ - public CsvFileSink(String baseFolderPath, FileNamingStrategy fileNamingStrategy, String csvSep) { + public CsvFileSink(Path baseFolderPath, FileNamingStrategy fileNamingStrategy, String csvSep) { this(baseFolderPath, new ProcessorProvider(), fileNamingStrategy, csvSep); } @@ -90,7 +91,7 @@ public CsvFileSink(String baseFolderPath, FileNamingStrategy fileNamingStrategy, * @param csvSep the csv file separator that should be use */ public CsvFileSink( - String baseFolderPath, + Path baseFolderPath, ProcessorProvider processorProvider, FileNamingStrategy fileNamingStrategy, String csvSep) { diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java index 6c7791bf6..541a247a2 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.io.source.csv; +import edu.ie3.datamodel.exceptions.ConnectorException; import edu.ie3.datamodel.exceptions.SourceException; import edu.ie3.datamodel.io.connectors.CsvFileConnector; import edu.ie3.datamodel.io.naming.FileNamingStrategy; @@ -15,6 +16,7 @@ import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Path; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @@ -51,7 +53,7 @@ public class CsvDataSource implements DataSource { @Deprecated(since = "1.1.0", forRemoval = true) private boolean notYetLoggedWarning = true; - protected CsvDataSource(String csvSep, String folderPath, FileNamingStrategy fileNamingStrategy) { + protected CsvDataSource(String csvSep, Path folderPath, FileNamingStrategy fileNamingStrategy) { this.csvSep = csvSep; this.connector = new CsvFileConnector(folderPath, fileNamingStrategy); } @@ -63,7 +65,7 @@ public Stream> getSourceData(Class e // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - public BufferedReader createReader(String filePath) throws FileNotFoundException { + public BufferedReader createReader(Path filePath) throws FileNotFoundException { return connector.initReader(filePath); } @@ -267,7 +269,7 @@ protected Stream> buildStreamWithFieldsToAttributesMap( Class entityClass, CsvFileConnector connector) { try { return buildStreamWithFieldsToAttributesMap(entityClass, connector.initReader(entityClass)); - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | ConnectorException e) { log.warn( "Unable to find file for entity '{}': {}", entityClass.getSimpleName(), e.getMessage()); } diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvJointGridContainerSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvJointGridContainerSource.java index b933b3a85..706e0a9ca 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvJointGridContainerSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvJointGridContainerSource.java @@ -15,13 +15,14 @@ import edu.ie3.datamodel.models.input.container.JointGridContainer; import edu.ie3.datamodel.models.input.container.RawGridElements; import edu.ie3.datamodel.models.input.container.SystemParticipants; +import java.nio.file.Path; /** Convenience class for cases where all used data comes from CSV sources */ public class CsvJointGridContainerSource { private CsvJointGridContainerSource() {} public static JointGridContainer read( - String gridName, String csvSep, String directoryPath, boolean isHierarchic) + String gridName, String csvSep, Path directoryPath, boolean isHierarchic) throws SourceException, FileException { /* Parameterization */ diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMappingSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMappingSource.java index 2953aade4..c6affdb71 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMappingSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMappingSource.java @@ -7,6 +7,7 @@ import edu.ie3.datamodel.io.naming.FileNamingStrategy; import edu.ie3.datamodel.io.source.TimeSeriesMappingSource; +import java.nio.file.Path; import java.util.Map; import java.util.stream.Stream; @@ -15,7 +16,7 @@ public class CsvTimeSeriesMappingSource extends TimeSeriesMappingSource { private final CsvDataSource dataSource; public CsvTimeSeriesMappingSource( - String csvSep, String gridFolderPath, FileNamingStrategy fileNamingStrategy) { + String csvSep, Path gridFolderPath, FileNamingStrategy fileNamingStrategy) { this.dataSource = new CsvDataSource(csvSep, gridFolderPath, fileNamingStrategy); } diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSource.java index 37d30fcf2..d657d30cb 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSource.java @@ -11,6 +11,7 @@ import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation; import edu.ie3.datamodel.io.source.TimeSeriesMetaInformationSource; import edu.ie3.datamodel.utils.TimeSeriesUtils; +import java.nio.file.Path; import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -34,7 +35,7 @@ public class CsvTimeSeriesMetaInformationSource implements TimeSeriesMetaInforma * @param fileNamingStrategy the file naming strategy */ public CsvTimeSeriesMetaInformationSource( - String csvSep, String folderPath, FileNamingStrategy fileNamingStrategy) { + String csvSep, Path folderPath, FileNamingStrategy fileNamingStrategy) { this.dataSource = new CsvDataSource(csvSep, folderPath, fileNamingStrategy); // retrieve only the desired time series this.timeSeriesMetaInformation = diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSource.java index f684804d3..6882b6dc3 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSource.java @@ -18,6 +18,7 @@ import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.*; import java.util.function.Function; @@ -40,7 +41,7 @@ public class CsvTimeSeriesSource extends TimeSeriesSource { */ public static CsvTimeSeriesSource getSource( String csvSep, - String folderPath, + Path folderPath, FileNamingStrategy fileNamingStrategy, CsvIndividualTimeSeriesMetaInformation metaInformation) throws SourceException { @@ -55,7 +56,7 @@ public static CsvTimeSeriesSource getSource( private static CsvTimeSeriesSource create( String csvSep, - String folderPath, + Path folderPath, FileNamingStrategy fileNamingStrategy, CsvIndividualTimeSeriesMetaInformation metaInformation, Class valClass) { @@ -83,10 +84,10 @@ private static CsvTimeSeriesSource create( */ public CsvTimeSeriesSource( String csvSep, - String folderPath, + Path folderPath, FileNamingStrategy fileNamingStrategy, UUID timeSeriesUuid, - String filePath, + Path filePath, Class valueClass, TimeBasedSimpleValueFactory factory) { super(valueClass, factory); @@ -135,7 +136,7 @@ public Optional getValue(ZonedDateTime time) { */ protected IndividualTimeSeries buildIndividualTimeSeries( UUID timeSeriesUuid, - String filePath, + Path filePath, Function, Optional>> fieldToValueFunction) throws SourceException { try (BufferedReader reader = dataSource.connector.initReader(filePath)) { diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java index 63596b62e..737d6a644 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java @@ -23,6 +23,7 @@ import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.*; import java.util.function.Function; @@ -48,7 +49,7 @@ public class CsvWeatherSource extends WeatherSource { */ public CsvWeatherSource( String csvSep, - String folderPath, + Path folderPath, FileNamingStrategy fileNamingStrategy, IdCoordinateSource idCoordinateSource, TimeBasedWeatherValueFactory weatherFactory) { diff --git a/src/main/java/edu/ie3/datamodel/utils/FileUtils.java b/src/main/java/edu/ie3/datamodel/utils/FileUtils.java new file mode 100644 index 000000000..845a30105 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/utils/FileUtils.java @@ -0,0 +1,90 @@ +/* + * © 2023. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.utils; + +import edu.ie3.datamodel.io.IoUtil; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Some utility functionalities. */ +public class FileUtils { + private static final Pattern FILE_NAME_PATTERN = + Pattern.compile( + "^(?[^\\\\/\\s.]{0,255})(?:\\.(?[a-zA-Z0-9]{0,10}(?:\\.[a-zA-Z0-9]{0,10})?))?$"); + private static final String CSV_FILE_EXTENSION = "csv"; + + private static final Logger logger = LoggerFactory.getLogger(FileUtils.class); + + private FileUtils() { + throw new IllegalStateException("Utility classes cannot be instantiated"); + } + + /** + * Method to get a {@link Path} from a filename and an option of a directory path. + * + * @param fileName of the file + * @param directoryPath option for the directory path + * @return a definition of a file + */ + public static Path of(String fileName, Optional directoryPath) { + return directoryPath.map(IoUtil::harmonizeFileSeparator).orElse(Path.of("")).resolve(fileName); + } + + /** + * Method to get a {@link Path} when two {@link Optional}'s are provided. + * + * @param fileName option for a filename + * @param directoryPath option for a directory path + * @return an option for a path + */ + public static Optional of(Optional fileName, Optional directoryPath) { + // do not adapt orElseGet, see https://www.baeldung.com/java-optional-or-else-vs-or-else-get for + // details + return Optional.of( + directoryPath + .map(IoUtil::harmonizeFileSeparator) + .orElseGet(() -> Path.of("")) + .resolve(fileName.orElseGet(() -> ""))); + } + + /** + * Method to get the {@link Path} of a csv file. This method will check whether the filename + * contains a csv extension. Also, this method will harmonize the path of the given directory + * path. + * + * @param fileName of the file + * @param directoryPath path to the directory + * @return a definition of the file + */ + public static Path ofCsv(String fileName, Path directoryPath) { + /* Remove all file separators at the beginning and end of a directory path and ensure harmonized file separator */ + Path dirPath = + Objects.nonNull(directoryPath) ? IoUtil.harmonizeFileSeparator(directoryPath) : Path.of(""); + + /* Check the given information of the file name */ + Matcher matcher = FILE_NAME_PATTERN.matcher(fileName); + + if (matcher.matches()) { + String extension = matcher.group("extension"); + if (Objects.nonNull(extension) && !extension.equalsIgnoreCase(CSV_FILE_EXTENSION)) + logger.warn( + "You provided a file name with extension '{}'. It will be overridden to '{}'.", + extension, + CSV_FILE_EXTENSION); + return dirPath.resolve(matcher.group("fileName") + "." + CSV_FILE_EXTENSION); + } else { + throw new IllegalArgumentException( + "The file name '" + + fileName + + "' is no valid file name. It may contain everything, except '/', '\\', '.' and any white space character."); + } + } +} diff --git a/src/test/groovy/edu/ie3/datamodel/io/connectors/CsvFileConnectorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/connectors/CsvFileConnectorTest.groovy index 9c4ef02c3..3b8eede71 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/connectors/CsvFileConnectorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/connectors/CsvFileConnectorTest.groovy @@ -19,17 +19,14 @@ import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue import edu.ie3.datamodel.models.timeseries.repetitive.RepetitiveTimeSeries import edu.ie3.datamodel.models.value.EnergyPriceValue import edu.ie3.util.io.FileIOUtils -import org.apache.commons.io.FilenameUtils import spock.lang.Shared import spock.lang.Specification import tech.units.indriya.quantity.Quantities import java.nio.file.Files import java.nio.file.Path -import java.nio.file.Paths import java.time.ZonedDateTime import java.util.stream.Collectors -import java.util.stream.Stream class CsvFileConnectorTest extends Specification { @Shared @@ -39,26 +36,26 @@ class CsvFileConnectorTest extends Specification { CsvFileConnector cfc @Shared - Set timeSeriesPaths + Set timeSeriesPaths @Shared - Set pathsToIgnore + Set pathsToIgnore def setupSpec() { tmpDirectory = Files.createTempDirectory("psdm_csv_file_connector_") - cfc = new CsvFileConnector(tmpDirectory.toString(), new FileNamingStrategy()) - def gridPaths = ["node_input.csv"] + cfc = new CsvFileConnector(tmpDirectory, new FileNamingStrategy()) + def gridPaths = [Path.of("node_input.csv")] timeSeriesPaths = [ "its_pq_53990eea-1b5d-47e8-9134-6d8de36604bf.csv", "its_p_fcf0b851-a836-4bde-8090-f44c382ed226.csv", "its_pqh_5022a70e-a58f-4bac-b8ec-1c62376c216b.csv", "its_c_b88dee50-5484-4136-901d-050d8c1c97d1.csv", "its_c_c7b0d9d6-5044-4f51-80b4-f221d8b1f14b.csv" - ] + ].stream().map { file -> Path.of(file) }.collect(Collectors.toSet()) pathsToIgnore = [ - "file_to_be_ignored.txt" + Path.of("file_to_be_ignored.txt") ] - (gridPaths + pathsToIgnore + timeSeriesPaths).forEach { it -> Files.createFile(Paths.get(FilenameUtils.concat(tmpDirectory.toString(), it))) } + (gridPaths + pathsToIgnore + timeSeriesPaths).forEach { path -> Files.createFile(tmpDirectory.resolve(path)) } } def cleanupSpec() { @@ -80,11 +77,11 @@ class CsvFileConnectorTest extends Specification { def "The csv file connector is able to build correct uuid to meta information mapping"() { given: def expected = [ - (UUID.fromString("53990eea-1b5d-47e8-9134-6d8de36604bf")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("53990eea-1b5d-47e8-9134-6d8de36604bf"), ColumnScheme.APPARENT_POWER, "its_pq_53990eea-1b5d-47e8-9134-6d8de36604bf"), - (UUID.fromString("fcf0b851-a836-4bde-8090-f44c382ed226")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("fcf0b851-a836-4bde-8090-f44c382ed226"), ColumnScheme.ACTIVE_POWER, "its_p_fcf0b851-a836-4bde-8090-f44c382ed226"), - (UUID.fromString("5022a70e-a58f-4bac-b8ec-1c62376c216b")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("5022a70e-a58f-4bac-b8ec-1c62376c216b"), ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND, "its_pqh_5022a70e-a58f-4bac-b8ec-1c62376c216b"), - (UUID.fromString("b88dee50-5484-4136-901d-050d8c1c97d1")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("b88dee50-5484-4136-901d-050d8c1c97d1"), ColumnScheme.ENERGY_PRICE, "its_c_b88dee50-5484-4136-901d-050d8c1c97d1"), - (UUID.fromString("c7b0d9d6-5044-4f51-80b4-f221d8b1f14b")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("c7b0d9d6-5044-4f51-80b4-f221d8b1f14b"), ColumnScheme.ENERGY_PRICE, "its_c_c7b0d9d6-5044-4f51-80b4-f221d8b1f14b") + (UUID.fromString("53990eea-1b5d-47e8-9134-6d8de36604bf")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("53990eea-1b5d-47e8-9134-6d8de36604bf"), ColumnScheme.APPARENT_POWER, Path.of("its_pq_53990eea-1b5d-47e8-9134-6d8de36604bf")), + (UUID.fromString("fcf0b851-a836-4bde-8090-f44c382ed226")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("fcf0b851-a836-4bde-8090-f44c382ed226"), ColumnScheme.ACTIVE_POWER, Path.of("its_p_fcf0b851-a836-4bde-8090-f44c382ed226")), + (UUID.fromString("5022a70e-a58f-4bac-b8ec-1c62376c216b")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("5022a70e-a58f-4bac-b8ec-1c62376c216b"), ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND, Path.of("its_pqh_5022a70e-a58f-4bac-b8ec-1c62376c216b")), + (UUID.fromString("b88dee50-5484-4136-901d-050d8c1c97d1")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("b88dee50-5484-4136-901d-050d8c1c97d1"), ColumnScheme.ENERGY_PRICE, Path.of("its_c_b88dee50-5484-4136-901d-050d8c1c97d1")), + (UUID.fromString("c7b0d9d6-5044-4f51-80b4-f221d8b1f14b")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("c7b0d9d6-5044-4f51-80b4-f221d8b1f14b"), ColumnScheme.ENERGY_PRICE, Path.of("its_c_c7b0d9d6-5044-4f51-80b4-f221d8b1f14b")) ] when: @@ -97,9 +94,9 @@ class CsvFileConnectorTest extends Specification { def "The csv file connector is able to build correct uuid to meta information mapping when restricting column schemes"() { given: def expected = [ - (UUID.fromString("b88dee50-5484-4136-901d-050d8c1c97d1")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("b88dee50-5484-4136-901d-050d8c1c97d1"), ColumnScheme.ENERGY_PRICE, "its_c_b88dee50-5484-4136-901d-050d8c1c97d1"), - (UUID.fromString("c7b0d9d6-5044-4f51-80b4-f221d8b1f14b")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("c7b0d9d6-5044-4f51-80b4-f221d8b1f14b"), ColumnScheme.ENERGY_PRICE, "its_c_c7b0d9d6-5044-4f51-80b4-f221d8b1f14b"), - (UUID.fromString("fcf0b851-a836-4bde-8090-f44c382ed226")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("fcf0b851-a836-4bde-8090-f44c382ed226"), ColumnScheme.ACTIVE_POWER, "its_p_fcf0b851-a836-4bde-8090-f44c382ed226") + (UUID.fromString("b88dee50-5484-4136-901d-050d8c1c97d1")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("b88dee50-5484-4136-901d-050d8c1c97d1"), ColumnScheme.ENERGY_PRICE, Path.of("its_c_b88dee50-5484-4136-901d-050d8c1c97d1")), + (UUID.fromString("c7b0d9d6-5044-4f51-80b4-f221d8b1f14b")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("c7b0d9d6-5044-4f51-80b4-f221d8b1f14b"), ColumnScheme.ENERGY_PRICE, Path.of("its_c_c7b0d9d6-5044-4f51-80b4-f221d8b1f14b")), + (UUID.fromString("fcf0b851-a836-4bde-8090-f44c382ed226")): new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("fcf0b851-a836-4bde-8090-f44c382ed226"), ColumnScheme.ACTIVE_POWER, Path.of("its_p_fcf0b851-a836-4bde-8090-f44c382ed226")) ] when: @@ -114,7 +111,7 @@ class CsvFileConnectorTest extends Specification { def "The csv file connector throws an Exception, if the foreseen file cannot be found"() { given: - def cfc = new CsvFileConnector(tmpDirectory.toString(), new FileNamingStrategy(new EntityPersistenceNamingStrategy(), new DefaultDirectoryHierarchy(tmpDirectory.toString(), "test"))) + def cfc = new CsvFileConnector(tmpDirectory, new FileNamingStrategy(new EntityPersistenceNamingStrategy(), new DefaultDirectoryHierarchy(tmpDirectory, "test"))) when: cfc.initReader(NodeInput) @@ -133,13 +130,13 @@ class CsvFileConnectorTest extends Specification { def "The csv file connector is able to init writers utilizing a directory hierarchy"() { given: "a suitable connector" - def baseDirectory = FilenameUtils.concat(tmpDirectory.toString(), "directoryHierarchy") + def baseDirectory = tmpDirectory.resolve("directoryHierarchy") def directoryHierarchy = new DefaultDirectoryHierarchy(baseDirectory, "test") def fileNamingStrategy = new FileNamingStrategy(new EntityPersistenceNamingStrategy(), directoryHierarchy) def connector = new CsvFileConnector(baseDirectory, fileNamingStrategy) and: "expected results" - def nodeFile = new File(Stream.of(baseDirectory, "test", "input", "grid", "node_input.csv").collect(Collectors.joining(File.separator))) + def nodeFile = baseDirectory.resolve(Path.of("test", "input", "grid", "node_input.csv")).toFile() when: /* The head line is of no interest here */ @@ -153,12 +150,12 @@ class CsvFileConnectorTest extends Specification { def "The csv file connector is able to init writers utilizing no directory hierarchy"() { given: "a suitable connector" - def baseDirectory = FilenameUtils.concat(tmpDirectory.toString(), "directoryHierarchy") + def baseDirectory = tmpDirectory.resolve("directoryHierarchy") def fileNamingStrategy = new FileNamingStrategy() def connector = new CsvFileConnector(baseDirectory, fileNamingStrategy) and: "expected results" - def nodeFile = new File(FilenameUtils.concat(baseDirectory, "node_input.csv")) + def nodeFile = baseDirectory.resolve("node_input.csv").toFile() when: /* The head line is of no interest here */ @@ -172,9 +169,8 @@ class CsvFileConnectorTest extends Specification { def "The csv file connector throws ConnectorException if no csv file definition can be built from class information"() { given: - def baseDirectory = tmpDirectory.toString() def fileNamingStrategy = new FileNamingStrategy() - def connector = new CsvFileConnector(baseDirectory, fileNamingStrategy) + def connector = new CsvFileConnector(tmpDirectory, fileNamingStrategy) when: connector.buildFileDefinition(String, ["a", "b", "c"] as String[], ",") @@ -186,37 +182,42 @@ class CsvFileConnectorTest extends Specification { def "The csv file connector is able to build correct csv file definition from class upon request"() { given: - def baseDirectory = tmpDirectory.toString() def fileNamingStrategy = new FileNamingStrategy() - def connector = new CsvFileConnector(baseDirectory, fileNamingStrategy) - def expected = new CsvFileDefinition("node_input.csv", "", ["a", "b", "c"] as String[], ",") + def connector = new CsvFileConnector(tmpDirectory, fileNamingStrategy) + def expected = new CsvFileDefinition("node_input.csv", Path.of(""), ["a", "b", "c"] as String[], ",") when: def actual = connector.buildFileDefinition(NodeInput, ["a", "b", "c"] as String[], ",") then: - actual == expected + actual.with { + assert it.filePath == expected.filePath + assert it.headLineElements() == expected.headLineElements() + assert it.csvSep() == expected.csvSep() + } } def "The csv file connector is able to build correct csv file definition from class upon request, utilizing directory hierarchy"() { given: - def baseDirectory = tmpDirectory.toString() - def fileNamingStrategy = new FileNamingStrategy(new EntityPersistenceNamingStrategy(), new DefaultDirectoryHierarchy(tmpDirectory.toString(), "test")) - def connector = new CsvFileConnector(baseDirectory, fileNamingStrategy) - def expected = new CsvFileDefinition("node_input.csv", Stream.of("test", "input", "grid").collect(Collectors.joining(File.separator)), ["a", "b", "c"] as String[], ",") + def fileNamingStrategy = new FileNamingStrategy(new EntityPersistenceNamingStrategy(), new DefaultDirectoryHierarchy(tmpDirectory, "test")) + def connector = new CsvFileConnector(tmpDirectory, fileNamingStrategy) + def expected = new CsvFileDefinition("node_input.csv", Path.of("test", "input", "grid"), ["a", "b", "c"] as String[], ",") when: def actual = connector.buildFileDefinition(NodeInput, ["a", "b", "c"] as String[], ",") then: - actual == expected + actual.with { + assert it.filePath == expected.filePath + assert it.headLineElements() == expected.headLineElements() + assert it.csvSep() == expected.csvSep() + } } def "The csv file connector throws ConnectorException if no csv file definition can be built from time series"() { given: "a suitable connector" - def baseDirectory = tmpDirectory.toString() def fileNamingStrategy = new FileNamingStrategy() - def connector = new CsvFileConnector(baseDirectory, fileNamingStrategy) + def connector = new CsvFileConnector(tmpDirectory, fileNamingStrategy) and: "credible input" def timeSeries = Mock(RepetitiveTimeSeries) @@ -231,10 +232,9 @@ class CsvFileConnectorTest extends Specification { def "The csv file connector is able to build correct csv file definition from time series upon request"() { given: "a suitable connector" - def baseDirectory = tmpDirectory.toString() def fileNamingStrategy = new FileNamingStrategy() - def connector = new CsvFileConnector(baseDirectory, fileNamingStrategy) - def expected = new CsvFileDefinition("its_c_0c03ce9f-ab0e-4715-bc13-f9d903f26dbf.csv", "", ["a", "b", "c"] as String[], ",") + def connector = new CsvFileConnector(tmpDirectory, fileNamingStrategy) + def expected = new CsvFileDefinition("its_c_0c03ce9f-ab0e-4715-bc13-f9d903f26dbf.csv", Path.of(""), ["a", "b", "c"] as String[], ",") and: "credible input" def entries = [ @@ -248,15 +248,18 @@ class CsvFileConnectorTest extends Specification { def actual = connector.buildFileDefinition(timeSeries, ["a", "b", "c"] as String[], ",") then: - actual == expected + actual.with { + assert it.filePath == expected.filePath + assert it.headLineElements() == expected.headLineElements() + assert it.csvSep() == expected.csvSep() + } } def "The csv file connector is able to build correct csv file definition from time series upon request, utilizing directory hierarchy"() { given: "a suitable connector" - def baseDirectory = tmpDirectory.toString() - def fileNamingStrategy = new FileNamingStrategy(new EntityPersistenceNamingStrategy(), new DefaultDirectoryHierarchy(tmpDirectory.toString(), "test")) - def connector = new CsvFileConnector(baseDirectory, fileNamingStrategy) - def expected = new CsvFileDefinition("its_c_0c03ce9f-ab0e-4715-bc13-f9d903f26dbf.csv", Stream.of("test", "input", "participants", "time_series").collect(Collectors.joining(File.separator)), ["a", "b", "c"] as String[], ",") + def fileNamingStrategy = new FileNamingStrategy(new EntityPersistenceNamingStrategy(), new DefaultDirectoryHierarchy(tmpDirectory, "test")) + def connector = new CsvFileConnector(tmpDirectory, fileNamingStrategy) + def expected = new CsvFileDefinition("its_c_0c03ce9f-ab0e-4715-bc13-f9d903f26dbf.csv", Path.of("test", "input", "participants", "time_series"), ["a", "b", "c"] as String[], ",") and: "credible input" def entries = [ @@ -270,15 +273,19 @@ class CsvFileConnectorTest extends Specification { def actual = connector.buildFileDefinition(timeSeries, ["a", "b", "c"] as String[], ",") then: - actual == expected + actual.with { + assert it.filePath == expected.filePath + assert it.headLineElements() == expected.headLineElements() + assert it.csvSep() == expected.csvSep() + } } def "Initialising a writer with incorrect base directory leads to ConnectorException"() { given: - def baseFolder = FilenameUtils.concat(tmpDirectory.toString(), "helloWorld.txt") - def baseFolderFile = new File(baseFolder) + def baseFolder = tmpDirectory.resolve("helloWorld.txt") + def baseFolderFile = baseFolder.toFile() baseFolderFile.createNewFile() - def fileDefinition = new CsvFileDefinition("test.csv", "", [] as String[], ",") + def fileDefinition = new CsvFileDefinition("test.csv", Path.of(""), [] as String[], ",") when: cfc.initWriter(baseFolder, fileDefinition) diff --git a/src/test/groovy/edu/ie3/datamodel/io/csv/BufferedCsvWriterTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/csv/BufferedCsvWriterTest.groovy index 97eb15071..a48264940 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/csv/BufferedCsvWriterTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/csv/BufferedCsvWriterTest.groovy @@ -29,9 +29,9 @@ class BufferedCsvWriterTest extends Specification { def "The convenience constructor of the BufferedCsvWriter class works as expected."() { given: - def baseDirectory = tmpDirectory.toString() - def fileDefinition = new CsvFileDefinition("test.csv", "", ["a", "b", "c"] as String[], ",") - def expectedFile = new File(FilenameUtils.concat(tmpDirectory.toString(), fileDefinition.filePath)) + def baseDirectory = tmpDirectory + def fileDefinition = new CsvFileDefinition("test.csv", Path.of(""), ["a", "b", "c"] as String[], ",") + def expectedFile = tmpDirectory.resolve(fileDefinition.filePath).toFile() when: def actual = new BufferedCsvWriter(baseDirectory, fileDefinition, false) @@ -47,7 +47,7 @@ class BufferedCsvWriterTest extends Specification { def "The buffered csv writer refuses to write entries, if their length does not conform the needed length of head line elements"() { given: - def targetFile = FilenameUtils.concat(tmpDirectory.toString(), "test.csv") + def targetFile = tmpDirectory.resolve("test.csv") def writer = new BufferedCsvWriter(targetFile, ["a", "b", "c"] as String[], "c,", false) def malFormedInput = [ "a": "z", @@ -64,7 +64,7 @@ class BufferedCsvWriterTest extends Specification { def "The buffered csv writer refuses to write entries, if keys do not match the required head line"() { given: - def targetFile = FilenameUtils.concat(tmpDirectory.toString(), "test.csv") + def targetFile = tmpDirectory.resolve("test.csv") def writer = new BufferedCsvWriter(targetFile, ["a", "b", "c"] as String[], "c,", false) def malFormedInput = [ "a": "z", @@ -82,7 +82,7 @@ class BufferedCsvWriterTest extends Specification { def "The buffered csv writer writes out content in the order specified by the headline elements"() { given: - def targetFile = FilenameUtils.concat(tmpDirectory.toString(), "order_test.csv") + def targetFile = tmpDirectory.resolve("order_test.csv") def writer = new BufferedCsvWriter(targetFile, ["third_header", "second_header", "first_header"] as String[], ",", false) writer.writeFileHeader() def content = [ @@ -97,7 +97,7 @@ class BufferedCsvWriterTest extends Specification { /* Read in the content */ def writtenContent = "" def headline = "" - try(BufferedReader reader = new BufferedReader(new FileReader(targetFile))) { + try(BufferedReader reader = new BufferedReader(new FileReader(targetFile.toFile()))) { headline = reader.readLine() writtenContent = reader.readLine() } catch (Exception e) { diff --git a/src/test/groovy/edu/ie3/datamodel/io/csv/CsvFileDefinitionTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/csv/CsvFileDefinitionTest.groovy index 054388dad..747d64120 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/csv/CsvFileDefinitionTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/csv/CsvFileDefinitionTest.groovy @@ -9,6 +9,8 @@ import org.apache.commons.io.FilenameUtils import spock.lang.Shared import spock.lang.Specification +import java.nio.file.Path + class CsvFileDefinitionTest extends Specification { @Shared String[] headLineElements @@ -20,45 +22,13 @@ class CsvFileDefinitionTest extends Specification { String fileName @Shared - String directory + Path directory def setupSpec() { headLineElements = ["a", "b", "c"] as String[] csvSep = "," fileName = "node_input.csv" - directory = FilenameUtils.concat("test", "grid") - } - - def "A csv file definition is set up correctly, if the directory path has corrupt file separator"() { - when: - def actual = new CsvFileDefinition(fileName, manipulatedDirectory, headLineElements, csvSep) - - then: - actual.with { - assert it.fileName() == this.fileName - assert it.directoryPath() == this.directory - assert it.headLineElements() == this.headLineElements - assert it.csvSep() == this.csvSep - } - - where: - manipulatedDirectory || expected - "/" + this.directory || this.directory - this.directory + "/" || this.directory - this.directory.replaceAll("[\\\\/]", File.separator == "/" ? "\\\\" : "/") || this.directory - } - - def "A csv file definition is set up correctly, if the directory path is null"() { - when: - def actual = new CsvFileDefinition(fileName, null, headLineElements, csvSep) - - then: - actual.with { - assert it.fileName() == this.fileName - assert it.directoryPath() == "" - assert it.headLineElements() == this.headLineElements - assert it.csvSep() == this.csvSep - } + directory = Path.of("test", "grid") } def "A csv file definition throw IllegalArgumentException, if the file name is malformed"() { @@ -82,8 +52,8 @@ class CsvFileDefinitionTest extends Specification { then: actual.with { - assert it.fileName() == this.fileName - assert it.directoryPath() == this.directory + assert it.filePath.fileName == Path.of(this.fileName) + assert it.directoryPath == this.directory assert it.headLineElements() == this.headLineElements assert it.csvSep() == this.csvSep } @@ -98,26 +68,10 @@ class CsvFileDefinitionTest extends Specification { then: actual.with { - assert it.fileName() == this.fileName - assert it.directoryPath() == directory + assert it.filePath.fileName == Path.of(this.fileName) + assert it.directoryPath == this.directory assert it.headLineElements() == this.headLineElements assert it.csvSep() == this.csvSep } } - - def "A csv file definition returns correct file path"() { - given: - def definition = new CsvFileDefinition(fileName, manipulatedDirectory, headLineElements, csvSep) - - when: - def actual = definition.filePath - - then: - actual == expected - - where: - manipulatedDirectory || expected - "" || this.fileName - FilenameUtils.concat("test", "grid") || FilenameUtils.concat(FilenameUtils.concat("test", "grid"), this.fileName) - } } diff --git a/src/test/groovy/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchyTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchyTest.groovy index af30a17b3..8852605c4 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchyTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchyTest.groovy @@ -28,7 +28,7 @@ class DefaultDirectoryHierarchyTest extends Specification { } def basePathString(String gridName) { - FilenameUtils.concat(tmpDirectory.toString(), gridName) + tmpDirectory.resolve(gridName) } def cleanup() { @@ -41,21 +41,21 @@ class DefaultDirectoryHierarchyTest extends Specification { def basePath = basePathString(gridName) when: - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) then: try { - dfh.baseDirectory == Paths.get(basePath) + dfh.baseDirectory.get() == basePath dfh.subDirectories.size() == 9 - dfh.subDirectories.get(Paths.get(Stream.of(basePath, "input", "grid").collect(Collectors.joining(File.separator)))) == true - dfh.subDirectories.get(Paths.get(Stream.of(basePath, "input", "participants").collect(Collectors.joining(File.separator)))) == true - dfh.subDirectories.get(Paths.get(Stream.of(basePath, "input", "participants", "time_series").collect(Collectors.joining(File.separator)))) == false - dfh.subDirectories.get(Paths.get(Stream.of(basePath, "input", "global").collect(Collectors.joining(File.separator)))) == true - dfh.subDirectories.get(Paths.get(Stream.of(basePath, "input", "thermal").collect(Collectors.joining(File.separator)))) == false - dfh.subDirectories.get(Paths.get(Stream.of(basePath, "input", "graphics").collect(Collectors.joining(File.separator)))) == false - dfh.subDirectories.get(Paths.get(Stream.of(basePath, "results", "grid").collect(Collectors.joining(File.separator)))) == false - dfh.subDirectories.get(Paths.get(Stream.of(basePath, "results", "participants").collect(Collectors.joining(File.separator)))) == false - dfh.subDirectories.get(Paths.get(Stream.of(basePath, "results", "thermal").collect(Collectors.joining(File.separator)))) == false + dfh.subDirectories.get(basePath.resolve(Path.of("input", "grid"))) == true + dfh.subDirectories.get(basePath.resolve(Path.of("input", "participants"))) == true + dfh.subDirectories.get(basePath.resolve(Path.of("input", "participants", "time_series"))) == false + dfh.subDirectories.get(basePath.resolve(Path.of("input", "global"))) == true + dfh.subDirectories.get(basePath.resolve(Path.of("input", "thermal"))) == false + dfh.subDirectories.get(basePath.resolve(Path.of("input", "graphics"))) == false + dfh.subDirectories.get(basePath.resolve(Path.of("results", "grid"))) == false + dfh.subDirectories.get(basePath.resolve(Path.of("results", "participants"))) == false + dfh.subDirectories.get(basePath.resolve(Path.of("results", "thermal"))) == false } catch (TestFailedException e) { FileIOUtils.deleteRecursively(tmpDirectory) throw e @@ -65,8 +65,8 @@ class DefaultDirectoryHierarchyTest extends Specification { def "A DefaultFileHierarchy is able to create a correct hierarchy of mandatory directories"() { given: def gridName = "test_grid" - def basePath = Paths.get(basePathString(gridName)) - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def basePath = basePathString(gridName) + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) when: dfh.createDirs() @@ -91,8 +91,8 @@ class DefaultDirectoryHierarchyTest extends Specification { def "A DefaultFileHierarchy is able to create a correct hierarchy of mandatory and optional directories"() { given: def gridName = "test_grid" - def basePath = Paths.get(basePathString(gridName)) - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def basePath = basePathString(gridName) + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) when: dfh.createDirs(true) @@ -112,7 +112,7 @@ class DefaultDirectoryHierarchyTest extends Specification { def "A DefaultFileHierarchy is able to validate a correct hierarchy of mandatory and optional directories"() { given: def gridName = "test_grid" - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) dfh.createDirs(true) when: @@ -125,8 +125,8 @@ class DefaultDirectoryHierarchyTest extends Specification { def "A DefaultFileHierarchy throws an exception when trying to validate a missing hierarchy of mandatory and optional directories"() { given: def gridName = "test_grid" - def basePath = Paths.get(basePathString(gridName)) - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def basePath = basePathString(gridName) + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) when: dfh.validate() @@ -139,8 +139,8 @@ class DefaultDirectoryHierarchyTest extends Specification { def "A DefaultFileHierarchy throws an exception when trying to validate a file instead of a hierarchy"() { given: def gridName = "test_grid" - def basePath = Paths.get(basePathString(gridName)) - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def basePath = basePathString(gridName) + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) Files.createFile(basePath) when: @@ -154,8 +154,8 @@ class DefaultDirectoryHierarchyTest extends Specification { def "A DefaultFileHierarchy throws an exception when trying to validate a hierarchy with missing mandatory directory"() { given: def gridName = "test_grid" - def basePath = Paths.get(basePathString(gridName)) - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def basePath = basePathString(gridName) + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) dfh.createDirs() def globalDirectory = dfh.subDirectories.entrySet().find { entry -> entry.key.toString().endsWith("global") }.key Files.delete(globalDirectory) @@ -171,8 +171,8 @@ class DefaultDirectoryHierarchyTest extends Specification { def "A DefaultFileHierarchy throws an exception when trying to validate a hierarchy with file instead of mandatory directory"() { given: def gridName = "test_grid" - def basePath = Paths.get(basePathString(gridName)) - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def basePath = basePathString(gridName) + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) dfh.createDirs() def globalDirectory = dfh.subDirectories.entrySet().find { entry -> entry.key.toString().endsWith("global") }.key Files.delete(globalDirectory) @@ -189,8 +189,8 @@ class DefaultDirectoryHierarchyTest extends Specification { def "A DefaultFileHierarchy throws an exception when trying to validate a hierarchy with file instead of optional directory"() { given: def gridName = "test_grid" - def basePath = Paths.get(basePathString(gridName)) - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def basePath = basePathString(gridName) + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) dfh.createDirs(true) def thermalDirectory = dfh.subDirectories.entrySet().find { entry -> entry.key.toString().endsWith("input" + File.separator + "thermal") }.key Files.delete(thermalDirectory) @@ -207,9 +207,9 @@ class DefaultDirectoryHierarchyTest extends Specification { def "A DefaultFileHierarchy throws an exception when trying to validate a hierarchy with unsupported extra directory"() { given: def gridName = "test_grid" - def basePath = Paths.get(basePathString(gridName)) - def fifthWheelPath = Paths.get(FilenameUtils.concat(basePathString(gridName), "something_on_top")) - def dfh = new DefaultDirectoryHierarchy(tmpDirectory.toString(), gridName) + def basePath = basePathString(gridName) + def fifthWheelPath = basePathString(gridName).resolve("something_on_top") + def dfh = new DefaultDirectoryHierarchy(tmpDirectory, gridName) dfh.createDirs(true) Files.createDirectory(fifthWheelPath) diff --git a/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy index a8fed6091..e36fe9c9d 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy @@ -69,7 +69,7 @@ import spock.lang.Specification import tech.units.indriya.quantity.Quantities import java.nio.file.Files -import java.nio.file.Paths +import java.nio.file.Path import java.time.ZonedDateTime class FileNamingStrategyTest extends Specification { @@ -81,7 +81,7 @@ class FileNamingStrategyTest extends Specification { def setup() { def tmpPath = Files.createTempDirectory("psdm_file_naming_strategy") - defaultHierarchy = new DefaultDirectoryHierarchy(tmpPath.toString(), "test_grid") + defaultHierarchy = new DefaultDirectoryHierarchy(tmpPath, "test_grid") flatHierarchy = new FlatDirectoryHierarchy() simpleEntityNaming = new EntityPersistenceNamingStrategy() } @@ -98,28 +98,28 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - LoadResult || "test_grid" + File.separator + "results" + File.separator + "participants" - FixedFeedInResult || "test_grid" + File.separator + "results" + File.separator + "participants" - BmResult || "test_grid" + File.separator + "results" + File.separator + "participants" - PvResult || "test_grid" + File.separator + "results" + File.separator + "participants" - ChpResult || "test_grid" + File.separator + "results" + File.separator + "participants" - WecResult || "test_grid" + File.separator + "results" + File.separator + "participants" - StorageResult || "test_grid" + File.separator + "results" + File.separator + "participants" - EvcsResult || "test_grid" + File.separator + "results" + File.separator + "participants" - EvResult || "test_grid" + File.separator + "results" + File.separator + "participants" - EmResult || "test_grid" + File.separator + "results" + File.separator + "participants" - FlexOptionsResult || "test_grid" + File.separator + "results" + File.separator + "participants" - Transformer2WResult || "test_grid" + File.separator + "results" + File.separator + "grid" - Transformer3WResult || "test_grid" + File.separator + "results" + File.separator + "grid" - LineResult || "test_grid" + File.separator + "results" + File.separator + "grid" - SwitchResult || "test_grid" + File.separator + "results" + File.separator + "grid" - NodeResult || "test_grid" + File.separator + "results" + File.separator + "grid" - CylindricalStorageResult || "test_grid" + File.separator + "results" + File.separator + "thermal" - ThermalHouseResult || "test_grid" + File.separator + "results" + File.separator + "thermal" + modelClass || expectedPath + LoadResult || Path.of("test_grid", "results", "participants") + FixedFeedInResult || Path.of("test_grid", "results", "participants") + BmResult || Path.of("test_grid", "results", "participants") + PvResult || Path.of("test_grid", "results", "participants") + ChpResult || Path.of("test_grid", "results", "participants") + WecResult || Path.of("test_grid", "results", "participants") + StorageResult || Path.of("test_grid", "results", "participants") + EvcsResult || Path.of("test_grid", "results", "participants") + EvResult || Path.of("test_grid", "results", "participants") + EmResult || Path.of("test_grid", "results", "participants") + FlexOptionsResult || Path.of("test_grid", "results", "participants") + Transformer2WResult || Path.of("test_grid", "results", "grid") + Transformer3WResult || Path.of("test_grid", "results", "grid") + LineResult || Path.of("test_grid", "results", "grid") + SwitchResult || Path.of("test_grid", "results", "grid") + NodeResult || Path.of("test_grid", "results", "grid") + CylindricalStorageResult || Path.of("test_grid", "results", "thermal") + ThermalHouseResult || Path.of("test_grid", "results", "thermal") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid directory paths for all input assets models"() { @@ -131,28 +131,28 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - FixedFeedInInput || "test_grid" + File.separator + "input" + File.separator + "participants" - PvInput || "test_grid" + File.separator + "input" + File.separator + "participants" - WecInput || "test_grid" + File.separator + "input" + File.separator + "participants" - ChpInput || "test_grid" + File.separator + "input" + File.separator + "participants" - BmInput || "test_grid" + File.separator + "input" + File.separator + "participants" - EvInput || "test_grid" + File.separator + "input" + File.separator + "participants" - EvcsInput || "test_grid" + File.separator + "input" + File.separator + "participants" - LoadInput || "test_grid" + File.separator + "input" + File.separator + "participants" - StorageInput || "test_grid" + File.separator + "input" + File.separator + "participants" - HpInput || "test_grid" + File.separator + "input" + File.separator + "participants" - LineInput || "test_grid" + File.separator + "input" + File.separator + "grid" - SwitchInput || "test_grid" + File.separator + "input" + File.separator + "grid" - NodeInput || "test_grid" + File.separator + "input" + File.separator + "grid" - MeasurementUnitInput || "test_grid" + File.separator + "input" + File.separator + "grid" - Transformer2WInput || "test_grid" + File.separator + "input" + File.separator + "grid" - Transformer3WInput || "test_grid" + File.separator + "input" + File.separator + "grid" - CylindricalStorageInput || "test_grid" + File.separator + "input" + File.separator + "thermal" - ThermalHouseInput || "test_grid" + File.separator + "input" + File.separator + "thermal" + modelClass || expectedPath + FixedFeedInInput || Path.of("test_grid", "input", "participants") + PvInput || Path.of("test_grid", "input", "participants") + WecInput || Path.of("test_grid", "input", "participants") + ChpInput || Path.of("test_grid", "input", "participants") + BmInput || Path.of("test_grid", "input", "participants") + EvInput || Path.of("test_grid", "input", "participants") + EvcsInput || Path.of("test_grid", "input", "participants") + LoadInput || Path.of("test_grid", "input", "participants") + StorageInput || Path.of("test_grid", "input", "participants") + HpInput || Path.of("test_grid", "input", "participants") + LineInput || Path.of("test_grid", "input", "grid") + SwitchInput || Path.of("test_grid", "input", "grid") + NodeInput || Path.of("test_grid", "input", "grid") + MeasurementUnitInput || Path.of("test_grid", "input", "grid") + Transformer2WInput || Path.of("test_grid", "input", "grid") + Transformer3WInput || Path.of("test_grid", "input", "grid") + CylindricalStorageInput || Path.of("test_grid", "input", "thermal") + ThermalHouseInput || Path.of("test_grid", "input", "thermal") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid directory paths for all input types models"() { @@ -164,19 +164,19 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - BmTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" - ChpTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" - EvTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" - HpTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" - StorageTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" - WecTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" - LineTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" - Transformer2WTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" - Transformer3WTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + modelClass || expectedPath + BmTypeInput || Path.of("test_grid", "input", "global") + ChpTypeInput || Path.of("test_grid", "input", "global") + EvTypeInput || Path.of("test_grid", "input", "global") + HpTypeInput || Path.of("test_grid", "input", "global") + StorageTypeInput || Path.of("test_grid", "input", "global") + WecTypeInput || Path.of("test_grid", "input", "global") + LineTypeInput || Path.of("test_grid", "input", "global") + Transformer2WTypeInput || Path.of("test_grid", "input", "global") + Transformer3WTypeInput || Path.of("test_grid", "input", "global") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid directory paths for a graphic input Model"() { @@ -188,12 +188,12 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - NodeGraphicInput || "test_grid" + File.separator + "input" + File.separator + "graphics" - LineGraphicInput || "test_grid" + File.separator + "input" + File.separator + "graphics" + modelClass || expectedPath + NodeGraphicInput || Path.of("test_grid", "input", "graphics") + LineGraphicInput || Path.of("test_grid", "input", "graphics") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffix should return valid directory path for load profile time series"() { @@ -210,7 +210,7 @@ class FileNamingStrategyTest extends Specification { where: clazz || expected - LoadProfileInput || "test_grid" + File.separator + "input" + File.separator + "global" + LoadProfileInput || Path.of("test_grid", "input", "global") } def "A FileNamingStrategy with DefaultHierarchy and should return valid directory path for individual time series"() { @@ -227,7 +227,7 @@ class FileNamingStrategyTest extends Specification { where: clazz || expected - IndividualTimeSeries || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "time_series" + IndividualTimeSeries || Path.of("test_grid", "input", "participants", "time_series") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid file paths for all result models"() { @@ -239,28 +239,28 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - LoadResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "load_res" - FixedFeedInResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "fixed_feed_in_res" - BmResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "bm_res" - PvResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "pv_res" - ChpResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "chp_res" - WecResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "wec_res" - StorageResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "storage_res" - EvcsResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "evcs_res" - EvResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "ev_res" - EmResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "em_res" - FlexOptionsResult || "test_grid" + File.separator + "results" + File.separator + "participants" + File.separator + "flex_options_res" - Transformer2WResult || "test_grid" + File.separator + "results" + File.separator + "grid" + File.separator + "transformer_2_w_res" - Transformer3WResult || "test_grid" + File.separator + "results" + File.separator + "grid" + File.separator + "transformer_3_w_res" - LineResult || "test_grid" + File.separator + "results" + File.separator + "grid" + File.separator + "line_res" - SwitchResult || "test_grid" + File.separator + "results" + File.separator + "grid" + File.separator + "switch_res" - NodeResult || "test_grid" + File.separator + "results" + File.separator + "grid" + File.separator + "node_res" - CylindricalStorageResult || "test_grid" + File.separator + "results" + File.separator + "thermal" + File.separator + "cylindrical_storage_res" - ThermalHouseResult || "test_grid" + File.separator + "results" + File.separator + "thermal" + File.separator + "thermal_house_res" + modelClass || expectedPath + LoadResult || Path.of("test_grid", "results", "participants", "load_res") + FixedFeedInResult || Path.of("test_grid", "results", "participants", "fixed_feed_in_res") + BmResult || Path.of("test_grid", "results", "participants", "bm_res") + PvResult || Path.of("test_grid", "results", "participants", "pv_res") + ChpResult || Path.of("test_grid", "results", "participants", "chp_res") + WecResult || Path.of("test_grid", "results", "participants", "wec_res") + StorageResult || Path.of("test_grid", "results", "participants", "storage_res") + EvcsResult || Path.of("test_grid", "results", "participants", "evcs_res") + EvResult || Path.of("test_grid", "results", "participants", "ev_res") + EmResult || Path.of("test_grid", "results", "participants", "em_res") + FlexOptionsResult || Path.of("test_grid", "results", "participants", "flex_options_res") + Transformer2WResult || Path.of("test_grid", "results", "grid", "transformer_2_w_res") + Transformer3WResult || Path.of("test_grid", "results", "grid", "transformer_3_w_res") + LineResult || Path.of("test_grid", "results", "grid", "line_res") + SwitchResult || Path.of("test_grid", "results", "grid", "switch_res") + NodeResult || Path.of("test_grid", "results", "grid", "node_res") + CylindricalStorageResult || Path.of("test_grid", "results", "thermal", "cylindrical_storage_res") + ThermalHouseResult || Path.of("test_grid", "results", "thermal", "thermal_house_res") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid file paths for all other input assets models"() { @@ -272,18 +272,18 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - LineInput || "test_grid" + File.separator + "input" + File.separator + "grid" + File.separator + "line_input" - SwitchInput || "test_grid" + File.separator + "input" + File.separator + "grid" + File.separator + "switch_input" - NodeInput || "test_grid" + File.separator + "input" + File.separator + "grid" + File.separator + "node_input" - MeasurementUnitInput || "test_grid" + File.separator + "input" + File.separator + "grid" + File.separator + "measurement_unit_input" - Transformer2WInput || "test_grid" + File.separator + "input" + File.separator + "grid" + File.separator + "transformer_2_w_input" - Transformer3WInput || "test_grid" + File.separator + "input" + File.separator + "grid" + File.separator + "transformer_3_w_input" - CylindricalStorageInput || "test_grid" + File.separator + "input" + File.separator + "thermal" + File.separator + "cylindrical_storage_input" - ThermalHouseInput || "test_grid" + File.separator + "input" + File.separator + "thermal" + File.separator + "thermal_house_input" + modelClass || expectedPath + LineInput || Path.of("test_grid", "input", "grid", "line_input") + SwitchInput || Path.of("test_grid", "input", "grid", "switch_input") + NodeInput || Path.of("test_grid", "input", "grid", "node_input") + MeasurementUnitInput || Path.of("test_grid", "input", "grid", "measurement_unit_input") + Transformer2WInput || Path.of("test_grid", "input", "grid", "transformer_2_w_input") + Transformer3WInput || Path.of("test_grid", "input", "grid", "transformer_3_w_input") + CylindricalStorageInput || Path.of("test_grid", "input", "thermal", "cylindrical_storage_input") + ThermalHouseInput || Path.of("test_grid", "input", "thermal", "thermal_house_input") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid file paths for all system input assets models"() { @@ -295,20 +295,20 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - FixedFeedInInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "fixed_feed_in_input" - PvInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "pv_input" - WecInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "wec_input" - ChpInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "chp_input" - BmInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "bm_input" - EvInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "ev_input" - LoadInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "load_input" - StorageInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "storage_input" - HpInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "hp_input" - EvcsInput || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "evcs_input" + modelClass || expectedPath + FixedFeedInInput || Path.of("test_grid", "input", "participants", "fixed_feed_in_input") + PvInput || Path.of("test_grid", "input", "participants", "pv_input") + WecInput || Path.of("test_grid", "input", "participants", "wec_input") + ChpInput || Path.of("test_grid", "input", "participants", "chp_input") + BmInput || Path.of("test_grid", "input", "participants", "bm_input") + EvInput || Path.of("test_grid", "input", "participants", "ev_input") + LoadInput || Path.of("test_grid", "input", "participants", "load_input") + StorageInput || Path.of("test_grid", "input", "participants", "storage_input") + HpInput || Path.of("test_grid", "input", "participants", "hp_input") + EvcsInput || Path.of("test_grid", "input", "participants", "evcs_input") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid file paths for all input types models"() { @@ -320,19 +320,19 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - BmTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "bm_type_input" - ChpTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "chp_type_input" - EvTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "ev_type_input" - HpTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "hp_type_input" - LineTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "line_type_input" - StorageTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "storage_type_input" - Transformer2WTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "transformer_2_w_type_input" - Transformer3WTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "transformer_3_w_type_input" - WecTypeInput || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "wec_type_input" + modelClass || expectedPath + BmTypeInput || Path.of("test_grid", "input", "global", "bm_type_input") + ChpTypeInput || Path.of("test_grid", "input", "global", "chp_type_input") + EvTypeInput || Path.of("test_grid", "input", "global", "ev_type_input") + HpTypeInput || Path.of("test_grid", "input", "global", "hp_type_input") + LineTypeInput || Path.of("test_grid", "input", "global", "line_type_input") + StorageTypeInput || Path.of("test_grid", "input", "global", "storage_type_input") + Transformer2WTypeInput || Path.of("test_grid", "input", "global", "transformer_2_w_type_input") + Transformer3WTypeInput || Path.of("test_grid", "input", "global", "transformer_3_w_type_input") + WecTypeInput || Path.of("test_grid", "input", "global", "wec_type_input") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid directory path for a Load Parameter Model"() { @@ -344,11 +344,11 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - RandomLoadParameters || "test_grid" + File.separator + "input" + File.separator + "global" + modelClass || expectedPath + RandomLoadParameters || Path.of("test_grid", "input", "global") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid file path for a Load Parameter Model"() { @@ -360,11 +360,11 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - RandomLoadParameters || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "random_load_parameters_input" + modelClass || expectedPath + RandomLoadParameters || Path.of("test_grid", "input", "global", "random_load_parameters_input") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid file paths for a graphic input Model"() { @@ -376,12 +376,12 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - NodeGraphicInput || "test_grid" + File.separator + "input" + File.separator + "graphics" + File.separator + "node_graphic_input" - LineGraphicInput || "test_grid" + File.separator + "input" + File.separator + "graphics" + File.separator + "line_graphic_input" + modelClass || expectedPath + NodeGraphicInput || Path.of("test_grid", "input", "graphics", "node_graphic_input") + LineGraphicInput || Path.of("test_grid", "input", "graphics", "line_graphic_input") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffix should return valid file path for individual time series"() { @@ -403,7 +403,7 @@ class FileNamingStrategyTest extends Specification { where: clazz | uuid || expectedFilePath - IndividualTimeSeries | UUID.fromString("4881fda2-bcee-4f4f-a5bb-6a09bf785276") || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "time_series" + File.separator + "its_c_4881fda2-bcee-4f4f-a5bb-6a09bf785276" + IndividualTimeSeries | UUID.fromString("4881fda2-bcee-4f4f-a5bb-6a09bf785276") || Path.of("test_grid", "input", "participants", "time_series", "its_c_4881fda2-bcee-4f4f-a5bb-6a09bf785276") } def "A FileNamingStrategy with DefaultHierarchy and with pre- or suffix should return valid file path for individual time series"() { @@ -425,7 +425,7 @@ class FileNamingStrategyTest extends Specification { where: clazz | uuid || expectedFileName - IndividualTimeSeries | UUID.fromString("4881fda2-bcee-4f4f-a5bb-6a09bf785276") || "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "time_series" + File.separator + "aa_its_c_4881fda2-bcee-4f4f-a5bb-6a09bf785276_zz" + IndividualTimeSeries | UUID.fromString("4881fda2-bcee-4f4f-a5bb-6a09bf785276") || Path.of("test_grid", "input", "participants", "time_series", "aa_its_c_4881fda2-bcee-4f4f-a5bb-6a09bf785276_zz") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffix should return valid file path for load profile time series"() { @@ -444,7 +444,7 @@ class FileNamingStrategyTest extends Specification { where: clazz | uuid | type || expectedFileName - LoadProfileInput | UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") | BdewStandardLoadProfile.G3 || "test_grid" + File.separator + "input" + File.separator + "global" + File.separator + "lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304" + LoadProfileInput | UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") | BdewStandardLoadProfile.G3 || Path.of("test_grid", "input", "global", "lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid directory path for time series mapping"() { @@ -456,7 +456,7 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "time_series" + res.get() == Path.of("test_grid", "input", "participants", "time_series") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid file path for time series mapping"() { @@ -468,7 +468,7 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "time_series" + File.separator + "time_series_mapping" + res.get() == Path.of("test_grid", "input", "participants", "time_series", "time_series_mapping") } def "A FileNamingStrategy with DefaultHierarchy and pre- and suffix should return valid file path for time series mapping"() { @@ -480,7 +480,7 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == "test_grid" + File.separator + "input" + File.separator + "participants" + File.separator + "time_series" + File.separator + "prefix_time_series_mapping_suffix" + res.get() == Path.of("test_grid", "input", "participants", "time_series", "prefix_time_series_mapping_suffix") } @@ -638,28 +638,28 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - LoadResult || "load_res" - FixedFeedInResult || "fixed_feed_in_res" - BmResult || "bm_res" - PvResult || "pv_res" - ChpResult || "chp_res" - WecResult || "wec_res" - StorageResult || "storage_res" - EvcsResult || "evcs_res" - EvResult || "ev_res" - EmResult || "em_res" - FlexOptionsResult || "flex_options_res" - Transformer2WResult || "transformer_2_w_res" - Transformer3WResult || "transformer_3_w_res" - LineResult || "line_res" - SwitchResult || "switch_res" - NodeResult || "node_res" - CylindricalStorageResult || "cylindrical_storage_res" - ThermalHouseResult || "thermal_house_res" + modelClass || expectedPath + LoadResult || Path.of("load_res") + FixedFeedInResult || Path.of("fixed_feed_in_res") + BmResult || Path.of("bm_res") + PvResult || Path.of("pv_res") + ChpResult || Path.of("chp_res") + WecResult || Path.of("wec_res") + StorageResult || Path.of("storage_res") + EvcsResult || Path.of("evcs_res") + EvResult || Path.of("ev_res") + EmResult || Path.of("em_res") + FlexOptionsResult || Path.of("flex_options_res") + Transformer2WResult || Path.of("transformer_2_w_res") + Transformer3WResult || Path.of("transformer_3_w_res") + LineResult || Path.of("line_res") + SwitchResult || Path.of("switch_res") + NodeResult || Path.of("node_res") + CylindricalStorageResult || Path.of("cylindrical_storage_res") + ThermalHouseResult || Path.of("thermal_house_res") } def "A FileNamingStrategy with FlatHierarchy and without pre- or suffixes should return valid file paths for all other system input classes"() { @@ -671,28 +671,28 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - FixedFeedInInput || "fixed_feed_in_input" - PvInput || "pv_input" - WecInput || "wec_input" - ChpInput || "chp_input" - BmInput || "bm_input" - EvInput || "ev_input" - EvcsInput || "evcs_input" - LoadInput || "load_input" - StorageInput || "storage_input" - HpInput || "hp_input" - LineInput || "line_input" - SwitchInput || "switch_input" - NodeInput || "node_input" - MeasurementUnitInput || "measurement_unit_input" - Transformer2WInput || "transformer_2_w_input" - Transformer3WInput || "transformer_3_w_input" - CylindricalStorageInput || "cylindrical_storage_input" - ThermalHouseInput || "thermal_house_input" + modelClass || expectedPath + FixedFeedInInput || Path.of("fixed_feed_in_input") + PvInput || Path.of("pv_input") + WecInput || Path.of("wec_input") + ChpInput || Path.of("chp_input") + BmInput || Path.of("bm_input") + EvInput || Path.of("ev_input") + EvcsInput || Path.of("evcs_input") + LoadInput || Path.of("load_input") + StorageInput || Path.of("storage_input") + HpInput || Path.of("hp_input") + LineInput || Path.of("line_input") + SwitchInput || Path.of("switch_input") + NodeInput || Path.of("node_input") + MeasurementUnitInput || Path.of("measurement_unit_input") + Transformer2WInput || Path.of("transformer_2_w_input") + Transformer3WInput || Path.of("transformer_3_w_input") + CylindricalStorageInput || Path.of("cylindrical_storage_input") + ThermalHouseInput || Path.of("thermal_house_input") } def "A FileNamingStrategy with FlatHierarchy and without pre- or suffixes should return valid file paths for all system characteristic and type input classes"() { @@ -704,19 +704,19 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - BmTypeInput || "bm_type_input" - ChpTypeInput || "chp_type_input" - EvTypeInput || "ev_type_input" - HpTypeInput || "hp_type_input" - StorageTypeInput || "storage_type_input" - WecTypeInput || "wec_type_input" - LineTypeInput || "line_type_input" - Transformer2WTypeInput || "transformer_2_w_type_input" - Transformer3WTypeInput || "transformer_3_w_type_input" + modelClass || expectedPath + BmTypeInput || Path.of("bm_type_input") + ChpTypeInput || Path.of("chp_type_input") + EvTypeInput || Path.of("ev_type_input") + HpTypeInput || Path.of("hp_type_input") + StorageTypeInput || Path.of("storage_type_input") + WecTypeInput || Path.of("wec_type_input") + LineTypeInput || Path.of("line_type_input") + Transformer2WTypeInput || Path.of("transformer_2_w_type_input") + Transformer3WTypeInput || Path.of("transformer_3_w_type_input") } def "A FileNamingStrategy with FlatHierarchy and without pre- or suffixes should return valid file paths for all graphics input classes"() { @@ -728,12 +728,12 @@ class FileNamingStrategyTest extends Specification { then: res.present - res.get() == expectedString + res.get() == expectedPath where: - modelClass || expectedString - NodeGraphicInput || "node_graphic_input" - LineGraphicInput || "line_graphic_input" + modelClass || expectedPath + NodeGraphicInput || Path.of("node_graphic_input") + LineGraphicInput || Path.of("line_graphic_input") } def "A FileNamingStrategy with FlatHierarchy does return valid file path for load profile time series"() { @@ -752,7 +752,7 @@ class FileNamingStrategyTest extends Specification { where: clazz | uuid | type || expectedFilePath - LoadProfileInput | UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") | BdewStandardLoadProfile.G3 || "lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304" + LoadProfileInput | UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") | BdewStandardLoadProfile.G3 || Path.of("lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304") } def "A FileNamingStrategy with FlatHierarchy does return valid file path for individual time series"() { @@ -774,7 +774,7 @@ class FileNamingStrategyTest extends Specification { where: clazz | uuid || expectedFilePath - IndividualTimeSeries | UUID.fromString("4881fda2-bcee-4f4f-a5bb-6a09bf785276") || "its_c_4881fda2-bcee-4f4f-a5bb-6a09bf785276" + IndividualTimeSeries | UUID.fromString("4881fda2-bcee-4f4f-a5bb-6a09bf785276") || Path.of("its_c_4881fda2-bcee-4f4f-a5bb-6a09bf785276") } String escapedFileSeparator = File.separator == "\\" ? "\\\\" : File.separator @@ -826,7 +826,7 @@ class FileNamingStrategyTest extends Specification { def "Trying to extract time series meta information throws an Exception, if it is provided a malformed string"() { given: def fns = new FileNamingStrategy(simpleEntityNaming, flatHierarchy) - def path = Paths.get("/bla/foo") + def path = Path.of("/bla/foo") when: fns.timeSeriesMetaInformation(path) @@ -839,7 +839,7 @@ class FileNamingStrategyTest extends Specification { def "The FileNamingStrategy extracts correct meta information from a valid time series file name"() { given: def fns = new FileNamingStrategy(simpleEntityNaming, flatHierarchy) - def path = Paths.get(pathString) + def path = Path.of(pathString) when: def metaInformation = fns.timeSeriesMetaInformation(path) @@ -865,7 +865,7 @@ class FileNamingStrategyTest extends Specification { def "The FileNamingStrategy extracts correct meta information from a valid time series file name with pre- and suffix"() { given: def fns = new FileNamingStrategy(new EntityPersistenceNamingStrategy("prefix", "suffix"), flatHierarchy) - def path = Paths.get(pathString) + def path = Path.of(pathString) when: def metaInformation = fns.timeSeriesMetaInformation(path) @@ -929,7 +929,7 @@ class FileNamingStrategyTest extends Specification { def "The FileNamingStrategy throw an IllegalArgumentException, if the column scheme is malformed."() { given: def fns = new FileNamingStrategy(simpleEntityNaming, flatHierarchy) - def path = Paths.get("/bla/foo/its_whoops_4881fda2-bcee-4f4f-a5bb-6a09bf785276.csv") + def path = Path.of("/bla/foo/its_whoops_4881fda2-bcee-4f4f-a5bb-6a09bf785276.csv") when: fns.timeSeriesMetaInformation(path) @@ -942,7 +942,7 @@ class FileNamingStrategyTest extends Specification { def "The FileNamingStrategy extracts correct meta information from a valid load profile time series file name"() { given: def fns = new FileNamingStrategy(simpleEntityNaming, flatHierarchy) - def path = Paths.get("/bla/foo/lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304.csv") + def path = Path.of("/bla/foo/lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304.csv") when: def metaInformation = fns.timeSeriesMetaInformation(path) @@ -958,7 +958,7 @@ class FileNamingStrategyTest extends Specification { def "The FileNamingStrategy extracts correct meta information from a valid load profile time series file name with pre- and suffix"() { given: def fns = new FileNamingStrategy(new EntityPersistenceNamingStrategy("prefix", "suffix"), flatHierarchy) - def path = Paths.get("/bla/foo/prefix_lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304_suffix.csv") + def path = Path.of("/bla/foo/prefix_lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304_suffix.csv") when: def metaInformation = fns.timeSeriesMetaInformation(path) @@ -980,7 +980,7 @@ class FileNamingStrategyTest extends Specification { then: idFilePath.present - idFilePath.get() == "prefix_coordinates_suffix" + idFilePath.get() == Path.of("prefix_coordinates_suffix") } def "The FileNamingStrategy with DefaultHierarchy returns the Id Coordinate file path correctly"() { @@ -991,6 +991,6 @@ class FileNamingStrategyTest extends Specification { then: idFilePath.present - idFilePath.get() == defaultHierarchy.baseDirectory.get() + File.separator + "prefix_coordinates_suffix" + idFilePath.get() == defaultHierarchy.baseDirectory.get().resolve("prefix_coordinates_suffix") } } \ No newline at end of file diff --git a/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy index f56a5a92c..62491ebc6 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy @@ -8,6 +8,8 @@ package edu.ie3.datamodel.io.sink import edu.ie3.datamodel.models.result.system.EmResult import edu.ie3.datamodel.models.result.system.FlexOptionsResult +import java.nio.file.Path + import static edu.ie3.util.quantities.PowerSystemUnits.KILOVOLTAMPERE import static tech.units.indriya.unit.Units.PERCENT import static edu.ie3.util.quantities.PowerSystemUnits.DEGREE_GEOM @@ -62,12 +64,12 @@ import javax.measure.quantity.Power class CsvFileSinkTest extends Specification implements TimeSeriesTestData { @Shared - String testBaseFolderPath = "test" + Path testBaseFolderPath = Path.of("test") // called automatically by spock (see http://spockframework.org/spock/docs/1.0/spock_primer.html - Fixture Methods) def cleanup() { // delete files after each test if they exist - if (new File(testBaseFolderPath).exists()) { + if (testBaseFolderPath.toFile().exists()) { FileIOUtils.deleteRecursively(testBaseFolderPath) } } @@ -174,27 +176,27 @@ class CsvFileSinkTest extends Specification implements TimeSeriesTestData { csvFileSink.shutdown() then: - new File(testBaseFolderPath).exists() - new File(testBaseFolderPath + File.separator + "wec_res.csv").exists() - new File(testBaseFolderPath + File.separator + "pv_res.csv").exists() - new File(testBaseFolderPath + File.separator + "evcs_res.csv").exists() - new File(testBaseFolderPath + File.separator + "em_res.csv").exists() - new File(testBaseFolderPath + File.separator + "flex_options_res.csv").exists() - new File(testBaseFolderPath + File.separator + "transformer_2_w_type_input.csv").exists() - new File(testBaseFolderPath + File.separator + "node_input.csv").exists() - new File(testBaseFolderPath + File.separator + "transformer_2_w_input.csv").exists() - new File(testBaseFolderPath + File.separator + "operator_input.csv").exists() - new File(testBaseFolderPath + File.separator + "cylindrical_storage_input.csv").exists() - new File(testBaseFolderPath + File.separator + "line_graphic_input.csv").exists() - new File(testBaseFolderPath + File.separator + "line_input.csv").exists() - new File(testBaseFolderPath + File.separator + "operator_input.csv").exists() - new File(testBaseFolderPath + File.separator + "node_graphic_input.csv").exists() - new File(testBaseFolderPath + File.separator + "thermal_bus_input.csv").exists() - new File(testBaseFolderPath + File.separator + "thermal_house_input.csv").exists() - new File(testBaseFolderPath + File.separator + "load_input.csv").exists() - new File(testBaseFolderPath + File.separator + "em_input.csv").exists() - - !new File(testBaseFolderPath + File.separator + "ev_res.csv").exists() + testBaseFolderPath.toFile().exists() + testBaseFolderPath.resolve("wec_res.csv").toFile().exists() + testBaseFolderPath.resolve("pv_res.csv").toFile().exists() + testBaseFolderPath.resolve("evcs_res.csv").toFile().exists() + testBaseFolderPath.resolve("em_res.csv").toFile().exists() + testBaseFolderPath.resolve("flex_options_res.csv").toFile().exists() + testBaseFolderPath.resolve("transformer_2_w_type_input.csv").toFile().exists() + testBaseFolderPath.resolve("node_input.csv").toFile().exists() + testBaseFolderPath.resolve("transformer_2_w_input.csv").toFile().exists() + testBaseFolderPath.resolve("operator_input.csv").toFile().exists() + testBaseFolderPath.resolve("cylindrical_storage_input.csv").toFile().exists() + testBaseFolderPath.resolve("line_graphic_input.csv").toFile().exists() + testBaseFolderPath.resolve("line_input.csv").toFile().exists() + testBaseFolderPath.resolve("operator_input.csv").toFile().exists() + testBaseFolderPath.resolve("node_graphic_input.csv").toFile().exists() + testBaseFolderPath.resolve("thermal_bus_input.csv").toFile().exists() + testBaseFolderPath.resolve("thermal_house_input.csv").toFile().exists() + testBaseFolderPath.resolve("load_input.csv").toFile().exists() + testBaseFolderPath.resolve("em_input.csv").toFile().exists() + + !testBaseFolderPath.resolve("ev_res.csv").toFile().exists() } def "A valid CsvFileSink should persist a time series correctly"() { @@ -216,8 +218,8 @@ class CsvFileSinkTest extends Specification implements TimeSeriesTestData { csvFileSink.shutdown() then: - new File(testBaseFolderPath).exists() - new File(testBaseFolderPath + File.separator + "its_c_a4bbcb77-b9d0-4b88-92be-b9a14a3e332b.csv").exists() + testBaseFolderPath.toFile().exists() + testBaseFolderPath.resolve("its_c_a4bbcb77-b9d0-4b88-92be-b9a14a3e332b.csv").toFile().exists() } def "A valid CsvFileSink persists a bunch of time series correctly"() { @@ -229,15 +231,15 @@ class CsvFileSinkTest extends Specification implements TimeSeriesTestData { csvFileSink.shutdown() then: - new File(testBaseFolderPath).exists() - new File(testBaseFolderPath + File.separator + "its_h_3c0ebc06-9bd7-44ea-a347-0c52d3dec854.csv").exists() - new File(testBaseFolderPath + File.separator + "its_p_b3d93b08-4985-41a6-b063-00f934a10b28.csv").exists() - new File(testBaseFolderPath + File.separator + "its_pq_7d085fc9-be29-4218-b768-00f885be066b.csv").exists() - new File(testBaseFolderPath + File.separator + "its_ph_56c20b88-c001-4225-8dac-cd13a75c6b48.csv").exists() - new File(testBaseFolderPath + File.separator + "its_pqh_83b577cc-06b1-47a1-bfff-ad648a00784b.csv").exists() - new File(testBaseFolderPath + File.separator + "its_c_a4bbcb77-b9d0-4b88-92be-b9a14a3e332b.csv").exists() - new File(testBaseFolderPath + File.separator + "lpts_g2_b56853fe-b800-4c18-b324-db1878b22a28.csv").exists() - new File(testBaseFolderPath + File.separator + "its_weather_4fcbdfcd-4ff0-46dd-b0df-f3af7ae3ed98.csv").exists() + testBaseFolderPath.toFile().exists() + testBaseFolderPath.resolve("its_h_3c0ebc06-9bd7-44ea-a347-0c52d3dec854.csv").toFile().exists() + testBaseFolderPath.resolve("its_p_b3d93b08-4985-41a6-b063-00f934a10b28.csv").toFile().exists() + testBaseFolderPath.resolve("its_pq_7d085fc9-be29-4218-b768-00f885be066b.csv").toFile().exists() + testBaseFolderPath.resolve("its_ph_56c20b88-c001-4225-8dac-cd13a75c6b48.csv").toFile().exists() + testBaseFolderPath.resolve("its_pqh_83b577cc-06b1-47a1-bfff-ad648a00784b.csv").toFile().exists() + testBaseFolderPath.resolve("its_c_a4bbcb77-b9d0-4b88-92be-b9a14a3e332b.csv").toFile().exists() + testBaseFolderPath.resolve("lpts_g2_b56853fe-b800-4c18-b324-db1878b22a28.csv").toFile().exists() + testBaseFolderPath.resolve("its_weather_4fcbdfcd-4ff0-46dd-b0df-f3af7ae3ed98.csv").toFile().exists() } def "A valid CsvFileSink is able to persist an InputEntity without persisting the nested elements"() { @@ -265,9 +267,9 @@ class CsvFileSinkTest extends Specification implements TimeSeriesTestData { csvFileSink.persistIgnoreNested(nestedInput) then: - new File(testBaseFolderPath).exists() - new File(testBaseFolderPath + File.separator + "pv_input.csv").exists() - !(new File(testBaseFolderPath + File.separator + "node_input.csv").exists()) + testBaseFolderPath.toFile().exists() + testBaseFolderPath.resolve("pv_input.csv").toFile().exists() + !testBaseFolderPath.resolve("node_input.csv").toFile().exists() cleanup: csvFileSink.shutdown() @@ -288,7 +290,7 @@ class CsvFileSinkTest extends Specification implements TimeSeriesTestData { csvFileSink.persist(individualEnergyPriceTimeSeries) then: - !(new File(testBaseFolderPath + File.separator + "its_a4bbcb77-b9d0-4b88-92be-b9a14a3e332b.csv").exists()) + !testBaseFolderPath.resolve("its_a4bbcb77-b9d0-4b88-92be-b9a14a3e332b.csv").toFile().exists() cleanup: csvFileSink.shutdown() @@ -307,16 +309,16 @@ class CsvFileSinkTest extends Specification implements TimeSeriesTestData { csvFileSink.persistJointGrid(SampleJointGrid.grid()) then: - new File(testBaseFolderPath + File.separator + "line_input.csv").exists() - new File(testBaseFolderPath + File.separator + "line_type_input.csv").exists() - new File(testBaseFolderPath + File.separator + "load_input.csv").exists() - new File(testBaseFolderPath + File.separator + "node_input.csv").exists() - new File(testBaseFolderPath + File.separator + "operator_input.csv").exists() - new File(testBaseFolderPath + File.separator + "pv_input.csv").exists() - new File(testBaseFolderPath + File.separator + "storage_input.csv").exists() - new File(testBaseFolderPath + File.separator + "storage_type_input.csv").exists() - new File(testBaseFolderPath + File.separator + "transformer_2_w_input.csv").exists() - new File(testBaseFolderPath + File.separator + "transformer_2_w_type_input.csv").exists() + testBaseFolderPath.resolve("line_input.csv").toFile().exists() + testBaseFolderPath.resolve("line_type_input.csv").toFile().exists() + testBaseFolderPath.resolve("load_input.csv").toFile().exists() + testBaseFolderPath.resolve( "node_input.csv").toFile().exists() + testBaseFolderPath.resolve("operator_input.csv").toFile().exists() + testBaseFolderPath.resolve("pv_input.csv").toFile().exists() + testBaseFolderPath.resolve("storage_input.csv").toFile().exists() + testBaseFolderPath.resolve("storage_type_input.csv").toFile().exists() + testBaseFolderPath.resolve("transformer_2_w_input.csv").toFile().exists() + testBaseFolderPath.resolve("transformer_2_w_type_input.csv").toFile().exists() cleanup: csvFileSink.shutdown() diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy index d540dccef..d42b393a2 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy @@ -16,6 +16,8 @@ import edu.ie3.test.common.GridTestData as gtd import spock.lang.Shared import spock.lang.Specification +import java.nio.file.Path + class EntitySourceTest extends Specification { private final class DummyEntitySource extends EntitySource { @@ -27,7 +29,7 @@ class EntitySourceTest extends Specification { @Shared String csvSep = "," @Shared - String testBaseFolderPath = "testBaseFolderPath" // does not have to exist for this test + Path testBaseFolderPath = Path.of("testBaseFolderPath") // does not have to exist for this test @Shared FileNamingStrategy fileNamingStrategy = new FileNamingStrategy() diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvDataSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvDataSourceTest.groovy index 38ae46f7f..e6c58dd97 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvDataSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvDataSourceTest.groovy @@ -13,6 +13,7 @@ import edu.ie3.test.common.SystemParticipantTestData as sptd import spock.lang.Shared import spock.lang.Specification +import java.nio.file.Path import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.LongAdder import java.util.function.Function @@ -28,7 +29,7 @@ class CsvDataSourceTest extends Specification { // methods in a public or protected method makes them available for testing private final class DummyCsvSource extends CsvDataSource { - DummyCsvSource(String csvSep, String folderPath, FileNamingStrategy fileNamingStrategy) { + DummyCsvSource(String csvSep, Path folderPath, FileNamingStrategy fileNamingStrategy) { super(csvSep, folderPath, fileNamingStrategy) } @@ -56,7 +57,7 @@ class CsvDataSourceTest extends Specification { @Shared String csvSep = "," @Shared - String testBaseFolderPath = "testBaseFolderPath" // does not have to exist for this test + Path testBaseFolderPath = Path.of("testBaseFolderPath") // does not have to exist for this test @Shared FileNamingStrategy fileNamingStrategy = new FileNamingStrategy() diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy index c8f03545f..f7d538b5e 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy @@ -20,6 +20,7 @@ import edu.ie3.test.common.GridTestData as rgtd import spock.lang.Shared import spock.lang.Specification +import java.nio.file.Path import java.util.stream.Collectors import java.util.stream.Stream diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTestDataMeta.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTestDataMeta.groovy index 284ca9e6a..fc0b2bf4d 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTestDataMeta.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTestDataMeta.groovy @@ -6,34 +6,51 @@ package edu.ie3.datamodel.io.source.csv import edu.ie3.datamodel.io.naming.FileNamingStrategy +import spock.lang.Shared -import java.nio.file.Paths +import java.nio.file.Path /** * Holds meta data for csv tests e.g. file and folder paths */ trait CsvTestDataMeta { - static String timeSeriesFolderPath = getResourceAbs("_timeseries") - static String graphicsFolderPath = getResourceAbs("_graphics") - static String typeFolderPath = getResourceAbs("_types") - static String participantsFolderPath = getResourceAbs("_participants") - static String resultEntitiesFolderPath = getResourceAbs("_results") - static String thermalFolderPath = getResourceAbs("_thermal") - static String coordinatesIconFolderPath = getResourceAbs("_coordinates/icon") - static String coordinatesCosmoFolderPath = getResourceAbs("_coordinates/cosmo") - static String weatherCosmoFolderPath = getResourceAbs("_weather/cosmo") - static String weatherIconFolderPath = getResourceAbs("_weather/icon") - static String jointGridFolderPath = getResourceAbs("_joint_grid") + @Shared + Path timeSeriesFolderPath = getResourceAbs("_timeseries") + @Shared + Path graphicsFolderPath = getResourceAbs("_graphics") + @Shared + Path typeFolderPath = getResourceAbs("_types") + @Shared + Path participantsFolderPath = getResourceAbs("_participants") + @Shared + Path resultEntitiesFolderPath = getResourceAbs("_results") + @Shared + Path thermalFolderPath = getResourceAbs("_thermal") + @Shared + Path coordinatesIconFolderPath = getResourceAbs("_coordinates/icon") + @Shared + Path coordinatesCosmoFolderPath = getResourceAbs("_coordinates/cosmo") + @Shared + Path weatherCosmoFolderPath = getResourceAbs("_weather/cosmo") + @Shared + Path weatherIconFolderPath = getResourceAbs("_weather/icon") + @Shared + Path jointGridFolderPath = getResourceAbs("_joint_grid") - static String gridDefaultFolderPath = getResourceAbs("_grid/default") - static String gridMalformedFolderPath = getResourceAbs("_grid/malformed") - static String gridEmptyFolderPath = getResourceAbs("_grid/empty") + @Shared + Path gridDefaultFolderPath = getResourceAbs("_grid/default") + @Shared + Path gridMalformedFolderPath = getResourceAbs("_grid/malformed") + @Shared + Path gridEmptyFolderPath = getResourceAbs("_grid/empty") - static String csvSep = "," - static FileNamingStrategy fileNamingStrategy = new FileNamingStrategy() + @Shared + String csvSep = "," + @Shared + FileNamingStrategy fileNamingStrategy = new FileNamingStrategy() - static String getResourceAbs(String directory) { - return Paths.get(CsvTestDataMeta.getResource(directory).toURI()).toString() + Path getResourceAbs(String directory) { + return Path.of(CsvTestDataMeta.getResource(directory).toURI()) } } \ No newline at end of file diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSourceIT.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSourceIT.groovy index 23f80df9f..2fa70a2f6 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSourceIT.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSourceIT.groovy @@ -11,6 +11,8 @@ import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme import spock.lang.Shared import spock.lang.Specification +import java.nio.file.Path + class CsvTimeSeriesMetaInformationSourceIT extends Specification implements CsvTestDataMeta { @Shared CsvTimeSeriesMetaInformationSource source @@ -22,13 +24,13 @@ class CsvTimeSeriesMetaInformationSourceIT extends Specification implements CsvT def "A CSV time series meta information source returns correct mapping of time series"() { given: def expectedTimeSeries = Set.of( - new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("2fcb3e53-b94a-4b96-bea4-c469e499f1a1"), ColumnScheme.ENERGY_PRICE, 'its_c_2fcb3e53-b94a-4b96-bea4-c469e499f1a1'), - new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("76c9d846-797c-4f07-b7ec-2245f679f5c7"), ColumnScheme.ACTIVE_POWER_AND_HEAT_DEMAND, 'its_ph_76c9d846-797c-4f07-b7ec-2245f679f5c7'), - new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("c8fe6547-fd85-4fdf-a169-e4da6ce5c3d0"), ColumnScheme.HEAT_DEMAND, 'its_h_c8fe6547-fd85-4fdf-a169-e4da6ce5c3d0'), - new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("9185b8c1-86ba-4a16-8dea-5ac898e8caa5"), ColumnScheme.ACTIVE_POWER, 'its_p_9185b8c1-86ba-4a16-8dea-5ac898e8caa5'), - new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c26"), ColumnScheme.APPARENT_POWER, 'its_pq_3fbfaa97-cff4-46d4-95ba-a95665e87c26'), - new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("46be1e57-e4ed-4ef7-95f1-b2b321cb2047"), ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND, 'its_pqh_46be1e57-e4ed-4ef7-95f1-b2b321cb2047'), - new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("1061af70-1c03-46e1-b960-940b956c429f"), ColumnScheme.APPARENT_POWER, 'its_pq_1061af70-1c03-46e1-b960-940b956c429f') + new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("2fcb3e53-b94a-4b96-bea4-c469e499f1a1"), ColumnScheme.ENERGY_PRICE, Path.of('its_c_2fcb3e53-b94a-4b96-bea4-c469e499f1a1')), + new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("76c9d846-797c-4f07-b7ec-2245f679f5c7"), ColumnScheme.ACTIVE_POWER_AND_HEAT_DEMAND, Path.of('its_ph_76c9d846-797c-4f07-b7ec-2245f679f5c7')), + new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("c8fe6547-fd85-4fdf-a169-e4da6ce5c3d0"), ColumnScheme.HEAT_DEMAND, Path.of('its_h_c8fe6547-fd85-4fdf-a169-e4da6ce5c3d0')), + new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("9185b8c1-86ba-4a16-8dea-5ac898e8caa5"), ColumnScheme.ACTIVE_POWER, Path.of('its_p_9185b8c1-86ba-4a16-8dea-5ac898e8caa5')), + new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c26"), ColumnScheme.APPARENT_POWER, Path.of('its_pq_3fbfaa97-cff4-46d4-95ba-a95665e87c26')), + new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("46be1e57-e4ed-4ef7-95f1-b2b321cb2047"), ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND, Path.of('its_pqh_46be1e57-e4ed-4ef7-95f1-b2b321cb2047')), + new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("1061af70-1c03-46e1-b960-940b956c429f"), ColumnScheme.APPARENT_POWER, Path.of('its_pq_1061af70-1c03-46e1-b960-940b956c429f')) ) when: diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceIT.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceIT.groovy index 81ea55403..de1857954 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceIT.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceIT.groovy @@ -5,6 +5,8 @@ */ package edu.ie3.datamodel.io.source.csv +import java.nio.file.Path + import static edu.ie3.test.common.TimeSeriesSourceTestData.* import edu.ie3.datamodel.exceptions.SourceException @@ -25,12 +27,12 @@ class CsvTimeSeriesSourceIT extends Specification implements CsvTestDataMeta { def setup() { factory = new TimeBasedSimpleValueFactory<>(HeatAndPValue) - source = new CsvTimeSeriesSource(";", timeSeriesFolderPath, new FileNamingStrategy(), UUID.fromString("76c9d846-797c-4f07-b7ec-2245f679f5c7"), "its_ph_76c9d846-797c-4f07-b7ec-2245f679f5c7", HeatAndPValue, factory) + source = new CsvTimeSeriesSource(";", timeSeriesFolderPath, new FileNamingStrategy(), UUID.fromString("76c9d846-797c-4f07-b7ec-2245f679f5c7"), Path.of("its_ph_76c9d846-797c-4f07-b7ec-2245f679f5c7"), HeatAndPValue, factory) } def "A csv time series source throw an Exception, if the file cannot be found"() { given: - def filePath = "file/not/found.csv" + def filePath = Path.of("file/not/found.csv") when: source.buildIndividualTimeSeries(UUID.fromString("fbc59b5b-9307-4fb4-a406-c1f08f26fee5"), filePath, { null }) @@ -43,7 +45,7 @@ class CsvTimeSeriesSourceIT extends Specification implements CsvTestDataMeta { def "A csv time series source is able to read in a proper file correctly"() { given: - def filePath = "its_ph_76c9d846-797c-4f07-b7ec-2245f679f5c7" + def filePath = Path.of("its_ph_76c9d846-797c-4f07-b7ec-2245f679f5c7") def tsUuid = UUID.fromString("76c9d846-797c-4f07-b7ec-2245f679f5c7") when: @@ -56,7 +58,7 @@ class CsvTimeSeriesSourceIT extends Specification implements CsvTestDataMeta { def "Construction a csv time series source with malicious parameters, leads to IllegalArgumentException"() { when: - new CsvTimeSeriesSource(";", timeSeriesFolderPath, new FileNamingStrategy(), UUID.fromString("fbc59b5b-9307-4fb4-a406-c1f08f26fee5"), "file/not/found", HeatAndPValue, factory) + new CsvTimeSeriesSource(";", timeSeriesFolderPath, new FileNamingStrategy(), UUID.fromString("fbc59b5b-9307-4fb4-a406-c1f08f26fee5"), Path.of("file/not/found"), HeatAndPValue, factory) then: def e = thrown(IllegalArgumentException) diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceTest.groovy index 6e2f7d667..a98481811 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceTest.groovy @@ -9,6 +9,8 @@ import edu.ie3.datamodel.io.csv.CsvIndividualTimeSeriesMetaInformation import edu.ie3.datamodel.io.naming.FileNamingStrategy import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme +import java.nio.file.Path + import static edu.ie3.datamodel.models.StandardUnits.ENERGY_PRICE import edu.ie3.datamodel.exceptions.SourceException @@ -26,7 +28,7 @@ class CsvTimeSeriesSourceTest extends Specification implements CsvTestDataMeta { def "The csv time series source is able to build time based values from simple data"() { given: def factory = new TimeBasedSimpleValueFactory(EnergyPriceValue) - def source = new CsvTimeSeriesSource(";", timeSeriesFolderPath, new FileNamingStrategy(), UUID.fromString("2fcb3e53-b94a-4b96-bea4-c469e499f1a1"), "its_c_2fcb3e53-b94a-4b96-bea4-c469e499f1a1", EnergyPriceValue, factory) + def source = new CsvTimeSeriesSource(";", timeSeriesFolderPath, new FileNamingStrategy(), UUID.fromString("2fcb3e53-b94a-4b96-bea4-c469e499f1a1"), Path.of("its_c_2fcb3e53-b94a-4b96-bea4-c469e499f1a1"), EnergyPriceValue, factory) def time = TimeUtil.withDefaults.toZonedDateTime("2019-01-01 00:00:00") def timeUtil = new TimeUtil(ZoneId.of("UTC"), Locale.GERMANY, "yyyy-MM-dd'T'HH:mm:ss[.S[S][S]]'Z'") def fieldToValue = [ @@ -50,7 +52,7 @@ class CsvTimeSeriesSourceTest extends Specification implements CsvTestDataMeta { def "The factory method in csv time series source refuses to build time series with unsupported column type"() { given: - def metaInformation = new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("8bc9120d-fb9b-4484-b4e3-0cdadf0feea9"), ColumnScheme.WEATHER, "its_weather_8bc9120d-fb9b-4484-b4e3-0cdadf0feea9") + def metaInformation = new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("8bc9120d-fb9b-4484-b4e3-0cdadf0feea9"), ColumnScheme.WEATHER, Path.of("its_weather_8bc9120d-fb9b-4484-b4e3-0cdadf0feea9")) when: CsvTimeSeriesSource.getSource(";", timeSeriesFolderPath, fileNamingStrategy, metaInformation) @@ -72,12 +74,12 @@ class CsvTimeSeriesSourceTest extends Specification implements CsvTestDataMeta { actual.timeSeries.entries[0].value.class == valueClass where: - uuid | columnScheme | path || amountOfEntries | valueClass - UUID.fromString("2fcb3e53-b94a-4b96-bea4-c469e499f1a1") | ColumnScheme.ENERGY_PRICE | "its_c_2fcb3e53-b94a-4b96-bea4-c469e499f1a1" || 2 | EnergyPriceValue - UUID.fromString("c8fe6547-fd85-4fdf-a169-e4da6ce5c3d0") | ColumnScheme.HEAT_DEMAND | "its_h_c8fe6547-fd85-4fdf-a169-e4da6ce5c3d0" || 2 | HeatDemandValue - UUID.fromString("9185b8c1-86ba-4a16-8dea-5ac898e8caa5") | ColumnScheme.ACTIVE_POWER | "its_p_9185b8c1-86ba-4a16-8dea-5ac898e8caa5" || 2 | PValue - UUID.fromString("76c9d846-797c-4f07-b7ec-2245f679f5c7") | ColumnScheme.ACTIVE_POWER_AND_HEAT_DEMAND | "its_ph_76c9d846-797c-4f07-b7ec-2245f679f5c7" || 2 | HeatAndPValue - UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c26") | ColumnScheme.APPARENT_POWER | "its_pq_3fbfaa97-cff4-46d4-95ba-a95665e87c26" || 2 | SValue - UUID.fromString("46be1e57-e4ed-4ef7-95f1-b2b321cb2047") | ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND | "its_pqh_46be1e57-e4ed-4ef7-95f1-b2b321cb2047" || 2 | HeatAndSValue + uuid | columnScheme | path || amountOfEntries | valueClass + UUID.fromString("2fcb3e53-b94a-4b96-bea4-c469e499f1a1") | ColumnScheme.ENERGY_PRICE | Path.of("its_c_2fcb3e53-b94a-4b96-bea4-c469e499f1a1") || 2 | EnergyPriceValue + UUID.fromString("c8fe6547-fd85-4fdf-a169-e4da6ce5c3d0") | ColumnScheme.HEAT_DEMAND | Path.of("its_h_c8fe6547-fd85-4fdf-a169-e4da6ce5c3d0") || 2 | HeatDemandValue + UUID.fromString("9185b8c1-86ba-4a16-8dea-5ac898e8caa5") | ColumnScheme.ACTIVE_POWER | Path.of("its_p_9185b8c1-86ba-4a16-8dea-5ac898e8caa5") || 2 | PValue + UUID.fromString("76c9d846-797c-4f07-b7ec-2245f679f5c7") | ColumnScheme.ACTIVE_POWER_AND_HEAT_DEMAND | Path.of("its_ph_76c9d846-797c-4f07-b7ec-2245f679f5c7") || 2 | HeatAndPValue + UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c26") | ColumnScheme.APPARENT_POWER | Path.of("its_pq_3fbfaa97-cff4-46d4-95ba-a95665e87c26") || 2 | SValue + UUID.fromString("46be1e57-e4ed-4ef7-95f1-b2b321cb2047") | ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND | Path.of("its_pqh_46be1e57-e4ed-4ef7-95f1-b2b321cb2047") || 2 | HeatAndSValue } } \ No newline at end of file diff --git a/src/test/groovy/edu/ie3/datamodel/io/csv/GridIoIT.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/GridIoIT.groovy similarity index 85% rename from src/test/groovy/edu/ie3/datamodel/io/csv/GridIoIT.groovy rename to src/test/groovy/edu/ie3/datamodel/io/source/csv/GridIoIT.groovy index 9b66b4578..4b8ebf9c3 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/csv/GridIoIT.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/GridIoIT.groovy @@ -3,15 +3,13 @@ * Institute of Energy Systems, Energy Efficiency and Energy Economics, * Research group Distribution grid planning and operation */ -package edu.ie3.datamodel.io.csv +package edu.ie3.datamodel.io.source.csv import edu.ie3.datamodel.exceptions.FileException import edu.ie3.datamodel.io.naming.DefaultDirectoryHierarchy import edu.ie3.datamodel.io.naming.EntityPersistenceNamingStrategy import edu.ie3.datamodel.io.naming.FileNamingStrategy import edu.ie3.datamodel.io.sink.CsvFileSink -import edu.ie3.datamodel.io.source.csv.CsvJointGridContainerSource -import edu.ie3.datamodel.io.source.csv.CsvTestDataMeta import edu.ie3.util.io.FileIOUtils import spock.lang.Shared import spock.lang.Specification @@ -37,10 +35,10 @@ class GridIoIT extends Specification implements CsvTestDataMeta { def setupSpec() { FileNamingStrategy hierarchicNamingStrategy = new FileNamingStrategy( new EntityPersistenceNamingStrategy(), - new DefaultDirectoryHierarchy("output", "vn_simona")) + new DefaultDirectoryHierarchy(Path.of("output"), "vn_simona")) tempDirectory = Files.createTempDirectory("GridIoIT") - sinkFlat = new CsvFileSink(tempDirectory.toAbsolutePath().toString()) - sinkHierarchic = new CsvFileSink(tempDirectory.toAbsolutePath().toString(), hierarchicNamingStrategy, ",") + sinkFlat = new CsvFileSink(tempDirectory.toAbsolutePath()) + sinkHierarchic = new CsvFileSink(tempDirectory.toAbsolutePath(), hierarchicNamingStrategy, ",") } def cleanupSpec() { @@ -61,7 +59,7 @@ class GridIoIT extends Specification implements CsvTestDataMeta { // write files from joint grid container in output directory sinkFlat.persistJointGrid(firstGridContainer) // create second grid container from output folder - def secondGridContainer = CsvJointGridContainerSource.read(gridName, separator, tempDirectory.toAbsolutePath().toString(), false) + def secondGridContainer = CsvJointGridContainerSource.read(gridName, separator, tempDirectory.toAbsolutePath(), false) then: // compare input and output joint grid container @@ -77,7 +75,7 @@ class GridIoIT extends Specification implements CsvTestDataMeta { when: sinkHierarchic.persistJointGrid(firstGridContainer) - def secondGridContainer = CsvJointGridContainerSource.read(gridName, separator, tempDirectory.toAbsolutePath().toString(), true) + def secondGridContainer = CsvJointGridContainerSource.read(gridName, separator, tempDirectory.toAbsolutePath(), true) then: // compare input and output joint grid container diff --git a/src/test/groovy/edu/ie3/datamodel/utils/FileUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/FileUtilsTest.groovy new file mode 100644 index 000000000..36741b050 --- /dev/null +++ b/src/test/groovy/edu/ie3/datamodel/utils/FileUtilsTest.groovy @@ -0,0 +1,65 @@ +/* + * © 2023. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ +package edu.ie3.datamodel.utils + +import edu.ie3.datamodel.io.IoUtil +import spock.lang.Shared +import spock.lang.Specification + +import java.nio.file.Path + +class FileUtilsTest extends Specification { + @Shared + String fileName + + @Shared + Path directory + + def setupSpec() { + fileName = "node_input.csv" + directory = Path.of("test", "grid") + } + + def "A file definition is et up correctly, if an empty path is given" () { + when: + def file = FileUtils.of("name", path) + + then: + file == expectedPath + + where: + path || expectedPath + IoUtil.pathOption("") || Path.of("name") + } + + def "A file definition of a csv file is set up correctly, if the directory path has corrupt file separator" () { + when: + def file = FileUtils.ofCsv(fileName, manipulatedDirectory) + + then: + file.with { + assert it.fileName == Path.of(this.fileName) + assert it == this.directory.resolve(this.fileName) + } + + where: + manipulatedDirectory || expected + Path.of(this.directory.toString(), "/") || this.directory + Path.of(this.directory.toString().replaceAll("[\\\\/]", File.separator == "/" ? "\\\\" : "/")) || this.directory + } + + def "A file definition of a csv file is set up correctly, if the directory path is null" () { + when: + def file = FileUtils.ofCsv(fileName, null) + + then: + file.with { + assert it.fileName == Path.of(this.fileName) + assert it.relativize(it.fileName) == Path.of("") + assert it.parent == null + } + } +}