diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesImport.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesImport.java index 4f9fd5a7222..2d8c2c06e36 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesImport.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesImport.java @@ -189,6 +189,11 @@ public boolean exists(String suffix, String ext) throws IOException { return ds.exists(suffix, ext) && filter.test(DataSourceUtil.getFileName(getBaseName(), suffix, ext)); } + @Override + public boolean isDataExtension(String ext) { + return ds.isDataExtension(ext); + } + @Override public boolean exists(String fileName) throws IOException { return ds.exists(fileName) && filter.test(fileName); diff --git a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesOnDataSource.java b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesOnDataSource.java index 15ac210058a..4654c1a7490 100644 --- a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesOnDataSource.java +++ b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesOnDataSource.java @@ -24,6 +24,8 @@ * @author Luma ZamarreƱo {@literal } */ public class CgmesOnDataSource { + private static final String EXTENSIONS = "xml"; + public CgmesOnDataSource(ReadOnlyDataSource ds) { this.dataSource = ds; } @@ -32,29 +34,55 @@ public ReadOnlyDataSource dataSource() { return dataSource; } + private boolean checkIfMainFileNotWithCgmesData(boolean isCim14) { + if (dataSource.getDataExtension() == null || dataSource.getDataExtension().isEmpty()) { + return false; + } else if (EXTENSIONS.equals(dataSource.getDataExtension())) { + try (InputStream is = dataSource.newInputStream(null, EXTENSIONS)) { + return isCim14 ? !existsNamespacesCim14(NamespaceReader.namespaces(is)) : !existsNamespaces(NamespaceReader.namespaces(is)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + return true; + } + public boolean exists() { + // Check that the main file is a CGMES file + if (checkIfMainFileNotWithCgmesData(false)) { + return false; + } // check that RDF and CIM16 are defined as namespaces in the data source - Set foundNamespaces = namespaces(); - if (!foundNamespaces.contains(RDF_NAMESPACE)) { + return existsNamespaces(namespaces()); + } + + private boolean existsNamespaces(Set namespaces) { + if (!namespaces.contains(RDF_NAMESPACE)) { return false; } // FIXME(Luma) This is legacy behaviour, we do not consider CIM14 valid in this check // But I think we do not need to support 14 separately? - return foundNamespaces.contains(CIM_16_NAMESPACE) || foundNamespaces.contains(CIM_100_NAMESPACE); + return namespaces.contains(CIM_16_NAMESPACE) || namespaces.contains(CIM_100_NAMESPACE); } public boolean existsCim14() { + // Check that the main file is a CGMES file + if (checkIfMainFileNotWithCgmesData(true)) { + return false; + } // check that RDF and CIM16 are defined as namespaces in the data source - Set foundNamespaces = namespaces(); - if (!foundNamespaces.contains(RDF_NAMESPACE)) { + return existsNamespacesCim14(namespaces()); + } + + private boolean existsNamespacesCim14(Set namespaces) { + if (!namespaces.contains(RDF_NAMESPACE)) { return false; } // FIXME(Luma) This is legacy behaviour, we do not consider CIM14 valid in this check // But I think we do not need to support 14 separately? - if (!foundNamespaces.contains(CIM_14_NAMESPACE)) { + if (!namespaces.contains(CIM_14_NAMESPACE)) { return false; } - return names().stream().anyMatch(CgmesSubset.EQUIPMENT::isValidName); } diff --git a/commons/src/main/java/com/powsybl/commons/datasource/AbstractArchiveDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/AbstractArchiveDataSource.java index a1439a91845..6871f2b1149 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/AbstractArchiveDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/AbstractArchiveDataSource.java @@ -17,8 +17,8 @@ public abstract class AbstractArchiveDataSource extends AbstractFileSystemDataSo private final String archiveFileName; final ArchiveFormat archiveFormat; - AbstractArchiveDataSource(Path directory, String archiveFileName, String baseName, CompressionFormat compressionFormat, ArchiveFormat archiveFormat, DataSourceObserver observer) { - super(directory, baseName, compressionFormat, observer); + AbstractArchiveDataSource(Path directory, String archiveFileName, String baseName, String dataExtension, CompressionFormat compressionFormat, ArchiveFormat archiveFormat, DataSourceObserver observer) { + super(directory, baseName, dataExtension, compressionFormat, observer); this.archiveFileName = archiveFileName; this.archiveFormat = archiveFormat; } diff --git a/commons/src/main/java/com/powsybl/commons/datasource/AbstractFileSystemDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/AbstractFileSystemDataSource.java index 3b208ae0b09..335b0295b53 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/AbstractFileSystemDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/AbstractFileSystemDataSource.java @@ -17,6 +17,7 @@ abstract class AbstractFileSystemDataSource implements DataSource { final Path directory; final String baseName; + final String dataExtension; final CompressionFormat compressionFormat; final DataSourceObserver observer; @@ -27,14 +28,21 @@ abstract class AbstractFileSystemDataSource implements DataSource { * @param observer Data source observer */ AbstractFileSystemDataSource(Path directory, String baseName, + String dataExtension, CompressionFormat compressionFormat, DataSourceObserver observer) { this.directory = Objects.requireNonNull(directory); this.baseName = Objects.requireNonNull(baseName); + this.dataExtension = dataExtension; this.compressionFormat = compressionFormat; this.observer = observer; } + @Override + public boolean isDataExtension(String ext) { + return dataExtension == null || dataExtension.isEmpty() || dataExtension.equals(ext); + } + public Path getDirectory() { return this.directory; } @@ -44,10 +52,19 @@ public String getBaseName() { return baseName; } + @Override + public String getDataExtension() { + return dataExtension; + } + public CompressionFormat getCompressionFormat() { return compressionFormat; } + String getCompressionExtension() { + return compressionFormat == null ? "" : "." + compressionFormat.getExtension(); + } + public DataSourceObserver getObserver() { return observer; } diff --git a/commons/src/main/java/com/powsybl/commons/datasource/Bzip2DirectoryDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/Bzip2DirectoryDataSource.java index f2a4ae78ad4..145b69d82ce 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/Bzip2DirectoryDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/Bzip2DirectoryDataSource.java @@ -18,12 +18,8 @@ */ public class Bzip2DirectoryDataSource extends DirectoryDataSource { - public Bzip2DirectoryDataSource(Path directory, String baseName, DataSourceObserver observer) { - super(directory, baseName, CompressionFormat.BZIP2, observer); - } - - public Bzip2DirectoryDataSource(Path directory, String baseName) { - super(directory, baseName, CompressionFormat.BZIP2, null); + public Bzip2DirectoryDataSource(Path directory, String baseName, String dataExtension, DataSourceObserver observer) { + super(directory, baseName, dataExtension, CompressionFormat.BZIP2, observer); } @Override diff --git a/commons/src/main/java/com/powsybl/commons/datasource/DataSourceBuilder.java b/commons/src/main/java/com/powsybl/commons/datasource/DataSourceBuilder.java new file mode 100644 index 00000000000..9736c8d3cbe --- /dev/null +++ b/commons/src/main/java/com/powsybl/commons/datasource/DataSourceBuilder.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.commons.datasource; + +import com.powsybl.commons.PowsyblException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * @author Nicolas Rol {@literal } + */ +class DataSourceBuilder { + private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceBuilder.class); + private Path directory; + private String baseName; + private String archiveFileName; + private CompressionFormat compressionFormat; + private ArchiveFormat archiveFormat; + private String dataExtension = ""; + private DataSourceObserver observer; + + DataSourceBuilder withDirectory(Path directory) { + this.directory = directory; + return this; + } + + DataSourceBuilder withBaseName(String baseName) { + this.baseName = baseName; + return this; + } + + DataSourceBuilder withArchiveFileName(String archiveFileName) { + this.archiveFileName = archiveFileName; + return this; + } + + DataSourceBuilder withCompressionFormat(CompressionFormat compressionFormat) { + this.compressionFormat = compressionFormat; + return this; + } + + DataSourceBuilder withArchiveFormat(ArchiveFormat archiveFormat) { + this.archiveFormat = archiveFormat; + return this; + } + + DataSourceBuilder withDataExtension(String dataExtension) { + this.dataExtension = dataExtension; + return this; + } + + DataSourceBuilder withObserver(DataSourceObserver observer) { + this.observer = observer; + return this; + } + + DataSource build() { + // Check the mandatory parameters + buildChecks(); + + // Create the datasource + if (compressionFormat == CompressionFormat.ZIP || archiveFormat == ArchiveFormat.ZIP) { + return buildZip(); + } else if (compressionFormat == null) { + return new DirectoryDataSource(directory, baseName, dataExtension, observer); + } else { + return switch (compressionFormat) { + case BZIP2 -> new Bzip2DirectoryDataSource(directory, baseName, dataExtension, observer); + case GZIP -> new GzDirectoryDataSource(directory, baseName, dataExtension, observer); + case XZ -> new XZDirectoryDataSource(directory, baseName, dataExtension, observer); + case ZSTD -> new ZstdDirectoryDataSource(directory, baseName, dataExtension, observer); + default -> { + LOGGER.warn("Unsupported compression format {}", compressionFormat); + yield new DirectoryDataSource(directory, baseName, dataExtension, observer); + } + }; + } + } + + private void buildChecks() { + if (directory == null) { + throw new PowsyblException("Datasource directory cannot be null"); + } + if (!Files.isDirectory(directory)) { + throw new PowsyblException("Datasource directory has to be a directory"); + } + if (baseName == null) { + throw new PowsyblException("Datasource baseName cannot be null"); + } + } + + private DataSource buildZip() { + if (compressionFormat != null && archiveFormat != null && !(compressionFormat == CompressionFormat.ZIP && archiveFormat == ArchiveFormat.ZIP)) { + throw new PowsyblException(String.format("Incoherence between compression format %s and archive format %s", compressionFormat, archiveFormat)); + } + return archiveFileName == null ? + new ZipArchiveDataSource(directory, baseName, dataExtension, observer) : + new ZipArchiveDataSource(directory, archiveFileName, baseName, dataExtension, observer); + } +} diff --git a/commons/src/main/java/com/powsybl/commons/datasource/DataSourceUtil.java b/commons/src/main/java/com/powsybl/commons/datasource/DataSourceUtil.java index 23a5cc25011..2a4f7aa7939 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/DataSourceUtil.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/DataSourceUtil.java @@ -40,45 +40,44 @@ static String getBaseName(String fileName) { } static DataSource createDataSource(Path directory, String basename, CompressionFormat compressionExtension, DataSourceObserver observer) { + return createDataSource(directory, basename, null, compressionExtension, observer); + } + + static DataSource createDataSource(Path directory, String basename, String dataExtension, CompressionFormat compressionFormat, DataSourceObserver observer) { Objects.requireNonNull(directory); Objects.requireNonNull(basename); - if (compressionExtension == null) { - return new DirectoryDataSource(directory, basename, observer); - } else { - switch (compressionExtension) { - case BZIP2: - return new Bzip2DirectoryDataSource(directory, basename, observer); - case GZIP: - return new GzDirectoryDataSource(directory, basename, observer); - case XZ: - return new XZDirectoryDataSource(directory, basename, observer); - case ZIP: - return new ZipArchiveDataSource(directory, basename, observer); - case ZSTD: - return new ZstdDirectoryDataSource(directory, basename, observer); - default: - throw new IllegalStateException("Unexpected CompressionFormat value: " + compressionExtension); - } + DataSourceBuilder dataSourceBuilder = new DataSourceBuilder() + .withDirectory(directory) + .withBaseName(basename) + .withDataExtension(dataExtension) + .withCompressionFormat(compressionFormat) + .withObserver(observer); + + // If a zip compression is asked + if (compressionFormat == CompressionFormat.ZIP) { + dataSourceBuilder.withArchiveFormat(ArchiveFormat.ZIP); } + + return dataSourceBuilder.build(); } static DataSource createDataSource(Path directory, String fileNameOrBaseName, DataSourceObserver observer) { Objects.requireNonNull(directory); Objects.requireNonNull(fileNameOrBaseName); - if (fileNameOrBaseName.endsWith(".zst")) { - return new ZstdDirectoryDataSource(directory, getBaseName(fileNameOrBaseName.substring(0, fileNameOrBaseName.length() - 4)), observer); - } else if (fileNameOrBaseName.endsWith(".zip")) { - return new ZipArchiveDataSource(directory, fileNameOrBaseName, getBaseName(fileNameOrBaseName.substring(0, fileNameOrBaseName.length() - 4)), observer); - } else if (fileNameOrBaseName.endsWith(".xz")) { - return new XZDirectoryDataSource(directory, getBaseName(fileNameOrBaseName.substring(0, fileNameOrBaseName.length() - 3)), observer); - } else if (fileNameOrBaseName.endsWith(".gz")) { - return new GzDirectoryDataSource(directory, getBaseName(fileNameOrBaseName.substring(0, fileNameOrBaseName.length() - 3)), observer); - } else if (fileNameOrBaseName.endsWith(".bz2")) { - return new Bzip2DirectoryDataSource(directory, getBaseName(fileNameOrBaseName.substring(0, fileNameOrBaseName.length() - 4)), observer); - } else { - return new DirectoryDataSource(directory, getBaseName(fileNameOrBaseName), observer); - } + // Get the file information + FileInformation fileInformation = new FileInformation(fileNameOrBaseName); + + DataSourceBuilder dataSourceBuilder = new DataSourceBuilder() + .withDirectory(directory) + .withArchiveFileName(fileNameOrBaseName) + .withBaseName(fileInformation.getBaseName()) + .withDataExtension(fileInformation.getDataExtension()) + .withCompressionFormat(fileInformation.getCompressionFormat()) + .withArchiveFormat(fileInformation.getArchiveFormat()) + .withObserver(observer); + + return dataSourceBuilder.build(); } } diff --git a/commons/src/main/java/com/powsybl/commons/datasource/DirectoryDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/DirectoryDataSource.java index 24fca2af1d4..3a92a4b84ff 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/DirectoryDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/DirectoryDataSource.java @@ -25,22 +25,25 @@ public class DirectoryDataSource extends AbstractFileSystemDataSource { public DirectoryDataSource(Path directory, String baseName) { - this(directory, baseName, null, null); + this(directory, baseName, null, null, null); } public DirectoryDataSource(Path directory, String baseName, DataSourceObserver observer) { - this(directory, baseName, null, observer); + this(directory, baseName, null, null, observer); + } + + public DirectoryDataSource(Path directory, String baseName, + String dataExtension, + DataSourceObserver observer) { + this(directory, baseName, dataExtension, null, observer); } DirectoryDataSource(Path directory, String baseName, + String dataExtension, CompressionFormat compressionFormat, DataSourceObserver observer) { - super(directory, baseName, compressionFormat, observer); - } - - protected String getCompressionExt() { - return compressionFormat == null ? "" : "." + compressionFormat.getExtension(); + super(directory, baseName, dataExtension, compressionFormat, observer); } /** @@ -59,7 +62,8 @@ protected OutputStream getCompressedOutputStream(OutputStream os) throws IOExcep private Path getPath(String fileName) { Objects.requireNonNull(fileName); - return directory.resolve(fileName + getCompressionExt()); + FileInformation fileInformation = new FileInformation(fileName, false); + return directory.resolve(fileInformation.getCompressionFormat() == null ? fileName + getCompressionExtension() : fileName); } @Override @@ -74,6 +78,11 @@ public OutputStream newOutputStream(String fileName, boolean append) throws IOEx return observer != null ? new ObservableOutputStream(os, path.toString(), observer) : os; } + /** + * Check if a file exists in the datasource. + * @param fileName Name of the file (excluding the compression extension) + * @return true if the file exists, else false + */ @Override public boolean exists(String fileName) throws IOException { Path path = getPath(fileName); @@ -104,7 +113,7 @@ public Set listNames(String regex) throws IOException { .map(Path::toString) .filter(name -> name.startsWith(baseName)) // Return names after removing the compression extension - .map(name -> name.replace(getCompressionExt(), "")) + .map(name -> name.replace(getCompressionExtension(), "")) .filter(s -> p.matcher(s).matches()) .collect(Collectors.toSet()); } diff --git a/commons/src/main/java/com/powsybl/commons/datasource/FileInformation.java b/commons/src/main/java/com/powsybl/commons/datasource/FileInformation.java new file mode 100644 index 00000000000..2cb17ece723 --- /dev/null +++ b/commons/src/main/java/com/powsybl/commons/datasource/FileInformation.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.commons.datasource; + +import com.powsybl.commons.PowsyblException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; + +/** + * @author Nicolas Rol {@literal } + */ +public class FileInformation { + + private static final Logger LOGGER = LoggerFactory.getLogger(FileInformation.class); + private String baseName; + private CompressionFormat compressionFormat; + private ArchiveFormat archiveFormat; + private String dataExtension; + + FileInformation(String fileName) { + Objects.requireNonNull(fileName); + computeInformation(fileName, true); + } + + FileInformation(String fileName, boolean dataSourceInitialization) { + Objects.requireNonNull(fileName); + computeInformation(fileName, dataSourceInitialization); + } + + private void computeInformation(String fileName, boolean dataSourceInitialization) { + // Check if filename is empty or only a dot + if (fileName.isEmpty() || fileName.equals(".")) { + throw new PowsyblException("File name cannot be empty nor just a dot"); + } + + // Last dot index + int currentDotIndex = fileName.lastIndexOf('.'); + + // Compression extension + compressionFormat = switch (fileName.substring(currentDotIndex + 1)) { + case "bz2" -> CompressionFormat.BZIP2; + case "gz" -> CompressionFormat.GZIP; + case "xz" -> CompressionFormat.XZ; + case "zip" -> CompressionFormat.ZIP; + case "zst" -> CompressionFormat.ZSTD; + default -> null; + }; + + // File name without the compression extension + String fileNameWithoutCompressionExtension = compressionFormat == null ? fileName : fileName.substring(0, currentDotIndex); + + // Archive extension + String fileNameWithoutCompressionNorArchive; + archiveFormat = compressionFormat == CompressionFormat.ZIP ? ArchiveFormat.ZIP : null; + fileNameWithoutCompressionNorArchive = fileNameWithoutCompressionExtension; + + // Last dot index + currentDotIndex = fileNameWithoutCompressionNorArchive.lastIndexOf('.'); + + /* Data datasource extension + * Four cases are possible: + * - case 1 ("dummy"): currentDotIndex < 0 -> no source format is given + * - case 2 (".dummy"): currentDotIndex == 0 -> considered as a hidden file so no source format is given + * - case 3 ("dummy.foo"): ".foo" is the source format + */ + dataExtension = currentDotIndex < 1 ? "" : fileNameWithoutCompressionNorArchive.substring(currentDotIndex + 1); + logDataExtension(fileName, dataExtension, dataSourceInitialization); + + // Base name + baseName = dataExtension.isEmpty() ? + fileNameWithoutCompressionNorArchive : + fileNameWithoutCompressionNorArchive.substring(0, currentDotIndex); + if (baseName.isEmpty()) { + LOGGER.warn("Base name is empty in file {}", fileName); + } + } + + private void logDataExtension(String fileName, String dataExtension, boolean dataSourceInitialization) { + if (dataSourceInitialization && dataExtension.isEmpty()) { + LOGGER.warn("Data extension is empty in file {}", fileName); + } + } + + public String getBaseName() { + return baseName; + } + + public CompressionFormat getCompressionFormat() { + return compressionFormat; + } + + public ArchiveFormat getArchiveFormat() { + return archiveFormat; + } + + public String getDataExtension() { + return dataExtension; + } + + public String toString() { + return "FileInformation[" + + "baseName=" + baseName + ", " + + "dataExtension=" + dataExtension + ", " + + "archiveFormat=" + archiveFormat + ", " + + "compressionFormat=" + compressionFormat + + "]"; + } +} diff --git a/commons/src/main/java/com/powsybl/commons/datasource/GenericReadOnlyDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/GenericReadOnlyDataSource.java index c5643233a2b..51a576a21a7 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/GenericReadOnlyDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/GenericReadOnlyDataSource.java @@ -21,15 +21,15 @@ public class GenericReadOnlyDataSource implements ReadOnlyDataSource { private final ReadOnlyDataSource[] dataSources; - public GenericReadOnlyDataSource(Path directory, String baseName, DataSourceObserver observer) { + public GenericReadOnlyDataSource(Path directory, String baseName, String dataExtension, DataSourceObserver observer) { dataSources = new DataSource[] { - new DirectoryDataSource(directory, baseName, observer), - new ZstdDirectoryDataSource(directory, baseName, observer), + new DirectoryDataSource(directory, baseName, dataExtension, observer), + new ZstdDirectoryDataSource(directory, baseName, dataExtension, observer), new ZipArchiveDataSource(directory), - new ZipArchiveDataSource(directory, baseName + ".zip", baseName, observer), - new XZDirectoryDataSource(directory, baseName, observer), - new GzDirectoryDataSource(directory, baseName, observer), - new Bzip2DirectoryDataSource(directory, baseName, observer) + new ZipArchiveDataSource(directory, baseName, dataExtension, observer), + new XZDirectoryDataSource(directory, baseName, dataExtension, observer), + new GzDirectoryDataSource(directory, baseName, dataExtension, observer), + new Bzip2DirectoryDataSource(directory, baseName, dataExtension, observer) }; } @@ -37,18 +37,27 @@ public GenericReadOnlyDataSource(Path directory, String baseName, DataSourceObse * The data source contains all files inside the given directory. */ public GenericReadOnlyDataSource(Path directory) { - this(directory, ""); + this(directory, "", null); } public GenericReadOnlyDataSource(Path directory, String baseName) { this(directory, baseName, null); } + public GenericReadOnlyDataSource(Path directory, String baseName, String dataExtension) { + this(directory, baseName, dataExtension, null); + } + @Override public String getBaseName() { return dataSources[0].getBaseName(); } + @Override + public String getDataExtension() { + return dataSources[0].getDataExtension(); + } + @Override public boolean exists(String suffix, String ext) throws IOException { for (ReadOnlyDataSource dataSource : dataSources) { @@ -59,6 +68,16 @@ public boolean exists(String suffix, String ext) throws IOException { return false; } + @Override + public boolean isDataExtension(String ext) { + for (ReadOnlyDataSource dataSource : dataSources) { + if (dataSource.isDataExtension(ext)) { + return true; + } + } + return false; + } + @Override public boolean exists(String fileName) throws IOException { for (ReadOnlyDataSource dataSource : dataSources) { diff --git a/commons/src/main/java/com/powsybl/commons/datasource/GzDirectoryDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/GzDirectoryDataSource.java index 6381c570d3b..5b6609be310 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/GzDirectoryDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/GzDirectoryDataSource.java @@ -19,12 +19,8 @@ */ public class GzDirectoryDataSource extends DirectoryDataSource { - public GzDirectoryDataSource(Path directory, String baseName, DataSourceObserver observer) { - super(directory, baseName, CompressionFormat.GZIP, observer); - } - - public GzDirectoryDataSource(Path directory, String baseName) { - super(directory, baseName, CompressionFormat.GZIP, null); + public GzDirectoryDataSource(Path directory, String baseName, String dataExtension, DataSourceObserver observer) { + super(directory, baseName, dataExtension, CompressionFormat.GZIP, observer); } @Override diff --git a/commons/src/main/java/com/powsybl/commons/datasource/MultipleReadOnlyDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/MultipleReadOnlyDataSource.java index e09592615c4..8db6959c269 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/MultipleReadOnlyDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/MultipleReadOnlyDataSource.java @@ -51,6 +51,11 @@ public boolean exists(String suffix, String ext) throws IOException { }); } + @Override + public boolean isDataExtension(String ext) { + return dataSources.stream().anyMatch(dataSource -> dataSource.isDataExtension(ext)); + } + @Override public boolean exists(String fileName) throws IOException { return dataSources.stream().anyMatch(dataSource -> { diff --git a/commons/src/main/java/com/powsybl/commons/datasource/ReadOnlyDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/ReadOnlyDataSource.java index c4ee48e42ac..91f29c53f2a 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/ReadOnlyDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/ReadOnlyDataSource.java @@ -18,6 +18,10 @@ public interface ReadOnlyDataSource { String getBaseName(); + default String getDataExtension() { + return null; + } + /** * Check if a file exists in the datasource. The file name will be constructed as: * {@code .}

@@ -29,11 +33,18 @@ public interface ReadOnlyDataSource { /** * Check if a file exists in the datasource. - * @param fileName Name of the file (excluding the compression extension) + * @param fileName Name of the file * @return true if the file exists, else false */ boolean exists(String fileName) throws IOException; + /** + * Check if the provided extension is a data extension for the datasource + * @param ext Extension to compare to the data extension of the datasource + * @return true if the datasource data extension is null, empty or equal to {@code ext}, else false + */ + boolean isDataExtension(String ext); + InputStream newInputStream(String suffix, String ext) throws IOException; InputStream newInputStream(String fileName) throws IOException; diff --git a/commons/src/main/java/com/powsybl/commons/datasource/ReadOnlyMemDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/ReadOnlyMemDataSource.java index 0d2c8a2b115..b776622de69 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/ReadOnlyMemDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/ReadOnlyMemDataSource.java @@ -67,6 +67,16 @@ public boolean exists(String suffix, String ext) throws IOException { return exists(DataSourceUtil.getFileName(baseName, suffix, ext)); } + /** + * {@inheritDoc} + * As a ReadOnlyMemDataSource does not have a main extension, this method always returns true + * @return true + */ + @Override + public boolean isDataExtension(String ext) { + return true; + } + @Override public boolean exists(String fileName) throws IOException { Objects.requireNonNull(fileName); diff --git a/commons/src/main/java/com/powsybl/commons/datasource/ResourceDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/ResourceDataSource.java index b3ec498b802..ac69880802e 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/ResourceDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/ResourceDataSource.java @@ -22,14 +22,21 @@ public class ResourceDataSource implements ReadOnlyDataSource { private final String baseName; + private final String dataExtension; + private final List resourceSets; public ResourceDataSource(String baseName, ResourceSet... resourceSets) { - this(baseName, Arrays.asList(resourceSets)); + this(baseName, null, Arrays.asList(resourceSets)); } public ResourceDataSource(String baseName, List resourceSets) { + this(baseName, null, resourceSets); + } + + public ResourceDataSource(String baseName, String dataExtension, List resourceSets) { this.baseName = Objects.requireNonNull(baseName); + this.dataExtension = dataExtension; this.resourceSets = Objects.requireNonNull(resourceSets); } @@ -38,11 +45,21 @@ public String getBaseName() { return baseName; } + @Override + public String getDataExtension() { + return dataExtension; + } + @Override public boolean exists(String suffix, String ext) { return exists(DataSourceUtil.getFileName(baseName, suffix, ext)); } + @Override + public boolean isDataExtension(String ext) { + return dataExtension == null || dataExtension.isEmpty() || dataExtension.equals(ext); + } + @Override public boolean exists(String fileName) { Objects.requireNonNull(fileName); diff --git a/commons/src/main/java/com/powsybl/commons/datasource/XZDirectoryDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/XZDirectoryDataSource.java index a5eb4014e79..74a8b68e62e 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/XZDirectoryDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/XZDirectoryDataSource.java @@ -18,12 +18,8 @@ */ public class XZDirectoryDataSource extends DirectoryDataSource { - public XZDirectoryDataSource(Path directory, String baseName, DataSourceObserver observer) { - super(directory, baseName, CompressionFormat.XZ, observer); - } - - public XZDirectoryDataSource(Path directory, String baseName) { - super(directory, baseName, CompressionFormat.XZ, null); + public XZDirectoryDataSource(Path directory, String baseName, String dataExtension, DataSourceObserver observer) { + super(directory, baseName, dataExtension, CompressionFormat.XZ, observer); } @Override diff --git a/commons/src/main/java/com/powsybl/commons/datasource/ZipArchiveDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/ZipArchiveDataSource.java index 7cdff8ab992..b6c90f26c19 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/ZipArchiveDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/ZipArchiveDataSource.java @@ -33,20 +33,28 @@ */ public class ZipArchiveDataSource extends AbstractArchiveDataSource { - public ZipArchiveDataSource(Path directory, String zipFileName, String baseName, DataSourceObserver observer) { - super(directory, zipFileName, baseName, CompressionFormat.ZIP, ArchiveFormat.ZIP, observer); + public ZipArchiveDataSource(Path directory, String zipFileName, String baseName, String dataExtension, DataSourceObserver observer) { + super(directory, zipFileName, baseName, dataExtension, CompressionFormat.ZIP, ArchiveFormat.ZIP, observer); } - public ZipArchiveDataSource(Path directory, String zipFileName, String baseName) { - this(directory, zipFileName, baseName, null); + public ZipArchiveDataSource(Path directory, String zipFileName, String baseName, String dataExtension) { + this(directory, zipFileName, baseName, dataExtension, null); } - public ZipArchiveDataSource(Path directory, String baseName) { - this(directory, baseName + ".zip", baseName, null); + public ZipArchiveDataSource(Path directory, String baseName, String dataExtension, DataSourceObserver observer) { + this(directory, baseName + ((dataExtension == null || dataExtension.isEmpty()) ? "" : "." + dataExtension) + ".zip", baseName, dataExtension, observer); + } + + public ZipArchiveDataSource(Path directory, String baseName, String dataExtension) { + this(directory, baseName + ((dataExtension == null || dataExtension.isEmpty()) ? "" : "." + dataExtension) + ".zip", baseName, dataExtension, null); } public ZipArchiveDataSource(Path directory, String baseName, DataSourceObserver observer) { - this(directory, baseName + ".zip", baseName, observer); + this(directory, baseName + ".zip", baseName, null, observer); + } + + public ZipArchiveDataSource(Path directory, String baseName) { + this(directory, baseName + ".zip", baseName, null, null); } public ZipArchiveDataSource(Path zipFile) { diff --git a/commons/src/main/java/com/powsybl/commons/datasource/ZstdDirectoryDataSource.java b/commons/src/main/java/com/powsybl/commons/datasource/ZstdDirectoryDataSource.java index f91fe3d36bd..b5b06a5f18c 100644 --- a/commons/src/main/java/com/powsybl/commons/datasource/ZstdDirectoryDataSource.java +++ b/commons/src/main/java/com/powsybl/commons/datasource/ZstdDirectoryDataSource.java @@ -18,12 +18,8 @@ */ public class ZstdDirectoryDataSource extends DirectoryDataSource { - public ZstdDirectoryDataSource(Path directory, String baseName, DataSourceObserver observer) { - super(directory, baseName, CompressionFormat.ZSTD, observer); - } - - public ZstdDirectoryDataSource(Path directory, String baseName) { - super(directory, baseName, CompressionFormat.ZSTD, null); + public ZstdDirectoryDataSource(Path directory, String baseName, String dataExtension, DataSourceObserver observer) { + super(directory, baseName, dataExtension, CompressionFormat.ZSTD, observer); } @Override diff --git a/commons/src/test/java/com/powsybl/commons/datasource/AbstractFileSystemDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/AbstractFileSystemDataSourceTest.java index 8a285694a99..c615887e620 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/AbstractFileSystemDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/AbstractFileSystemDataSourceTest.java @@ -44,8 +44,8 @@ protected boolean appendTest() { protected abstract DataSource createDataSource(DataSourceObserver observer); - protected String getFileName(String baseName, CompressionFormat compressionFormat) { - return testDir + "/" + baseName + protected String getFileName(String baseName, String dataExtension, CompressionFormat compressionFormat) { + return testDir + "/" + baseName + (dataExtension == null || dataExtension.isEmpty() ? "" : "." + dataExtension) + (compressionFormat == null ? "" : "." + compressionFormat.getExtension()); } @@ -53,9 +53,9 @@ protected String getFileName(String baseName, CompressionFormat compressionForma @ParameterizedTest @MethodSource("provideArgumentsForWriteThenReadTest") - void writeThenReadTest(String baseName, CompressionFormat compressionFormat) throws IOException { + void writeThenReadTest(String baseName, String dataExtension, CompressionFormat compressionFormat) throws IOException { // Compute the full filename - String fileName = getFileName(baseName, compressionFormat); + String fileName = getFileName(baseName, dataExtension, compressionFormat); // Create the files createFiles(fileName); @@ -112,11 +112,11 @@ private void writeThenReadTest(DataSource dataSource, String suffix, String ext) @ParameterizedTest @MethodSource("provideArgumentsForClassAndListingTest") - void testClassAndListing(String baseName, + void testClassAndListing(String baseName, String dataExtension, CompressionFormat compressionFormat, Class dataSourceClass, Set listedFiles, Set listedBarFiles) throws IOException { // Compute the full filename - String fileName = getFileName(baseName, compressionFormat); + String fileName = getFileName(baseName, dataExtension, compressionFormat); // Update the list of unlisted files unlistedFiles = existingFiles.stream().filter(name -> !listedFiles.contains(name)).collect(Collectors.toSet()); @@ -145,8 +145,9 @@ void testGetters() { // Checks assertInstanceOf(AbstractFileSystemDataSource.class, dataSourceWithObserver); - assertEquals("foo", dataSourceWithObserver.getBaseName()); assertEquals(testDir, ((AbstractFileSystemDataSource) dataSourceWithObserver).getDirectory()); + assertEquals("foo", dataSourceWithObserver.getBaseName()); + assertEquals("iidm", dataSourceWithObserver.getDataExtension()); assertEquals(compressionFormat, ((AbstractFileSystemDataSource) dataSourceWithObserver).getCompressionFormat()); assertEquals(observer, ((AbstractFileSystemDataSource) dataSourceWithObserver).getObserver()); @@ -157,7 +158,28 @@ void testGetters() { assertInstanceOf(AbstractFileSystemDataSource.class, dataSourceWithoutObserver); assertEquals("foo", dataSourceWithoutObserver.getBaseName()); assertEquals(testDir, ((AbstractFileSystemDataSource) dataSourceWithoutObserver).getDirectory()); + assertEquals("foo", dataSourceWithoutObserver.getBaseName()); + assertNull(dataSourceWithoutObserver.getDataExtension()); assertEquals(compressionFormat, ((AbstractFileSystemDataSource) dataSourceWithoutObserver).getCompressionFormat()); assertNull(((AbstractFileSystemDataSource) dataSourceWithoutObserver).getObserver()); } + + @Test + void testExists() throws IOException { + // Observer + DataSourceObserver observer = new DefaultDataSourceObserver(); + + // Create the files + createFiles(getFileName("foo", "iidm", compressionFormat)); + + // Create the datasource + DataSource dataSourceWithObserver = createDataSource(observer); + + // Checks + assertTrue(dataSourceWithObserver.exists(null, "iidm")); + assertTrue(dataSourceWithObserver.exists(null, "txt")); + assertTrue(dataSourceWithObserver.isDataExtension("iidm")); + assertFalse(dataSourceWithObserver.isDataExtension("txt")); + + } } diff --git a/commons/src/test/java/com/powsybl/commons/datasource/Bzip2DirectoryDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/Bzip2DirectoryDataSourceTest.java index 9e19f4874d1..3d6ccae925f 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/Bzip2DirectoryDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/Bzip2DirectoryDataSourceTest.java @@ -36,12 +36,12 @@ void testConstructors() { DataSourceObserver observer = new DefaultDataSourceObserver(); // Check constructors - checkDataSource(new Bzip2DirectoryDataSource(testDir, "foo_bar", observer), observer); - checkDataSource(new Bzip2DirectoryDataSource(testDir, "foo_bar"), null); + checkDataSource(new Bzip2DirectoryDataSource(testDir, "foo_bar", "iidm", observer), observer); } private void checkDataSource(DirectoryDataSource dataSource, DataSourceObserver observer) { assertEquals(testDir, dataSource.getDirectory()); + assertEquals("iidm", dataSource.getDataExtension()); assertEquals(compressionFormat, dataSource.getCompressionFormat()); assertEquals("foo_bar", dataSource.getBaseName()); assertEquals(observer, dataSource.getObserver()); @@ -55,19 +55,19 @@ protected boolean appendTest() { @Override protected DataSource createDataSource() { - return new Bzip2DirectoryDataSource(testDir, "foo"); + return new Bzip2DirectoryDataSource(testDir, "foo", null, null); } @Override protected DataSource createDataSource(DataSourceObserver observer) { - return new Bzip2DirectoryDataSource(testDir, "foo", observer); + return new Bzip2DirectoryDataSource(testDir, "foo", "iidm", observer); } static Stream provideArgumentsForWriteThenReadTest() { return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.BZIP2), - Arguments.of("foo", CompressionFormat.BZIP2), - Arguments.of("foo.v3", CompressionFormat.BZIP2) + Arguments.of("foo", "iidm", CompressionFormat.BZIP2), + Arguments.of("foo", "", CompressionFormat.BZIP2), + Arguments.of("foo", "v3", CompressionFormat.BZIP2) ); } @@ -78,13 +78,13 @@ static Stream provideArgumentsForClassAndListingTest() { "foo.gz", "foo.txt.gz", "foo.iidm.gz", "foo.xiidm.gz", "foo.v3.iidm.gz", "foo.v3.gz", "foo_bar.iidm.gz", "foo_bar.gz"); Set listedBarFiles = Set.of("foo_bar.iidm", "foo_bar", "foo_bar.iidm.xz", "foo_bar.xz", "foo_bar.iidm.zst", "foo_bar.zst", "foo_bar.iidm.gz", "foo_bar.gz"); return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.BZIP2, Bzip2DirectoryDataSource.class, + Arguments.of("foo", "iidm", CompressionFormat.BZIP2, Bzip2DirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo", CompressionFormat.BZIP2, Bzip2DirectoryDataSource.class, + Arguments.of("foo", "", CompressionFormat.BZIP2, Bzip2DirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo.v3", CompressionFormat.BZIP2, Bzip2DirectoryDataSource.class, + Arguments.of("foo", "v3", CompressionFormat.BZIP2, Bzip2DirectoryDataSource.class, listedFiles, listedBarFiles) ); diff --git a/commons/src/test/java/com/powsybl/commons/datasource/DataSourceBuilderTest.java b/commons/src/test/java/com/powsybl/commons/datasource/DataSourceBuilderTest.java new file mode 100644 index 00000000000..1ad9ecfd6c3 --- /dev/null +++ b/commons/src/test/java/com/powsybl/commons/datasource/DataSourceBuilderTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.commons.datasource; + +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import com.powsybl.commons.PowsyblException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Nicolas Rol {@literal } + */ +class DataSourceBuilderTest { + protected FileSystem fileSystem; + protected Path testDir; + + @BeforeEach + void setUp() throws IOException { + fileSystem = Jimfs.newFileSystem(Configuration.unix()); + testDir = fileSystem.getPath("/tmp"); + Files.createDirectories(testDir); + } + + @Test + void testBuilder() { + // Observer + DataSourceObserver observer = new DefaultDataSourceObserver(); + + // Constant parameters + DataSourceBuilder builder = new DataSourceBuilder() + .withDirectory(testDir) + .withBaseName("foo") + .withDataExtension(".baz") + .withObserver(observer); + + // Directory datasource + assertInstanceOf(DirectoryDataSource.class, builder.build()); + assertInstanceOf(GzDirectoryDataSource.class, builder.withCompressionFormat(CompressionFormat.GZIP).build()); + assertInstanceOf(ZstdDirectoryDataSource.class, builder.withCompressionFormat(CompressionFormat.ZSTD).build()); + assertInstanceOf(XZDirectoryDataSource.class, builder.withCompressionFormat(CompressionFormat.XZ).build()); + assertInstanceOf(Bzip2DirectoryDataSource.class, builder.withCompressionFormat(CompressionFormat.BZIP2).build()); + + // Archive datasources + assertInstanceOf(ZipArchiveDataSource.class, builder.withArchiveFormat(ArchiveFormat.ZIP).withCompressionFormat(null).build()); + assertInstanceOf(ZipArchiveDataSource.class, builder.withCompressionFormat(CompressionFormat.ZIP).build()); + assertInstanceOf(ZipArchiveDataSource.class, builder.withArchiveFormat(null).build()); + } + + @Test + void testBuilderErrors() { + // Observer + DataSourceObserver observer = new DefaultDataSourceObserver(); + + // Builder + DataSourceBuilder builder = new DataSourceBuilder() + .withCompressionFormat(CompressionFormat.ZIP) + .withArchiveFileName("bar.zip") + .withDataExtension(".baz") + .withArchiveFormat(ArchiveFormat.ZIP) + .withObserver(observer); + + // Directory missing + PowsyblException exception = assertThrows(PowsyblException.class, builder::build); + assertEquals("Datasource directory cannot be null", exception.getMessage()); + + // Directory parameter is not a directory but a file + Path file = testDir.resolve("fake.zip"); + builder.withDirectory(file); + exception = assertThrows(PowsyblException.class, builder::build); + assertEquals("Datasource directory has to be a directory", exception.getMessage()); + + // Base name missing + builder.withDirectory(testDir); + exception = assertThrows(PowsyblException.class, builder::build); + assertEquals("Datasource baseName cannot be null", exception.getMessage()); + } + + @Test + void testBuilderErrorsZip() { + DataSourceBuilder builder = new DataSourceBuilder() + .withDirectory(testDir) + .withBaseName("foo") + .withArchiveFileName("bar.zip") + .withDataExtension(".baz"); + + // Wrong compression format + builder.withCompressionFormat(CompressionFormat.GZIP).withArchiveFormat(ArchiveFormat.ZIP); + PowsyblException exception = assertThrows(PowsyblException.class, builder::build); + assertEquals("Incoherence between compression format GZIP and archive format ZIP", exception.getMessage()); + } +} diff --git a/commons/src/test/java/com/powsybl/commons/datasource/DirectoryDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/DirectoryDataSourceTest.java index 2641571df76..5eb13218e6c 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/DirectoryDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/DirectoryDataSourceTest.java @@ -71,13 +71,15 @@ void testConstructors() { DataSourceObserver observer = new DefaultDataSourceObserver(); // Check constructors - checkDataSource(new DirectoryDataSource(testDir, "foo_bar", CompressionFormat.GZIP, observer), CompressionFormat.GZIP, observer); - checkDataSource(new DirectoryDataSource(testDir, "foo_bar", observer), null, observer); - checkDataSource(new DirectoryDataSource(testDir, "foo_bar"), null, null); + checkDataSource(new DirectoryDataSource(testDir, "foo_bar"), null, null, null); + checkDataSource(new DirectoryDataSource(testDir, "foo_bar", observer), null, null, observer); + checkDataSource(new DirectoryDataSource(testDir, "foo_bar", "iidm", observer), "iidm", null, observer); + checkDataSource(new DirectoryDataSource(testDir, "foo_bar", "iidm", CompressionFormat.GZIP, observer), "iidm", CompressionFormat.GZIP, observer); } - private void checkDataSource(DirectoryDataSource dataSource, CompressionFormat compressionFormat, DataSourceObserver observer) { + private void checkDataSource(DirectoryDataSource dataSource, String dataExtension, CompressionFormat compressionFormat, DataSourceObserver observer) { assertEquals(testDir, dataSource.getDirectory()); + assertEquals(dataExtension, dataSource.getDataExtension()); assertEquals(compressionFormat, dataSource.getCompressionFormat()); assertEquals("foo_bar", dataSource.getBaseName()); assertEquals(observer, dataSource.getObserver()); @@ -90,14 +92,14 @@ protected DataSource createDataSource() { @Override protected DataSource createDataSource(DataSourceObserver observer) { - return new DirectoryDataSource(testDir, "foo", observer); + return new DirectoryDataSource(testDir, "foo", "iidm", observer); } static Stream provideArgumentsForWriteThenReadTest() { return Stream.of( - Arguments.of("foo.iidm", null), - Arguments.of("foo", null), - Arguments.of("foo.v3", null) + Arguments.of("foo", "iidm", null), + Arguments.of("foo", "", null), + Arguments.of("foo", "v3", null) ); } @@ -110,13 +112,13 @@ static Stream provideArgumentsForClassAndListingTest() { Set listedBarFiles = Set.of("foo_bar.iidm", "foo_bar", "foo_bar.iidm.bz2", "foo_bar.bz2", "foo_bar.iidm.xz", "foo_bar.xz", "foo_bar.iidm.zst", "foo_bar.zst", "foo_bar.iidm.gz", "foo_bar.gz"); return Stream.of( - Arguments.of("foo.iidm", null, DirectoryDataSource.class, + Arguments.of("foo", "iidm", null, DirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo", null, DirectoryDataSource.class, + Arguments.of("foo", "", null, DirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo.v3", null, DirectoryDataSource.class, + Arguments.of("foo", "v3", null, DirectoryDataSource.class, listedFiles, listedBarFiles) ); diff --git a/commons/src/test/java/com/powsybl/commons/datasource/FileInformationTest.java b/commons/src/test/java/com/powsybl/commons/datasource/FileInformationTest.java new file mode 100644 index 00000000000..4396afc5586 --- /dev/null +++ b/commons/src/test/java/com/powsybl/commons/datasource/FileInformationTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.commons.datasource; + +import com.powsybl.commons.PowsyblException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Nicolas Rol {@literal } + */ +class FileInformationTest { + + @Test + void tests() { + unitTest("dummy", "dummy", null, null, ""); + unitTest("dummy.iidm", "dummy", null, null, "iidm"); + unitTest("dummy.xml.xz", "dummy", CompressionFormat.XZ, null, "xml"); + + // A zip file is a compressed archive + unitTest("dummy.zip", "dummy", CompressionFormat.ZIP, ArchiveFormat.ZIP, ""); + + // It can still specify the source format + unitTest("dummy.jiidm.zip", "dummy", CompressionFormat.ZIP, ArchiveFormat.ZIP, "jiidm"); + + // If there is a usual format and additional extensions, those extensions go in the baseName + unitTest("dummy.v3.xml.zst", "dummy.v3", CompressionFormat.ZSTD, null, "xml"); + + // If there are additional extensions but no usual format, the last extension becomes the source format + unitTest("dummy.v3.bz2", "dummy", CompressionFormat.BZIP2, null, "v3"); + + // Hidden files + unitTest(".dummy", ".dummy", null, null, ""); + unitTest(".iidm", ".iidm", null, null, ""); + unitTest(".zip", "", CompressionFormat.ZIP, ArchiveFormat.ZIP, ""); + unitTest(".dummy.jiidm.zip", ".dummy", CompressionFormat.ZIP, ArchiveFormat.ZIP, "jiidm"); + + PowsyblException exception = assertThrows(PowsyblException.class, () -> new FileInformation("")); + assertEquals("File name cannot be empty nor just a dot", exception.getMessage()); + + exception = assertThrows(PowsyblException.class, () -> new FileInformation(".")); + assertEquals("File name cannot be empty nor just a dot", exception.getMessage()); + } + + private void unitTest(String filename, String baseName, + CompressionFormat compressionFormat, ArchiveFormat archiveFormat, String dataExtension) { + // Create the file information object + FileInformation fileInformation = new FileInformation(filename); + + // Check the information + assertEquals(baseName, fileInformation.getBaseName()); + assertEquals(compressionFormat, fileInformation.getCompressionFormat()); + assertEquals(archiveFormat, fileInformation.getArchiveFormat()); + assertEquals(dataExtension, fileInformation.getDataExtension()); + } + + @Test + void testToString() { + // Create the file information object + FileInformation fileInformation = new FileInformation("foo.bar.zip"); + + assertEquals("FileInformation[baseName=foo, dataExtension=bar, archiveFormat=ZIP, compressionFormat=ZIP]", fileInformation.toString()); + } +} diff --git a/commons/src/test/java/com/powsybl/commons/datasource/GenericReadOnlyDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/GenericReadOnlyDataSourceTest.java new file mode 100644 index 00000000000..0f3a28f82a8 --- /dev/null +++ b/commons/src/test/java/com/powsybl/commons/datasource/GenericReadOnlyDataSourceTest.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.commons.datasource; + +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Nicolas Rol {@literal } + */ +class GenericReadOnlyDataSourceTest { + + protected FileSystem fileSystem; + protected Path testDir; + protected Set unlistedFiles; + protected Set existingFiles; + protected Set filesInArchive; + + @BeforeEach + void setUp() throws Exception { + fileSystem = Jimfs.newFileSystem(Configuration.unix()); + testDir = fileSystem.getPath("/tmp"); + Files.createDirectories(testDir); + + // Files + existingFiles = Set.of( + "foo", "foo.txt", "foo.iidm", "foo.xiidm", "foo.v3.iidm", "foo.v3", "foo_bar.iidm", "foo_bar", "bar.iidm", "bar", + "foo.bz2", "foo.txt.bz2", "foo.iidm.bz2", "foo.xiidm.bz2", "foo.v3.iidm.bz2", "foo.v3.bz2", "foo_bar.iidm.bz2", "foo_bar.bz2", "bar.iidm.bz2", "bar.bz2", + "foo.xz", "foo.txt.xz", "foo.iidm.xz", "foo.xiidm.xz", "foo.v3.iidm.xz", "foo.v3.xz", "foo_bar.iidm.xz", "foo_bar.xz", "bar.iidm.xz", "bar.xz", + "foo.zst", "foo.txt.zst", "foo.iidm.zst", "foo.xiidm.zst", "foo.v3.iidm.zst", "foo.v3.zst", "foo_bar.iidm.zst", "foo_bar.zst", "bar.iidm.zst", "bar.zst", + "foo.gz", "foo.txt.gz", "foo.iidm.gz", "foo.xiidm.gz", "foo.v3.iidm.gz", "foo.v3.gz", "foo_bar.iidm.gz", "foo_bar.gz", "bar.iidm.gz", "bar.gz" + ); + filesInArchive = Set.of( + "foo_in_archive", "foo_in_archive.txt", "foo_in_archive.iidm", "foo_in_archive.xiidm", + "foo_in_archive.v3.iidm", "foo_in_archive.v3", "foo_bar_in_archive.iidm", "foo_bar_in_archive", + "bar_in_archive.iidm", "bar_in_archive"); + } + + @AfterEach + void tearDown() throws Exception { + fileSystem.close(); + } + + @Test + void testConstructors() { + // Observer + DataSourceObserver observer = new DefaultDataSourceObserver(); + + // Check constructors + checkDataSource(new GenericReadOnlyDataSource(testDir), "", null); + checkDataSource(new GenericReadOnlyDataSource(testDir, "foo_bar"), "foo_bar", null); + checkDataSource(new GenericReadOnlyDataSource(testDir, "foo_bar", "iidm"), "foo_bar", "iidm"); + checkDataSource(new GenericReadOnlyDataSource(testDir, "foo_bar", "iidm", observer), "foo_bar", "iidm"); + } + + private void checkDataSource(GenericReadOnlyDataSource dataSource, String baseName, String dataExtension) { + assertEquals(baseName, dataSource.getBaseName()); + assertEquals(dataExtension, dataSource.getDataExtension()); + } + + private String getFileName(String baseName, String dataExtension) { + return testDir + "/" + baseName + (dataExtension == null || dataExtension.isEmpty() ? "" : "." + dataExtension); + } + + private void createFiles(String archiveName) throws IOException { + // Create the test files in the directory + existingFiles.forEach(fileName -> { + try { + Files.createFile(fileSystem.getPath(testDir + "/" + fileName)); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + // Create the Zip archive and add the files + try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(fileSystem.getPath(archiveName + ".zip")))) { + filesInArchive.forEach(fileInArchive -> { + try { + ZipEntry e = new ZipEntry(fileInArchive); + out.putNextEntry(e); + byte[] data = "Test String".getBytes(); + out.write(data, 0, data.length); + out.closeEntry(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + }); + } + } + + // Currently, the files are not filtered in the zip archive + static Stream provideArgumentsForClassAndListingTest() { + Set listedBarFiles = Set.of("foo_bar.iidm", "foo_bar", "foo_bar.iidm.bz2", "foo_bar.bz2", "foo_bar.iidm.xz", "foo_bar.xz", + "foo_bar.iidm.zst", "foo_bar.zst", "foo_bar.iidm.gz", "foo_bar.gz", "foo_bar_in_archive.iidm", "foo_bar_in_archive", + "bar_in_archive.iidm", "bar_in_archive"); + return Stream.of( + Arguments.of("foo", "iidm", GenericReadOnlyDataSource.class, + Set.of("foo", "foo.txt", "foo.iidm", "foo.xiidm", "foo.v3.iidm", "foo.v3", "foo_bar.iidm", "foo_bar", + "foo.bz2", "foo.txt.bz2", "foo.iidm.bz2", "foo.xiidm.bz2", "foo.v3.iidm.bz2", "foo.v3.bz2", "foo_bar.iidm.bz2", "foo_bar.bz2", + "foo.xz", "foo.txt.xz", "foo.iidm.xz", "foo.xiidm.xz", "foo.v3.iidm.xz", "foo.v3.xz", "foo_bar.iidm.xz", "foo_bar.xz", + "foo.zst", "foo.txt.zst", "foo.iidm.zst", "foo.xiidm.zst", "foo.v3.iidm.zst", "foo.v3.zst", "foo_bar.iidm.zst", "foo_bar.zst", + "foo.gz", "foo.txt.gz", "foo.iidm.gz", "foo.xiidm.gz", "foo.v3.iidm.gz", "foo.v3.gz", "foo_bar.iidm.gz", "foo_bar.gz", + "foo_in_archive", "foo_in_archive.txt", "foo_in_archive.iidm", "foo_in_archive.xiidm", + "foo_in_archive.v3.iidm", "foo_in_archive.v3", "foo_bar_in_archive.iidm", "foo_bar_in_archive", + "bar_in_archive.iidm", "bar_in_archive", "foo.iidm.zip"), + listedBarFiles), + Arguments.of("foo", "", GenericReadOnlyDataSource.class, + Set.of("foo", "foo.txt", "foo.iidm", "foo.xiidm", "foo.v3.iidm", "foo.v3", "foo_bar.iidm", "foo_bar", + "foo.bz2", "foo.txt.bz2", "foo.iidm.bz2", "foo.xiidm.bz2", "foo.v3.iidm.bz2", "foo.v3.bz2", "foo_bar.iidm.bz2", "foo_bar.bz2", + "foo.xz", "foo.txt.xz", "foo.iidm.xz", "foo.xiidm.xz", "foo.v3.iidm.xz", "foo.v3.xz", "foo_bar.iidm.xz", "foo_bar.xz", + "foo.zst", "foo.txt.zst", "foo.iidm.zst", "foo.xiidm.zst", "foo.v3.iidm.zst", "foo.v3.zst", "foo_bar.iidm.zst", "foo_bar.zst", + "foo.gz", "foo.txt.gz", "foo.iidm.gz", "foo.xiidm.gz", "foo.v3.iidm.gz", "foo.v3.gz", "foo_bar.iidm.gz", "foo_bar.gz", + "foo_in_archive", "foo_in_archive.txt", "foo_in_archive.iidm", "foo_in_archive.xiidm", + "foo_in_archive.v3.iidm", "foo_in_archive.v3", "foo_bar_in_archive.iidm", "foo_bar_in_archive", + "bar_in_archive.iidm", "bar_in_archive", "foo.zip"), + listedBarFiles), + Arguments.of("foo", "v3", GenericReadOnlyDataSource.class, + Set.of("foo", "foo.txt", "foo.iidm", "foo.xiidm", "foo.v3.iidm", "foo.v3", "foo_bar.iidm", "foo_bar", + "foo.bz2", "foo.txt.bz2", "foo.iidm.bz2", "foo.xiidm.bz2", "foo.v3.iidm.bz2", "foo.v3.bz2", "foo_bar.iidm.bz2", "foo_bar.bz2", + "foo.xz", "foo.txt.xz", "foo.iidm.xz", "foo.xiidm.xz", "foo.v3.iidm.xz", "foo.v3.xz", "foo_bar.iidm.xz", "foo_bar.xz", + "foo.zst", "foo.txt.zst", "foo.iidm.zst", "foo.xiidm.zst", "foo.v3.iidm.zst", "foo.v3.zst", "foo_bar.iidm.zst", "foo_bar.zst", + "foo.gz", "foo.txt.gz", "foo.iidm.gz", "foo.xiidm.gz", "foo.v3.iidm.gz", "foo.v3.gz", "foo_bar.iidm.gz", "foo_bar.gz", + "foo_in_archive", "foo_in_archive.txt", "foo_in_archive.iidm", "foo_in_archive.xiidm", + "foo_in_archive.v3.iidm", "foo_in_archive.v3", "foo_bar_in_archive.iidm", "foo_bar_in_archive", + "bar_in_archive.iidm", "bar_in_archive", "foo.v3.zip"), + listedBarFiles) + ); + } + + @ParameterizedTest + @MethodSource("provideArgumentsForClassAndListingTest") + void testClassAndListing(String baseName, String dataExtension, + Class dataSourceClass, + Set listedFiles, Set listedBarFiles) throws IOException { + // Compute the full filename + String fileName = getFileName(baseName, dataExtension); + + // Update the list of unlisted files + unlistedFiles = existingFiles.stream().filter(name -> !listedFiles.contains(name)).collect(Collectors.toSet()); + + // Create the files + createFiles(fileName); + + // Create the datasource + GenericReadOnlyDataSource dataSource = new GenericReadOnlyDataSource(testDir, baseName, dataExtension); + + // Check the class + assertInstanceOf(dataSourceClass, dataSource); + + // List all the files in the datasource + assertEquals(listedFiles, dataSource.listNames(".*")); + assertEquals(listedBarFiles, dataSource.listNames(".*bar.*")); + } + + @Test + void testIsDataExtension() { + GenericReadOnlyDataSource dataSource = new GenericReadOnlyDataSource(testDir, "foo_bar"); + assertTrue(dataSource.isDataExtension("test")); + assertTrue(dataSource.isDataExtension("iidm")); + + dataSource = new GenericReadOnlyDataSource(testDir, "foo_bar", "iidm"); + assertTrue(dataSource.isDataExtension("test")); + assertTrue(dataSource.isDataExtension("iidm")); + + } +} diff --git a/commons/src/test/java/com/powsybl/commons/datasource/GzDirectoryDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/GzDirectoryDataSourceTest.java index b49391e9189..793082c13ef 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/GzDirectoryDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/GzDirectoryDataSourceTest.java @@ -36,12 +36,12 @@ void testConstructors() { DataSourceObserver observer = new DefaultDataSourceObserver(); // Check constructors - checkDataSource(new GzDirectoryDataSource(testDir, "foo_bar", observer), observer); - checkDataSource(new GzDirectoryDataSource(testDir, "foo_bar"), null); + checkDataSource(new GzDirectoryDataSource(testDir, "foo_bar", "iidm", observer), observer); } private void checkDataSource(DirectoryDataSource dataSource, DataSourceObserver observer) { assertEquals(testDir, dataSource.getDirectory()); + assertEquals("iidm", dataSource.getDataExtension()); assertEquals(compressionFormat, dataSource.getCompressionFormat()); assertEquals("foo_bar", dataSource.getBaseName()); assertEquals(observer, dataSource.getObserver()); @@ -49,19 +49,19 @@ private void checkDataSource(DirectoryDataSource dataSource, DataSourceObserver @Override protected DataSource createDataSource() { - return new GzDirectoryDataSource(testDir, "foo"); + return new GzDirectoryDataSource(testDir, "foo", null, null); } @Override protected DataSource createDataSource(DataSourceObserver observer) { - return new GzDirectoryDataSource(testDir, "foo", observer); + return new GzDirectoryDataSource(testDir, "foo", "iidm", observer); } static Stream provideArgumentsForWriteThenReadTest() { return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.GZIP), - Arguments.of("foo", CompressionFormat.GZIP), - Arguments.of("foo.v3", CompressionFormat.GZIP) + Arguments.of("foo", "iidm", CompressionFormat.GZIP), + Arguments.of("foo", "", CompressionFormat.GZIP), + Arguments.of("foo", "v3", CompressionFormat.GZIP) ); } @@ -72,13 +72,13 @@ static Stream provideArgumentsForClassAndListingTest() { "foo.zst", "foo.txt.zst", "foo.iidm.zst", "foo.xiidm.zst", "foo.v3.iidm.zst", "foo.v3.zst", "foo_bar.iidm.zst", "foo_bar.zst"); Set listedBarFiles = Set.of("foo_bar.iidm", "foo_bar", "foo_bar.iidm.bz2", "foo_bar.bz2", "foo_bar.iidm.xz", "foo_bar.xz", "foo_bar.iidm.zst", "foo_bar.zst"); return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.GZIP, GzDirectoryDataSource.class, + Arguments.of("foo", "iidm", CompressionFormat.GZIP, GzDirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo", CompressionFormat.GZIP, GzDirectoryDataSource.class, + Arguments.of("foo", "", CompressionFormat.GZIP, GzDirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo.v3", CompressionFormat.GZIP, GzDirectoryDataSource.class, + Arguments.of("foo", "v3", CompressionFormat.GZIP, GzDirectoryDataSource.class, listedFiles, listedBarFiles) ); diff --git a/commons/src/test/java/com/powsybl/commons/datasource/MemDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/MemDataSourceTest.java index 419cd822b02..282f5947b1c 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/MemDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/MemDataSourceTest.java @@ -63,6 +63,11 @@ void baseNameTest() { assertEquals(dataSource.getBaseName(), getBaseName()); } + @Test + void dataExtensionTest() { + assertNull(dataSource.getDataExtension()); + } + private void writeThenReadTest(String suffix, String ext) throws IOException { // check file does not exist assertFalse(dataSource.exists(suffix, ext)); diff --git a/commons/src/test/java/com/powsybl/commons/datasource/MultipleReadOnlyDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/MultipleReadOnlyDataSourceTest.java index 3d79eabc81d..8ac50671499 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/MultipleReadOnlyDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/MultipleReadOnlyDataSourceTest.java @@ -38,6 +38,7 @@ void setUp() throws Exception { Files.createDirectories(testDir); Files.createFile(testDir.resolve("a.txt")); Files.createFile(testDir.resolve("b.txt")); + Files.createFile(testDir.resolve("b.foo")); } @AfterEach @@ -48,14 +49,16 @@ void tearDown() throws Exception { @Test void test() throws IOException { ReadOnlyDataSource dataSource = new MultipleReadOnlyDataSource(new DirectoryDataSource(testDir, "a"), - new DirectoryDataSource(testDir, "b")); + new DirectoryDataSource(testDir, "b", "txt", null)); assertEquals("a", dataSource.getBaseName()); assertTrue(dataSource.exists(null, "txt")); assertFalse(dataSource.exists(null, "json")); + assertTrue(dataSource.exists(null, "foo")); + assertTrue(dataSource.isDataExtension("foo")); assertTrue(dataSource.exists("a.txt")); assertTrue(dataSource.exists("b.txt")); assertFalse(dataSource.exists("c.txt")); - assertEquals(Set.of("a.txt", "b.txt"), dataSource.listNames(".*")); + assertEquals(Set.of("a.txt", "b.txt", "b.foo"), dataSource.listNames(".*")); try (var is = dataSource.newInputStream("a.txt")) { assertNotNull(is); } diff --git a/commons/src/test/java/com/powsybl/commons/datasource/ResourcesDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/ResourcesDataSourceTest.java index 079159a3905..c41dbce5f82 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/ResourcesDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/ResourcesDataSourceTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.Test; import java.util.Collections; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -18,10 +19,35 @@ */ class ResourcesDataSourceTest { + @Test + void testExists() { + ResourceDataSource dataSourceWithNoDataExtension = new ResourceDataSource("foo", List.of(new ResourceSet("/test/", "foo.txt", "foo.bar"))); + assertTrue(dataSourceWithNoDataExtension.exists("foo.txt")); + assertTrue(dataSourceWithNoDataExtension.exists(null, "bar")); + assertTrue(dataSourceWithNoDataExtension.exists(null, "txt")); + assertTrue(dataSourceWithNoDataExtension.isDataExtension("bar")); + assertTrue(dataSourceWithNoDataExtension.isDataExtension("txt")); + + ResourceDataSource dataSourceWithEmptyDataExtension = new ResourceDataSource("foo", "", List.of(new ResourceSet("/test/", "foo.txt", "foo.bar"))); + assertTrue(dataSourceWithEmptyDataExtension.exists("foo.txt")); + assertTrue(dataSourceWithEmptyDataExtension.exists(null, "bar")); + assertTrue(dataSourceWithEmptyDataExtension.exists(null, "txt")); + assertTrue(dataSourceWithEmptyDataExtension.isDataExtension("bar")); + assertTrue(dataSourceWithEmptyDataExtension.isDataExtension("txt")); + + ResourceDataSource dataSourceWithDataExtension = new ResourceDataSource("foo", "txt", List.of(new ResourceSet("/test/", "foo.txt", "foo.bar"))); + assertTrue(dataSourceWithDataExtension.exists("foo.txt")); + assertTrue(dataSourceWithDataExtension.exists(null, "bar")); + assertTrue(dataSourceWithDataExtension.exists(null, "txt")); + assertFalse(dataSourceWithDataExtension.isDataExtension("bar")); + assertTrue(dataSourceWithDataExtension.isDataExtension("txt")); + } + @Test void test() { ResourceDataSource dataSource = new ResourceDataSource("foo", new ResourceSet("/test/", "foo.txt")); assertEquals("foo", dataSource.getBaseName()); + assertNull(dataSource.getDataExtension()); assertTrue(dataSource.exists("foo.txt")); assertTrue(dataSource.exists(null, "txt")); assertFalse(dataSource.exists("foo.doc")); diff --git a/commons/src/test/java/com/powsybl/commons/datasource/XZDirectoryDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/XZDirectoryDataSourceTest.java index a670c4c19bd..197c3b5f0e8 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/XZDirectoryDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/XZDirectoryDataSourceTest.java @@ -36,12 +36,12 @@ void testConstructors() { DataSourceObserver observer = new DefaultDataSourceObserver(); // Check constructors - checkDataSource(new XZDirectoryDataSource(testDir, "foo_bar", observer), observer); - checkDataSource(new XZDirectoryDataSource(testDir, "foo_bar"), null); + checkDataSource(new XZDirectoryDataSource(testDir, "foo_bar", "iidm", observer), observer); } private void checkDataSource(DirectoryDataSource dataSource, DataSourceObserver observer) { assertEquals(testDir, dataSource.getDirectory()); + assertEquals("iidm", dataSource.getDataExtension()); assertEquals(compressionFormat, dataSource.getCompressionFormat()); assertEquals("foo_bar", dataSource.getBaseName()); assertEquals(observer, dataSource.getObserver()); @@ -55,19 +55,19 @@ protected boolean appendTest() { @Override protected DataSource createDataSource() { - return new XZDirectoryDataSource(testDir, "foo"); + return new XZDirectoryDataSource(testDir, "foo", null, null); } @Override protected DataSource createDataSource(DataSourceObserver observer) { - return new XZDirectoryDataSource(testDir, "foo", observer); + return new XZDirectoryDataSource(testDir, "foo", "iidm", observer); } static Stream provideArgumentsForWriteThenReadTest() { return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.XZ), - Arguments.of("foo", CompressionFormat.XZ), - Arguments.of("foo.v3", CompressionFormat.XZ) + Arguments.of("foo", "iidm", CompressionFormat.XZ), + Arguments.of("foo", "", CompressionFormat.XZ), + Arguments.of("foo", "v3", CompressionFormat.XZ) ); } @@ -78,13 +78,13 @@ static Stream provideArgumentsForClassAndListingTest() { "foo.gz", "foo.txt.gz", "foo.iidm.gz", "foo.xiidm.gz", "foo.v3.iidm.gz", "foo.v3.gz", "foo_bar.iidm.gz", "foo_bar.gz"); Set listedBarFiles = Set.of("foo_bar.iidm", "foo_bar", "foo_bar.iidm.bz2", "foo_bar.bz2", "foo_bar.iidm.zst", "foo_bar.zst", "foo_bar.iidm.gz", "foo_bar.gz"); return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.XZ, XZDirectoryDataSource.class, + Arguments.of("foo", "iidm", CompressionFormat.XZ, XZDirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo", CompressionFormat.XZ, XZDirectoryDataSource.class, + Arguments.of("foo", "", CompressionFormat.XZ, XZDirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo.v3", CompressionFormat.XZ, XZDirectoryDataSource.class, + Arguments.of("foo", "v3", CompressionFormat.XZ, XZDirectoryDataSource.class, listedFiles, listedBarFiles) ); diff --git a/commons/src/test/java/com/powsybl/commons/datasource/ZipArchiveDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/ZipArchiveDataSourceTest.java index 5e72fafdb9b..f715be6551b 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/ZipArchiveDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/ZipArchiveDataSourceTest.java @@ -55,15 +55,21 @@ void testConstructors() { DataSourceObserver observer = new DefaultDataSourceObserver(); // Check constructors - checkDataSource(new ZipArchiveDataSource(testDir, "foo_bar.zip", "foo", observer), "foo_bar.zip", "foo", observer); - checkDataSource(new ZipArchiveDataSource(testDir, "foo_bar.zip", "foo"), "foo_bar.zip", "foo", null); - checkDataSource(new ZipArchiveDataSource(testDir, "foo", observer), "foo.zip", "foo", observer); - checkDataSource(new ZipArchiveDataSource(testDir, "foo"), "foo.zip", "foo", null); - checkDataSource(new ZipArchiveDataSource(testDir.resolve("foo_bar.zip")), "foo_bar.zip", "foo_bar", null); + checkDataSource(new ZipArchiveDataSource(testDir, "foo_bar.zip", "foo", "iidm", observer), "foo_bar.zip", "foo", "iidm", observer); + checkDataSource(new ZipArchiveDataSource(testDir, "foo_bar.zip", "foo", "iidm"), "foo_bar.zip", "foo", "iidm", null); + checkDataSource(new ZipArchiveDataSource(testDir, "foo", "iidm", observer), "foo.iidm.zip", "foo", "iidm", observer); + checkDataSource(new ZipArchiveDataSource(testDir, "foo", "", observer), "foo.zip", "foo", "", observer); + checkDataSource(new ZipArchiveDataSource(testDir, "foo", "iidm"), "foo.iidm.zip", "foo", "iidm", null); + checkDataSource(new ZipArchiveDataSource(testDir, "foo", (String) null), "foo.zip", "foo", null, null); + checkDataSource(new ZipArchiveDataSource(testDir, "foo", ""), "foo.zip", "foo", "", null); + checkDataSource(new ZipArchiveDataSource(testDir, "foo", observer), "foo.zip", "foo", null, observer); + checkDataSource(new ZipArchiveDataSource(testDir, "foo"), "foo.zip", "foo", null, null); + checkDataSource(new ZipArchiveDataSource(testDir.resolve("foo_bar.zip")), "foo_bar.zip", "foo_bar", null, null); } - private void checkDataSource(ZipArchiveDataSource dataSource, String zipFileName, String baseName, DataSourceObserver observer) { + private void checkDataSource(ZipArchiveDataSource dataSource, String zipFileName, String baseName, String dataExtension, DataSourceObserver observer) { assertEquals(testDir, dataSource.getDirectory()); + assertEquals(dataExtension, dataSource.getDataExtension()); assertEquals(zipFileName, dataSource.getArchiveFilePath().getFileName().toString()); assertEquals(baseName, dataSource.getBaseName()); assertEquals(observer, dataSource.getObserver()); @@ -76,19 +82,19 @@ protected boolean appendTest() { @Override protected DataSource createDataSource() { - return new ZipArchiveDataSource(testDir, "foo.zip", "foo"); + return new ZipArchiveDataSource(testDir, "foo.zip", "foo", null, null); } @Override protected DataSource createDataSource(DataSourceObserver observer) { - return new ZipArchiveDataSource(testDir, "foo", observer); + return new ZipArchiveDataSource(testDir, "foo", "iidm", observer); } static Stream provideArgumentsForWriteThenReadTest() { return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.ZIP), - Arguments.of("foo", CompressionFormat.ZIP), - Arguments.of("foo.v3", CompressionFormat.ZIP) + Arguments.of("foo", "iidm", CompressionFormat.ZIP), + Arguments.of("foo", "", CompressionFormat.ZIP), + Arguments.of("foo", "v3", CompressionFormat.ZIP) ); } @@ -97,13 +103,13 @@ static Stream provideArgumentsForClassAndListingTest() { Set listedFiles = Set.of("foo", "foo.txt", "foo.iidm", "foo.xiidm", "foo.v3.iidm", "foo.v3", "foo_bar.iidm", "foo_bar", "bar.iidm", "bar"); Set listedBarFiles = Set.of("foo_bar.iidm", "foo_bar", "bar.iidm", "bar"); return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.ZIP, ZipArchiveDataSource.class, + Arguments.of("foo", "iidm", CompressionFormat.ZIP, ZipArchiveDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo", CompressionFormat.ZIP, ZipArchiveDataSource.class, + Arguments.of("foo", "", CompressionFormat.ZIP, ZipArchiveDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo.v3", CompressionFormat.ZIP, ZipArchiveDataSource.class, + Arguments.of("foo", "v3", CompressionFormat.ZIP, ZipArchiveDataSource.class, listedFiles, listedBarFiles) ); diff --git a/commons/src/test/java/com/powsybl/commons/datasource/ZstdDirectoryDataSourceTest.java b/commons/src/test/java/com/powsybl/commons/datasource/ZstdDirectoryDataSourceTest.java index 5d8cfbc67b5..c94f790e76f 100644 --- a/commons/src/test/java/com/powsybl/commons/datasource/ZstdDirectoryDataSourceTest.java +++ b/commons/src/test/java/com/powsybl/commons/datasource/ZstdDirectoryDataSourceTest.java @@ -36,12 +36,12 @@ void testConstructors() { DataSourceObserver observer = new DefaultDataSourceObserver(); // Check constructors - checkDataSource(new ZstdDirectoryDataSource(testDir, "foo_bar", observer), observer); - checkDataSource(new ZstdDirectoryDataSource(testDir, "foo_bar"), null); + checkDataSource(new ZstdDirectoryDataSource(testDir, "foo_bar", "iidm", observer), observer); } private void checkDataSource(DirectoryDataSource dataSource, DataSourceObserver observer) { assertEquals(testDir, dataSource.getDirectory()); + assertEquals("iidm", dataSource.getDataExtension()); assertEquals(compressionFormat, dataSource.getCompressionFormat()); assertEquals("foo_bar", dataSource.getBaseName()); assertEquals(observer, dataSource.getObserver()); @@ -49,19 +49,19 @@ private void checkDataSource(DirectoryDataSource dataSource, DataSourceObserver @Override protected DataSource createDataSource() { - return new ZstdDirectoryDataSource(testDir, "foo"); + return new ZstdDirectoryDataSource(testDir, "foo", null, null); } @Override protected DataSource createDataSource(DataSourceObserver observer) { - return new ZstdDirectoryDataSource(testDir, "foo", observer); + return new ZstdDirectoryDataSource(testDir, "foo", "iidm", observer); } static Stream provideArgumentsForWriteThenReadTest() { return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.ZSTD), - Arguments.of("foo", CompressionFormat.ZSTD), - Arguments.of("foo.v3", CompressionFormat.ZSTD) + Arguments.of("foo", "iidm", CompressionFormat.ZSTD), + Arguments.of("foo", "", CompressionFormat.ZSTD), + Arguments.of("foo", "v3", CompressionFormat.ZSTD) ); } @@ -72,13 +72,13 @@ static Stream provideArgumentsForClassAndListingTest() { "foo.gz", "foo.txt.gz", "foo.iidm.gz", "foo.xiidm.gz", "foo.v3.iidm.gz", "foo.v3.gz", "foo_bar.iidm.gz", "foo_bar.gz"); Set listedBarFiles = Set.of("foo_bar.iidm", "foo_bar", "foo_bar.iidm.bz2", "foo_bar.bz2", "foo_bar.iidm.xz", "foo_bar.xz", "foo_bar.iidm.gz", "foo_bar.gz"); return Stream.of( - Arguments.of("foo.iidm", CompressionFormat.ZSTD, ZstdDirectoryDataSource.class, + Arguments.of("foo", "iidm", CompressionFormat.ZSTD, ZstdDirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo", CompressionFormat.ZSTD, ZstdDirectoryDataSource.class, + Arguments.of("foo", "", CompressionFormat.ZSTD, ZstdDirectoryDataSource.class, listedFiles, listedBarFiles), - Arguments.of("foo.v3", CompressionFormat.ZSTD, ZstdDirectoryDataSource.class, + Arguments.of("foo", "v3", CompressionFormat.ZSTD, ZstdDirectoryDataSource.class, listedFiles, listedBarFiles) ); diff --git a/commons/src/test/resources/test/foo.bar b/commons/src/test/resources/test/foo.bar new file mode 100644 index 00000000000..19102815663 --- /dev/null +++ b/commons/src/test/resources/test/foo.bar @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git a/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java b/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java index 0d410b6082e..9b24cd54af6 100644 --- a/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java +++ b/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java @@ -80,7 +80,7 @@ public String getComment() { @Override public boolean exists(ReadOnlyDataSource dataSource) { try { - if (dataSource.exists(null, EXT)) { + if (dataSource.isDataExtension(EXT) && dataSource.exists(null, EXT)) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(dataSource.newInputStream(null, EXT)))) { String titleLine = reader.readLine(); if (titleLine != null) { diff --git a/iidm/iidm-api/src/test/java/com/powsybl/iidm/network/MultipleImporterIssueTest.java b/iidm/iidm-api/src/test/java/com/powsybl/iidm/network/MultipleImporterIssueTest.java new file mode 100644 index 00000000000..5b546d9bf1f --- /dev/null +++ b/iidm/iidm-api/src/test/java/com/powsybl/iidm/network/MultipleImporterIssueTest.java @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2022, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network; + +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import com.powsybl.commons.datasource.DataSourceUtil; +import com.powsybl.commons.datasource.ReadOnlyDataSource; +import com.powsybl.commons.report.ReportNode; +import com.powsybl.computation.ComputationManager; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @author Geoffroy Jamgotchian + */ +class MultipleImporterIssueTest { + + static class FooImporter implements Importer { + + @Override + public String getFormat() { + return "foo"; + } + + @Override + public String getComment() { + return ""; + } + + @Override + public boolean exists(ReadOnlyDataSource dataSource) { + try { + return dataSource.isDataExtension("foo") && dataSource.exists(null, "foo"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public Network importData(ReadOnlyDataSource dataSource, NetworkFactory networkFactory, Properties parameters, ReportNode reportNode) { + throw new UnsupportedOperationException(); + } + } + + static class BarImporter implements Importer { + + @Override + public String getFormat() { + return "bar"; + } + + @Override + public String getComment() { + return ""; + } + + @Override + public boolean exists(ReadOnlyDataSource dataSource) { + try { + return dataSource.isDataExtension("bar") && dataSource.exists(null, "bar"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public Network importData(ReadOnlyDataSource dataSource, NetworkFactory networkFactory, Properties parameters, ReportNode reportNode) { + throw new UnsupportedOperationException(); + } + } + + @Test + void test() throws IOException { + try (FileSystem fileSystem = Jimfs.newFileSystem(Configuration.unix())) { + Path workingDir = fileSystem.getPath("/work"); + Path fooFile = workingDir.resolve("test.foo"); + Path barFile = workingDir.resolve("test.bar"); + Files.createFile(fooFile); + Files.createFile(barFile); + + var dataSource = DataSourceUtil.createDataSource(workingDir, "test.bar", null); + ComputationManager computationManager = Mockito.mock(ComputationManager.class); + var importer = Importer.find(dataSource, new ImportersLoaderList(new FooImporter(), new BarImporter()), computationManager, new ImportConfig()); + assertNotNull(importer); + assertInstanceOf(BarImporter.class, importer); + } + } +} diff --git a/iidm/iidm-api/src/test/java/com/powsybl/iidm/network/TestImporter.java b/iidm/iidm-api/src/test/java/com/powsybl/iidm/network/TestImporter.java index 1e36b7cc62c..21de23731e5 100644 --- a/iidm/iidm-api/src/test/java/com/powsybl/iidm/network/TestImporter.java +++ b/iidm/iidm-api/src/test/java/com/powsybl/iidm/network/TestImporter.java @@ -34,7 +34,7 @@ public String getComment() { @Override public boolean exists(ReadOnlyDataSource dataSource) { try { - return dataSource == null || dataSource.exists(null, "tst"); + return dataSource == null || dataSource.isDataExtension("tst") && dataSource.exists(null, "tst"); } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/iidm/iidm-serde/pom.xml b/iidm/iidm-serde/pom.xml index 0206f45cad9..0c29d3e1ec8 100644 --- a/iidm/iidm-serde/pom.xml +++ b/iidm/iidm-serde/pom.xml @@ -118,6 +118,12 @@ ${project.version} test + + ${project.groupId} + powsybl-tools-test + ${project.version} + test + diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataImporter.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataImporter.java index 621c93a5a43..9a41534cf25 100644 --- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataImporter.java +++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataImporter.java @@ -97,7 +97,7 @@ public List getParameters() { private String findExtension(ReadOnlyDataSource dataSource) throws IOException { for (String ext : getExtensions()) { - if (dataSource.exists(null, ext)) { + if (dataSource.isDataExtension(ext) && dataSource.exists(null, ext)) { return ext; } } diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/BinaryImporter.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/BinaryImporter.java index 27460f369d1..deb44113a06 100644 --- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/BinaryImporter.java +++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/BinaryImporter.java @@ -27,7 +27,7 @@ @AutoService(Importer.class) public class BinaryImporter extends AbstractTreeDataImporter { - private static final String[] EXTENSIONS = {"biidm", "bin", "iidm.bin"}; + private static final String[] EXTENSIONS = {"biidm", "bin"}; @Override protected String[] getExtensions() { diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/JsonImporter.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/JsonImporter.java index 92eda22af8a..25100ed9ca4 100644 --- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/JsonImporter.java +++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/JsonImporter.java @@ -28,7 +28,7 @@ @AutoService(Importer.class) public class JsonImporter extends AbstractTreeDataImporter { - private static final String[] EXTENSIONS = {"jiidm", "json", "iidm.json"}; + private static final String[] EXTENSIONS = {"jiidm", "json"}; @Override protected String[] getExtensions() { diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/XMLImporter.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/XMLImporter.java index 0d50956f6f0..f1910f38716 100644 --- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/XMLImporter.java +++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/XMLImporter.java @@ -34,7 +34,7 @@ public class XMLImporter extends AbstractTreeDataImporter { private static final Logger LOGGER = LoggerFactory.getLogger(XMLImporter.class); - private static final String[] EXTENSIONS = {"xiidm", "iidm", "xml", "iidm.xml"}; + private static final String[] EXTENSIONS = {"xiidm", "iidm", "xml"}; private static final Supplier XML_INPUT_FACTORY_SUPPLIER = Suppliers.memoize(XMLInputFactory::newInstance); diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ConversionTest.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ConversionTest.java new file mode 100644 index 00000000000..d381a90e247 --- /dev/null +++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ConversionTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.serde; + +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import com.powsybl.commons.config.InMemoryPlatformConfig; +import com.powsybl.iidm.network.ImportConfig; +import com.powsybl.iidm.network.tools.ConversionTool; +import com.powsybl.tools.CommandLineTools; +import com.powsybl.tools.test.AbstractToolTest; +import org.apache.commons.compress.archivers.zip.ZipFile; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Nicolas Rol {@literal } + */ +class ConversionTest { + + protected FileSystem fileSystem; + + protected InMemoryPlatformConfig platformConfig; + + private CommandLineTools tools; + + @BeforeEach + public void setUp() { + fileSystem = Jimfs.newFileSystem(Configuration.unix()); + platformConfig = new InMemoryPlatformConfig(fileSystem); + tools = new CommandLineTools(Collections.singletonList(createConversionTool())); + } + + private ConversionTool createConversionTool() { + return new ConversionTool() { + + @Override + protected ImportConfig createImportConfig() { + return ImportConfig.load(platformConfig); + } + }; + } + + @Test + void testConversionZip() throws IOException { + // Prepare the firectory and file + Files.createDirectory(fileSystem.getPath("/tmp")); + Files.copy(Objects.requireNonNull(getClass().getResourceAsStream("/slackTerminal.xml")), fileSystem.getPath("/tmp/foo.xiidm")); + + // Prepare the command + String[] commandLine = new String[] { + "convert-network", + "--input-file", "/tmp/foo.xiidm", + "--output-format", "XIIDM", + "--output-file", "/tmp/bar.zip" + }; + + // Assert the command is successful + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ByteArrayOutputStream berr = new ByteArrayOutputStream(); + int status = AbstractToolTest.runCommand(commandLine, bout, berr, tools, fileSystem); + + // Assert the command worked + assertEquals(0, status); + assertEquals("Generating file /tmp/bar.zip:bar.xiidm..." + System.lineSeparator(), + bout.toString(StandardCharsets.UTF_8)); + assertEquals("", berr.toString(StandardCharsets.UTF_8)); + + // Assert the right files are created + Path zipFilePath = fileSystem.getPath("/tmp/bar.zip"); + assertTrue(Files.isRegularFile(zipFilePath)); + try (ZipFile zipFile = ZipFile.builder() + .setSeekableByteChannel(Files.newByteChannel(zipFilePath)) + .get()) { + assertNotNull(zipFile.getEntry("bar.xiidm")); + } catch (IOException e) { + fail(); + } + } +} diff --git a/matpower/matpower-converter/src/main/java/com/powsybl/matpower/converter/MatpowerImporter.java b/matpower/matpower-converter/src/main/java/com/powsybl/matpower/converter/MatpowerImporter.java index 40ca6a38e3a..6f6c97274c7 100644 --- a/matpower/matpower-converter/src/main/java/com/powsybl/matpower/converter/MatpowerImporter.java +++ b/matpower/matpower-converter/src/main/java/com/powsybl/matpower/converter/MatpowerImporter.java @@ -516,7 +516,7 @@ private static boolean reactiveLimitsAreOk(double minQ, double maxQ) { @Override public boolean exists(ReadOnlyDataSource dataSource) { try { - return dataSource.exists(null, MatpowerConstants.EXT); + return dataSource.isDataExtension(MatpowerConstants.EXT) && dataSource.exists(null, MatpowerConstants.EXT); } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/powerfactory/powerfactory-converter/src/main/java/com/powsybl/powerfactory/converter/PowerFactoryImporter.java b/powerfactory/powerfactory-converter/src/main/java/com/powsybl/powerfactory/converter/PowerFactoryImporter.java index c3aaf1b2bf7..5b20a9d0269 100644 --- a/powerfactory/powerfactory-converter/src/main/java/com/powsybl/powerfactory/converter/PowerFactoryImporter.java +++ b/powerfactory/powerfactory-converter/src/main/java/com/powsybl/powerfactory/converter/PowerFactoryImporter.java @@ -64,7 +64,7 @@ public String getComment() { private Optional> findProjectLoader(ReadOnlyDataSource dataSource) { for (PowerFactoryDataLoader studyCaseLoader : PowerFactoryDataLoader.find(StudyCase.class)) { try { - if (dataSource.exists(null, studyCaseLoader.getExtension())) { + if (dataSource.isDataExtension(studyCaseLoader.getExtension()) && dataSource.exists(null, studyCaseLoader.getExtension())) { return Optional.of(studyCaseLoader); } } catch (IOException e) { diff --git a/psse/psse-converter/src/main/java/com/powsybl/psse/converter/PsseImporter.java b/psse/psse-converter/src/main/java/com/powsybl/psse/converter/PsseImporter.java index ef1fecaeec0..b256104154d 100644 --- a/psse/psse-converter/src/main/java/com/powsybl/psse/converter/PsseImporter.java +++ b/psse/psse-converter/src/main/java/com/powsybl/psse/converter/PsseImporter.java @@ -83,7 +83,7 @@ public boolean exists(ReadOnlyDataSource dataSource) { private String findExtension(ReadOnlyDataSource dataSource) throws IOException { for (String ext : EXTENSIONS) { - if (dataSource.exists(null, ext)) { + if (dataSource.isDataExtension(ext) && dataSource.exists(null, ext)) { return ext; } } diff --git a/tools-test/src/main/java/com/powsybl/tools/test/AbstractToolTest.java b/tools-test/src/main/java/com/powsybl/tools/test/AbstractToolTest.java index 6ff033accef..5b3a37d8cf6 100644 --- a/tools-test/src/main/java/com/powsybl/tools/test/AbstractToolTest.java +++ b/tools-test/src/main/java/com/powsybl/tools/test/AbstractToolTest.java @@ -137,6 +137,17 @@ protected void assertCommandMatchTextOrRegex(String[] args, int expectedStatus, private void assertCommand(String[] args, int expectedStatus, String expectedOut, String expectedErr, BiConsumer comparisonFunction) { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ByteArrayOutputStream berr = new ByteArrayOutputStream(); + int status = runCommand(args, bout, berr, tools, fileSystem); + assertEquals(expectedStatus, status); + if (expectedOut != null) { + assertMatches(expectedOut, bout, comparisonFunction); + } + if (expectedErr != null) { + assertMatches(expectedErr, berr, comparisonFunction); + } + } + + public static int runCommand(String[] args, ByteArrayOutputStream bout, ByteArrayOutputStream berr, CommandLineTools tools, FileSystem fileSystem) { int status; try (PrintStream out = new PrintStream(bout); PrintStream err = new PrintStream(berr); @@ -173,13 +184,7 @@ public ComputationManager createLongTimeExecutionComputationManager(CommandLine } }); } - assertEquals(expectedStatus, status); - if (expectedOut != null) { - assertMatches(expectedOut, bout, comparisonFunction); - } - if (expectedErr != null) { - assertMatches(expectedErr, berr, comparisonFunction); - } + return status; } @Test diff --git a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteImporter.java b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteImporter.java index 2f9db7339ca..edb2e9b4445 100644 --- a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteImporter.java +++ b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteImporter.java @@ -951,7 +951,7 @@ public List getParameters() { private String findExtension(ReadOnlyDataSource dataSource, boolean throwException) throws IOException { for (String ext : EXTENSIONS) { - if (dataSource.exists(null, ext)) { + if (dataSource.isDataExtension(ext) && dataSource.exists(null, ext)) { return ext; } }