From e9f21ae22e029f4cabd0866cbc0cab397a18e3ee Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Wed, 2 Jul 2025 15:55:19 +0200 Subject: [PATCH 1/6] Improved error messages when reading and validating an invalid grid --- CHANGELOG.md | 1 + .../io/source/csv/CsvDataSource.java | 58 +++++++++++------ .../io/source/csv/CsvIdCoordinateSource.java | 2 +- .../io/source/csv/CsvWeatherSource.java | 10 +-- .../java/edu/ie3/datamodel/utils/Try.java | 14 ++++ .../GridContainerValidationUtils.java | 44 ++++++------- .../validation/UniquenessValidationUtils.java | 65 ++++++++++++------- 7 files changed, 123 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7593a97d..7353a7834 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Updated dependabot workflow and added CODEOWNERS [#1328](https://github.com/ie3-institute/PowerSystemDataModel/issues/1328) - Extend azimuth angle range to [-180°, 180°] for PV inputs [#1330](https://github.com/ie3-institute/PowerSystemDataModel/issues/1330) +- Improved error messages when reading and validating an invalid grid [#1354](https://github.com/ie3-institute/PowerSystemDataModel/issues/1354) ## [7.0.0] - 2025-05-08 diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java index 78aa77f75..2e8dc614d 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java @@ -79,8 +79,19 @@ public Optional> getSourceFields(Class entityClass */ public Optional> getSourceFields(Path filePath) throws SourceException { try (BufferedReader reader = connector.initReader(filePath)) { - return Optional.of( - Arrays.stream(parseCsvRow(reader.readLine(), csvSep)).collect(Collectors.toSet())); + String line = reader.readLine(); + String[] headline = parseCsvRow(line, csvSep); + + if (headline.length <= 1) { + throw new SourceException( + "The given file has less than two columns! (Used separator '" + + csvSep + + "' on headline '" + + line + + "')"); + } + + return Optional.of(Arrays.stream(headline).collect(Collectors.toSet())); } catch (FileNotFoundException e) { // A file not existing can be acceptable in many cases, and is handled elsewhere. log.debug("The source for the given entity couldn't be found! Cause: {}", e.getMessage()); @@ -208,36 +219,40 @@ protected Set getTimeSeriesFilePaths(Pattern pattern) { */ protected Map buildFieldsToAttributes( final String csvRow, final String[] headline) throws SourceException { - - TreeMap insensitiveFieldsToAttributes = - new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - + // parse row String[] fieldVals = parseCsvRow(csvRow, csvSep); - insensitiveFieldsToAttributes.putAll( - IntStream.range(0, Math.min(fieldVals.length, headline.length)) - .boxed() - .collect( - Collectors.toMap( - k -> StringUtils.snakeCaseToCamelCase(headline[k]), v -> fieldVals[v]))); + // check if the number row elements matched the number of headline elements if (fieldVals.length != headline.length) { + String headlineElements = "['" + String.join("', '", headline) + "']"; + String parsedRow = "['" + String.join("', '", fieldVals) + "']"; + throw new SourceException( "The size of the headline (" + headline.length + ") does not fit to the size of the attribute fields (" + fieldVals.length + ").\nHeadline: " - + String.join(", ", headline) - + "\nRow: " - + csvRow.trim() + + headlineElements + + "\nParsed row: " + + parsedRow + ".\nPlease check:" - + "\n - is the csv separator in the file matching the separator provided in the constructor ('" + + "\n - is the csv separator in the row matching the provided separator '" + csvSep - + "')" + + "'" + "\n - does the number of columns match the number of headline fields " + "\n - are you using a valid RFC 4180 formatted csv row?"); } + TreeMap insensitiveFieldsToAttributes = + new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + insensitiveFieldsToAttributes.putAll( + IntStream.range(0, Math.min(fieldVals.length, headline.length)) + .boxed() + .collect( + Collectors.toMap( + k -> StringUtils.snakeCaseToCamelCase(headline[k]), v -> fieldVals[v]))); + if (insensitiveFieldsToAttributes.size() != fieldVals.length) { throw new SourceException( "There might be duplicate headline elements.\nHeadline: " @@ -298,7 +313,9 @@ protected Try>, SourceException> buildStreamWithField // is wanted to avoid a lock on the file), but this causes a closing of the stream as well. // As we still want to consume the data at other places, we start a new stream instead of // returning the original one - return csvRowFieldValueMapping(reader, headline); + return csvRowFieldValueMapping(reader, headline, filePath.getFileName()) + .transformF( + e -> new SourceException("The file '" + filePath + "' could not be parsed.", e)); } catch (FileNotFoundException e) { if (allowFileNotExisting) { log.warn("Unable to find file '{}': {}", filePath, e.getMessage()); @@ -324,10 +341,11 @@ private Try getFilePath(Class entityCla * * @param reader for the file * @param headline of the file + * @param fileName the name of the file, that is read * @return a list of mapping */ protected Try>, SourceException> csvRowFieldValueMapping( - BufferedReader reader, String[] headline) { + BufferedReader reader, String[] headline, Path fileName) { return Try.scanStream( reader .lines() @@ -337,7 +355,7 @@ protected Try>, SourceException> csvRowFieldValueMapp Try.of( () -> buildFieldsToAttributes(csvRow, headline), SourceException.class)), - "Map") + fileName.toString()) .transform( stream -> stream.filter(map -> !map.isEmpty()), e -> new SourceException("Parsing csv row failed.", e)); diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvIdCoordinateSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvIdCoordinateSource.java index 199a4925d..26038ee55 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvIdCoordinateSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvIdCoordinateSource.java @@ -209,7 +209,7 @@ private Collection getCoordinatesInBoundingBox( // is wanted to avoid a lock on the file), but this causes a closing of the stream as well. // As we still want to consume the data at other places, we start a new stream instead of // returning the original one - return dataSource.csvRowFieldValueMapping(reader, headline); + return dataSource.csvRowFieldValueMapping(reader, headline, filePath.getFileName()); } catch (IOException e) { return Failure.of( new SourceException("Cannot read the file for coordinate id to coordinate mapping.", e)); diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java index ab565db80..803fd6c26 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java @@ -177,9 +177,11 @@ private Map> readWeatherTimeSeries( this::buildWeatherValue; /* Reading in weather time series */ for (CsvIndividualTimeSeriesMetaInformation data : weatherMetaInformation) { + Path path = data.getFullFilePath(); + // we need a reader for each file - try (BufferedReader reader = connector.initReader(data.getFullFilePath())) { - buildStreamWithFieldsToAttributesMap(reader) + try (BufferedReader reader = connector.initReader(path)) { + buildStreamWithFieldsToAttributesMap(reader, path.getFileName()) .getOrThrow() .map(fieldToValueFunction) .flatMap(Optional::stream) @@ -227,7 +229,7 @@ private Map> readWeatherTimeSeries( } private Try>, SourceException> buildStreamWithFieldsToAttributesMap( - BufferedReader bufferedReader) throws ValidationException { + BufferedReader bufferedReader, Path fileName) throws ValidationException { Class entityClass = TimeBasedValue.class; try (BufferedReader reader = bufferedReader) { @@ -240,7 +242,7 @@ private Try>, SourceException> buildStreamWithFieldsT // is wanted to avoid a lock on the file), but this causes a closing of the stream as well. // As we still want to consume the data at other places, we start a new stream instead of // returning the original one - return dataSource.csvRowFieldValueMapping(reader, headline); + return dataSource.csvRowFieldValueMapping(reader, headline, fileName); } catch (IOException e) { return Failure.of( new SourceException( diff --git a/src/main/java/edu/ie3/datamodel/utils/Try.java b/src/main/java/edu/ie3/datamodel/utils/Try.java index ffe006407..7ff103cc8 100644 --- a/src/main/java/edu/ie3/datamodel/utils/Try.java +++ b/src/main/java/edu/ie3/datamodel/utils/Try.java @@ -67,6 +67,20 @@ public static Try ofVoid( } } + /** + * Method to create multiple {@link Try} object easily. + * + * @param suppliers that either return no data or throw an exception + * @param clazz class of the exception + * @return a collection of try objects + * @param type of exception that could be thrown + */ + @SafeVarargs + public static Collection> ofVoids( + Class clazz, VoidSupplier... suppliers) { + return Arrays.stream(suppliers).map(supplier -> ofVoid(supplier, clazz)).toList(); + } + /** * Method to create a {@link Try} object easily. * diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/GridContainerValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/GridContainerValidationUtils.java index 7d9e9b26b..471c83567 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/GridContainerValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/GridContainerValidationUtils.java @@ -99,10 +99,15 @@ private GridContainerValidationUtils() { /* sanity check to ensure uniqueness */ List> exceptions = new ArrayList<>(); - exceptions.add( - Try.ofVoid( - () -> checkAssetUniqueness(rawGridElements.allEntitiesAsList()), - DuplicateEntitiesException.class)); + exceptions.addAll( + Try.ofVoids( + DuplicateEntitiesException.class, + () -> checkAssetUniqueness(rawGridElements.getNodes()), + () -> checkAssetUniqueness(rawGridElements.getLines()), + () -> checkAssetUniqueness(rawGridElements.getSwitches()), + () -> checkAssetUniqueness(rawGridElements.getTransformer2Ws()), + () -> checkAssetUniqueness(rawGridElements.getTransformer3Ws()), + () -> checkAssetUniqueness(rawGridElements.getMeasurementUnits()))); /* Checking nodes */ Set nodes = rawGridElements.getNodes(); @@ -287,10 +292,6 @@ protected static Try checkConnectivity( /* sanity check to ensure uniqueness */ List> exceptions = new ArrayList<>(); - exceptions.add( - Try.ofVoid( - () -> checkAssetUniqueness(systemParticipants.allEntitiesAsList()), - DuplicateEntitiesException.class)); exceptions.addAll(checkSystemParticipants(systemParticipants.getBmPlants(), nodes)); exceptions.addAll(checkSystemParticipants(systemParticipants.getChpPlants(), nodes)); @@ -306,8 +307,8 @@ protected static Try checkConnectivity( } /** - * Checks the validity of specific system participant. Moreover, it checks, if the systems are - * connected to a node that is not in the provided set + * Checks the validity and uniqueness of specific system participant. Moreover, it checks, if the + * systems are connected to a node that is not in the provided set * * @param participants a set of specific system participants * @param nodes Set of already known nodes @@ -316,18 +317,17 @@ protected static Try checkConnectivity( */ protected static List> checkSystemParticipants( Set participants, Set nodes) { - return participants.stream() - .map( - entity -> { - List> exceptions = new ArrayList<>(); - - exceptions.add(checkNodeAvailability(entity, nodes)); - exceptions.addAll(SystemParticipantValidationUtils.check(entity)); - - return exceptions; - }) - .flatMap(List::stream) - .toList(); + List> exceptions = new ArrayList<>(); + exceptions.add( + Try.ofVoid(() -> checkAssetUniqueness(participants), DuplicateEntitiesException.class)); + + participants.forEach( + participant -> { + exceptions.add(checkNodeAvailability(participant, nodes)); + exceptions.addAll(SystemParticipantValidationUtils.check(participant)); + }); + + return exceptions; } /** diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java index cdf980fad..031ee0aad 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java @@ -24,10 +24,11 @@ public class UniquenessValidationUtils extends ValidationUtils { // default field set supplier - protected static final FieldSetSupplier uuidFieldSupplier = + protected static final FieldSetSupplier uuidFieldSupplier = entity -> Set.of(entity.getUuid()); - protected static final FieldSetSupplier idFieldSupplier = e -> Set.of(e.getId()); - protected static final FieldSetSupplier resultFieldSupplier = + protected static final FieldSetSupplier idFieldSupplier = + e -> Set.of(e.getId()); + protected static final FieldSetSupplier resultFieldSupplier = entity -> Set.of(entity.getTime(), entity.getInputModel()); protected static final FieldSetSupplier mappingFieldSupplier = entity -> Set.of(entity.getAsset()); @@ -44,9 +45,10 @@ public class UniquenessValidationUtils extends ValidationUtils { * @param entities to be checked * @throws DuplicateEntitiesException if uniqueness is violated */ - public static void checkUniqueEntities(Collection entities) + @SuppressWarnings("unchecked") + public static void checkUniqueEntities(Collection entities) throws DuplicateEntitiesException { - checkUniqueness(entities, uuidFieldSupplier).getOrThrow(); + checkUniqueness(entities, (FieldSetSupplier) uuidFieldSupplier).getOrThrow(); } /** @@ -55,13 +57,14 @@ public static void checkUniqueEntities(Collection entiti * @param entities to be checked * @throws DuplicateEntitiesException if uniqueness is violated */ - public static void checkAssetUniqueness(Collection entities) + @SuppressWarnings("unchecked") + public static void checkAssetUniqueness(Collection entities) throws DuplicateEntitiesException { List exceptions = Try.getExceptions( Try.ofVoid(() -> checkUniqueEntities(entities), DuplicateEntitiesException.class), - checkUniqueness(entities, idFieldSupplier)); + checkUniqueness(entities, (FieldSetSupplier) idFieldSupplier)); if (!exceptions.isEmpty()) { throw new DuplicateEntitiesException("AssetInput", exceptions); @@ -74,9 +77,10 @@ public static void checkAssetUniqueness(Collection entitie * @param entities to be checked * @throws DuplicateEntitiesException if uniqueness is violated */ - public static void checkResultUniqueness(Collection entities) + @SuppressWarnings("unchecked") + public static void checkResultUniqueness(Collection entities) throws DuplicateEntitiesException { - checkUniqueness(entities, resultFieldSupplier).getOrThrow(); + checkUniqueness(entities, (FieldSetSupplier) resultFieldSupplier).getOrThrow(); } /** @@ -122,33 +126,46 @@ public static void checkWeatherUniqueness(Collection Try checkUniqueness( Collection entities, FieldSetSupplier supplier) { + Optional option = entities.stream().findAny().map(e -> e.getClass().getSimpleName()); + if (option.isPresent()) { + return checkUniqueness(entities, supplier, option.get()); + } else { + return Try.Success.empty(); + } + } + + /** + * Checking the uniqueness for a given {@link Entity}. + * + * @param entities to be checked + * @param supplier for the field set + * @param entityName name of the class of the entity + * @return a try object + * @param type of entity + */ + private static Try checkUniqueness( + Collection entities, FieldSetSupplier supplier, String entityName) { if (entities.size() < 2) { return Success.empty(); } - return entities.stream() - .findAny() - .map( - entity -> { - List> elements = entities.stream().map(supplier::getFieldSets).toList(); - Set> uniqueElements = new HashSet<>(elements); - - return Try.ofVoid( - elements.size() != uniqueElements.size(), - () -> buildDuplicationException(entity.getClass(), elements)); - }) - .orElse(Success.empty()); + List> elements = entities.stream().map(supplier::getFieldSets).toList(); + Set> uniqueElements = new HashSet<>(elements); + + return Try.ofVoid( + elements.size() != uniqueElements.size(), + () -> buildDuplicationException(entityName, elements)); } /** * Method for building a {@link DuplicateEntitiesException}. * - * @param entityClass class of the entity + * @param entityClass name of the class of the entity * @param notUniqueElements list of not unique elements * @return a {@link DuplicateEntitiesException} */ protected static DuplicateEntitiesException buildDuplicationException( - Class entityClass, List> notUniqueElements) { + String entityClass, List> notUniqueElements) { String fieldName = notUniqueElements.get(0).stream() .map(f -> f.getClass().getSimpleName()) @@ -167,7 +184,7 @@ protected static DuplicateEntitiesException buildDuplicationException( return new DuplicateEntitiesException( "'" - + entityClass.getSimpleName() + + entityClass + "' entities with duplicated " + fieldName + " key, but different field " From 28756ae54ed1ca83de7e3f9bf45b4c0ca3cfe6bf Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Thu, 3 Jul 2025 14:16:09 +0200 Subject: [PATCH 2/6] Improving the messages and the format of exceptions. --- .../DuplicateEntitiesException.java | 4 +- .../exceptions/FailedValidationException.java | 3 +- .../exceptions/InvalidEntityException.java | 5 +- .../datamodel/exceptions/SourceException.java | 2 +- .../io/processor/ProcessorProvider.java | 36 +++++------ .../ie3/datamodel/io/source/EntitySource.java | 21 +++---- .../datamodel/io/source/GraphicSource.java | 9 ++- .../datamodel/io/source/RawGridSource.java | 23 ++++--- .../io/source/ResultEntitySource.java | 4 +- .../io/source/SystemParticipantSource.java | 28 ++++----- .../datamodel/io/source/ThermalSource.java | 4 +- .../io/source/TimeSeriesMappingSource.java | 8 ++- .../ie3/datamodel/io/source/TypeSource.java | 4 +- .../datamodel/io/source/WeatherSource.java | 5 +- .../io/source/csv/CsvDataSource.java | 31 +++++---- .../io/source/csv/CsvIdCoordinateSource.java | 3 +- .../csv/CsvJointGridContainerSource.java | 3 +- .../io/source/csv/CsvLoadProfileSource.java | 4 +- .../io/source/csv/CsvTimeSeriesSource.java | 6 +- .../io/source/csv/CsvWeatherSource.java | 2 +- .../ie3/datamodel/utils/ExceptionUtils.java | 63 +++++++------------ .../java/edu/ie3/datamodel/utils/Try.java | 36 ++++++----- .../source/EnergyManagementSourceTest.groovy | 8 +-- .../io/source/EntitySourceTest.groovy | 3 +- .../source/TimeSeriesMappingSourceTest.groovy | 11 ++-- .../io/source/csv/CsvDataSourceTest.groovy | 23 +++++-- .../io/source/csv/CsvGraphicSourceTest.groovy | 10 +-- .../io/source/csv/CsvRawGridSourceTest.groovy | 7 ++- .../csv/CsvSystemParticipantSourceTest.groovy | 25 ++++++-- .../edu/ie3/datamodel/utils/TryTest.groovy | 9 +-- ...ystemParticipantValidationUtilsTest.groovy | 42 +++++-------- .../UniquenessValidationUtilsTest.groovy | 5 +- .../validation/ValidationUtilsTest.groovy | 6 +- 33 files changed, 222 insertions(+), 231 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java b/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java index f2a46bce0..eee2942f1 100644 --- a/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java +++ b/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java @@ -19,7 +19,7 @@ public DuplicateEntitiesException( this( "The following exception(s) occurred while checking the uniqueness of '" + entityName - + "' entities: " - + ExceptionUtils.getMessages(exceptions)); + + "' entities: \n" + + ExceptionUtils.combineExceptions(exceptions)); } } diff --git a/src/main/java/edu/ie3/datamodel/exceptions/FailedValidationException.java b/src/main/java/edu/ie3/datamodel/exceptions/FailedValidationException.java index b1cc6386b..4b10acc06 100644 --- a/src/main/java/edu/ie3/datamodel/exceptions/FailedValidationException.java +++ b/src/main/java/edu/ie3/datamodel/exceptions/FailedValidationException.java @@ -23,7 +23,6 @@ public FailedValidationException(String message) { /** @param exceptions List of exceptions, which must not be empty */ public FailedValidationException(List exceptions) { - super( - "Validation failed due to: \n" + ExceptionUtils.getMessages(exceptions), exceptions.get(0)); + super("Validation failed due to: " + ExceptionUtils.combineExceptions(exceptions)); } } diff --git a/src/main/java/edu/ie3/datamodel/exceptions/InvalidEntityException.java b/src/main/java/edu/ie3/datamodel/exceptions/InvalidEntityException.java index 744e08c25..162acd0b1 100644 --- a/src/main/java/edu/ie3/datamodel/exceptions/InvalidEntityException.java +++ b/src/main/java/edu/ie3/datamodel/exceptions/InvalidEntityException.java @@ -13,13 +13,12 @@ public class InvalidEntityException extends ValidationException { private static final long serialVersionUID = 809496087520306374L; public InvalidEntityException(String faultDescription, UniqueEntity invalidEntity) { - super("Entity is invalid because of: \n" + faultDescription + " [" + invalidEntity + "]"); + super("Entity is invalid because of: " + faultDescription + " [" + invalidEntity + "]"); } public InvalidEntityException( String faultDescription, Throwable cause, UniqueEntity invalidEntity) { - super( - "Entity is invalid because of: \n" + faultDescription + " [" + invalidEntity + "]", cause); + super("Entity is invalid because of: " + faultDescription + " [" + invalidEntity + "]", cause); } public InvalidEntityException(String message, Throwable cause) { diff --git a/src/main/java/edu/ie3/datamodel/exceptions/SourceException.java b/src/main/java/edu/ie3/datamodel/exceptions/SourceException.java index 2a5a19030..623dc801b 100644 --- a/src/main/java/edu/ie3/datamodel/exceptions/SourceException.java +++ b/src/main/java/edu/ie3/datamodel/exceptions/SourceException.java @@ -32,6 +32,6 @@ public SourceException(final String message) { } public SourceException(String message, List exceptions) { - super(message + " " + ExceptionUtils.getMessages(exceptions), exceptions.get(0)); + super(message + "\n " + ExceptionUtils.combineExceptions(exceptions)); } } diff --git a/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java b/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java index f1858c44b..9cb9ee5a0 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java @@ -6,7 +6,6 @@ package edu.ie3.datamodel.io.processor; import edu.ie3.datamodel.exceptions.EntityProcessorException; -import edu.ie3.datamodel.exceptions.FailureException; import edu.ie3.datamodel.exceptions.ProcessorProviderException; import edu.ie3.datamodel.io.processor.input.InputEntityProcessor; import edu.ie3.datamodel.io.processor.result.ResultEntityProcessor; @@ -313,25 +312,22 @@ public static Collection> allResultEntityProce Value, Value>> allTimeSeriesProcessors() throws EntityProcessorException { - try { - return Try.scanStream( - TimeSeriesProcessor.eligibleKeys.stream() - .map( - key -> - Try.of( - () -> - new TimeSeriesProcessor<>( - (Class, Value, Value>>) - key.getTimeSeriesClass(), - (Class>) key.getEntryClass(), - (Class) key.getValueClass()), - EntityProcessorException.class)), - "list of processors") - .getOrThrow() - .collect(Collectors.toMap(TimeSeriesProcessor::getRegisteredKey, Function.identity())); - } catch (FailureException e) { - throw new EntityProcessorException(e.getCause()); - } + return Try.scanStream( + TimeSeriesProcessor.eligibleKeys.stream() + .map( + key -> + Try.of( + () -> + new TimeSeriesProcessor<>( + (Class, Value, Value>>) + key.getTimeSeriesClass(), + (Class>) key.getEntryClass(), + (Class) key.getValueClass()), + EntityProcessorException.class)), + "time series processors", + EntityProcessorException::new) + .getOrThrow() + .collect(Collectors.toMap(TimeSeriesProcessor::getRegisteredKey, Function.identity())); } @SuppressWarnings("unchecked cast") diff --git a/src/main/java/edu/ie3/datamodel/io/source/EntitySource.java b/src/main/java/edu/ie3/datamodel/io/source/EntitySource.java index be0cdea31..726a35279 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/EntitySource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/EntitySource.java @@ -204,14 +204,12 @@ protected static Stream getEntities( * @return a stream of the entity data wrapped in a {@link Try} */ protected static Stream> buildEntityData( - Class entityClass, DataSource dataSource) { - return Try.of(() -> dataSource.getSourceData(entityClass), SourceException.class) - .convert( - data -> - data.map( - fieldsToAttributes -> - new Try.Success<>(new EntityData(fieldsToAttributes, entityClass))), - exception -> Stream.of(Failure.of(exception))); + Class entityClass, DataSource dataSource) throws SourceException { + Stream> dataStream = + Try.of(() -> dataSource.getSourceData(entityClass), SourceException.class).getOrThrow(); + + return dataStream.map( + fieldsToAttributes -> new Try.Success<>(new EntityData(fieldsToAttributes, entityClass))); } /** @@ -227,7 +225,8 @@ protected static Stream> buildEntityData( protected static Stream> buildEntityData( Class entityClass, DataSource dataSource, - WrappedFunction converter) { + WrappedFunction converter) + throws SourceException { return buildEntityData(entityClass, dataSource).map(converter); } @@ -356,9 +355,7 @@ Function, R> enrichFunction( */ protected static Stream unpack( Stream> inputStream, Class clazz) throws SourceException { - return Try.scanStream(inputStream, clazz.getSimpleName()) - .transformF(SourceException::new) - .getOrThrow(); + return Try.scanStream(inputStream, clazz.getSimpleName(), SourceException::new).getOrThrow(); } /** diff --git a/src/main/java/edu/ie3/datamodel/io/source/GraphicSource.java b/src/main/java/edu/ie3/datamodel/io/source/GraphicSource.java index 339f3f638..d92336aa2 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/GraphicSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/GraphicSource.java @@ -59,8 +59,8 @@ public void validate() throws ValidationException { Stream.of( validate(NodeGraphicInput.class, dataSource, nodeGraphicInputFactory), validate(LineGraphicInput.class, dataSource, lineGraphicInputFactory)), - "Validation") - .transformF(FailedValidationException::new) + "Validation", + FailedValidationException::new) .getOrThrow(); } @@ -95,12 +95,11 @@ public GraphicElements getGraphicElements(Map nodes, Map, SourceException> lineGraphics = Try.of(() -> getLineGraphicInput(lines), SourceException.class); - List exceptions = Try.getExceptions(List.of(nodeGraphics, lineGraphics)); + List exceptions = Try.getExceptions(nodeGraphics, lineGraphics); if (!exceptions.isEmpty()) { throw new GraphicSourceException( - exceptions.size() + " error(s) occurred while initializing graphic elements. ", - exceptions); + "Some exception(s) occurred while initializing graphic elements. ", exceptions); } else { // if everything is fine, return a GraphicElements instance // getOrThrow should not throw an exception in this context, because all exception are diff --git a/src/main/java/edu/ie3/datamodel/io/source/RawGridSource.java b/src/main/java/edu/ie3/datamodel/io/source/RawGridSource.java index 46d9432b5..3d5f5e2ef 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/RawGridSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/RawGridSource.java @@ -5,11 +5,19 @@ */ package edu.ie3.datamodel.io.source; -import edu.ie3.datamodel.exceptions.*; +import edu.ie3.datamodel.exceptions.FailedValidationException; +import edu.ie3.datamodel.exceptions.RawGridException; +import edu.ie3.datamodel.exceptions.SourceException; +import edu.ie3.datamodel.exceptions.ValidationException; import edu.ie3.datamodel.io.factory.EntityData; import edu.ie3.datamodel.io.factory.input.*; -import edu.ie3.datamodel.models.input.*; -import edu.ie3.datamodel.models.input.connector.*; +import edu.ie3.datamodel.models.input.MeasurementUnitInput; +import edu.ie3.datamodel.models.input.NodeInput; +import edu.ie3.datamodel.models.input.OperatorInput; +import edu.ie3.datamodel.models.input.connector.LineInput; +import edu.ie3.datamodel.models.input.connector.SwitchInput; +import edu.ie3.datamodel.models.input.connector.Transformer2WInput; +import edu.ie3.datamodel.models.input.connector.Transformer3WInput; import edu.ie3.datamodel.models.input.connector.type.LineTypeInput; import edu.ie3.datamodel.models.input.connector.type.Transformer2WTypeInput; import edu.ie3.datamodel.models.input.connector.type.Transformer3WTypeInput; @@ -62,8 +70,8 @@ public void validate() throws ValidationException { validate(Transformer3WInput.class, dataSource, transformer3WInputFactory), validate(SwitchInput.class, dataSource, switchInputFactory), validate(MeasurementUnitInput.class, dataSource, measurementUnitInputFactory)), - "Validation") - .transformF(FailedValidationException::new) + "Validation", + FailedValidationException::new) .getOrThrow(); } @@ -146,12 +154,11 @@ public RawGridElements getGridData( Try.of(() -> getMeasurementUnits(operators, nodes), SourceException.class); List exceptions = - Try.getExceptions( - List.of(transformer2WInputs, transformer3WInputs, switches, measurementUnits)); + Try.getExceptions(transformer2WInputs, transformer3WInputs, switches, measurementUnits); if (!exceptions.isEmpty()) { throw new RawGridException( - exceptions.size() + " error(s) occurred while initializing raw grid. ", exceptions); + "Some exception(s) occurred while initializing raw grid.", exceptions); } else { /* build and return the grid if it is not empty */ // getOrThrow should not throw an exception in this context, because all exception are diff --git a/src/main/java/edu/ie3/datamodel/io/source/ResultEntitySource.java b/src/main/java/edu/ie3/datamodel/io/source/ResultEntitySource.java index d1889c4bd..1e555cc56 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/ResultEntitySource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/ResultEntitySource.java @@ -105,9 +105,7 @@ public void validate() throws ValidationException { validate(FlexOptionsResult.class, dataSource, flexOptionsResultFactory), validate(CongestionResult.class, dataSource, congestionResultFactory))); - Try.scanCollection(participantResults, Void.class) - .transformF(FailedValidationException::new) - .getOrThrow(); + Try.scanCollection(participantResults, Void.class, FailedValidationException::new).getOrThrow(); } /** diff --git a/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java b/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java index 48aba751e..dc240862a 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java @@ -110,8 +110,8 @@ public void validate() throws ValidationException { validate(StorageInput.class, dataSource, storageInputFactory), validate(WecInput.class, dataSource, wecInputFactory), validate(EvcsInput.class, dataSource, evcsInputFactory)), - "Validation") - .transformF(FailedValidationException::new) + "Validation", + FailedValidationException::new) .getOrThrow(); } @@ -212,22 +212,20 @@ public SystemParticipants getSystemParticipants( List exceptions = Try.getExceptions( - List.of( - fixedFeedInInputs, - pvInputs, - loads, - bmInputs, - storages, - wecInputs, - evs, - evcs, - chpInputs, - hpInputs)); + fixedFeedInInputs, + pvInputs, + loads, + bmInputs, + storages, + wecInputs, + evs, + evcs, + chpInputs, + hpInputs); if (!exceptions.isEmpty()) { throw new SystemParticipantsException( - exceptions.size() + " error(s) occurred while initializing system participants. ", - exceptions); + "Some exception(s) occurred while initializing system participants.", exceptions); } else { // if everything is fine, return a system participants container // getOrThrow should not throw an exception in this context, because all exception are diff --git a/src/main/java/edu/ie3/datamodel/io/source/ThermalSource.java b/src/main/java/edu/ie3/datamodel/io/source/ThermalSource.java index f8d73a0a7..bc955ff82 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/ThermalSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/ThermalSource.java @@ -65,8 +65,8 @@ public void validate() throws ValidationException { dataSource, domesticHotWaterStorageInputFactory), validate(ThermalHouseInput.class, dataSource, thermalHouseInputFactory)), - "Validation") - .transformF(FailedValidationException::new) + "Validation", + FailedValidationException::new) .getOrThrow(); } diff --git a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java index 15e5b63e4..eeb956b56 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java @@ -38,10 +38,12 @@ public void validate() throws ValidationException { * @return That mapping */ public Map getMapping() throws SourceException { - return Try.scanStream(getMappingSourceData().map(this::createMappingEntry), "MappingEntry") - .transform( - s -> s.collect(Collectors.toMap(MappingEntry::getAsset, MappingEntry::getTimeSeries)), + return Try.scanStream( + getMappingSourceData().map(this::createMappingEntry), + "MappingEntry", SourceException::new) + .transformS( + s -> s.collect(Collectors.toMap(MappingEntry::getAsset, MappingEntry::getTimeSeries))) .getOrThrow(); } diff --git a/src/main/java/edu/ie3/datamodel/io/source/TypeSource.java b/src/main/java/edu/ie3/datamodel/io/source/TypeSource.java index 16b2a9f4f..67f3ecd0b 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/TypeSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/TypeSource.java @@ -74,9 +74,7 @@ public void validate() throws ValidationException { validate(Transformer2WTypeInput.class, dataSource, transformer2WTypeInputFactory), validate(Transformer3WTypeInput.class, dataSource, transformer3WTypeInputFactory))); - Try.scanCollection(participantResults, Void.class) - .transformF(FailedValidationException::new) - .getOrThrow(); + Try.scanCollection(participantResults, Void.class, FailedValidationException::new).getOrThrow(); } /** diff --git a/src/main/java/edu/ie3/datamodel/io/source/WeatherSource.java b/src/main/java/edu/ie3/datamodel/io/source/WeatherSource.java index a7a056d85..94fdbd733 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/WeatherSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/WeatherSource.java @@ -170,8 +170,9 @@ protected List> buildTimeBasedValues( return factory.get( Try.from(data, () -> new SourceException("Missing data in: " + data))); }), - "TimeBasedValue") - .transform(Stream::toList, SourceException::new) + "TimeBasedValue", + SourceException::new) + .transformS(Stream::toList) .getOrThrow(); } } diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java index 2e8dc614d..6879b57eb 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java @@ -232,22 +232,22 @@ protected Map buildFieldsToAttributes( + headline.length + ") does not fit to the size of the attribute fields (" + fieldVals.length - + ").\nHeadline: " + + ").\n Headline fields: " + headlineElements - + "\nParsed row: " + + "\n Row values: " + parsedRow - + ".\nPlease check:" - + "\n - is the csv separator in the row matching the provided separator '" + + ".\n Please check:" + + "\n - is the csv separator in the row matching the provided separator '" + csvSep + "'" - + "\n - does the number of columns match the number of headline fields " - + "\n - are you using a valid RFC 4180 formatted csv row?"); + + "\n - does the number of columns match the number of headline fields " + + "\n - are you using a valid RFC 4180 formatted csv row?"); } TreeMap insensitiveFieldsToAttributes = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); insensitiveFieldsToAttributes.putAll( - IntStream.range(0, Math.min(fieldVals.length, headline.length)) + IntStream.range(0, headline.length) .boxed() .collect( Collectors.toMap( @@ -255,9 +255,9 @@ protected Map buildFieldsToAttributes( if (insensitiveFieldsToAttributes.size() != fieldVals.length) { throw new SourceException( - "There might be duplicate headline elements.\nHeadline: " - + String.join(", ", headline) - + ".\nPlease keep in mind that headlines are case-insensitive and underscores from snake case are ignored."); + "There might be duplicate headline elements.\nHeadline fields: ['" + + String.join("', '", headline) + + "'].\nPlease keep in mind that headlines are case-insensitive and underscores from snake case are ignored."); } return insensitiveFieldsToAttributes; @@ -313,9 +313,7 @@ protected Try>, SourceException> buildStreamWithField // is wanted to avoid a lock on the file), but this causes a closing of the stream as well. // As we still want to consume the data at other places, we start a new stream instead of // returning the original one - return csvRowFieldValueMapping(reader, headline, filePath.getFileName()) - .transformF( - e -> new SourceException("The file '" + filePath + "' could not be parsed.", e)); + return csvRowFieldValueMapping(reader, headline, filePath.getFileName()); } catch (FileNotFoundException e) { if (allowFileNotExisting) { log.warn("Unable to find file '{}': {}", filePath, e.getMessage()); @@ -355,9 +353,8 @@ protected Try>, SourceException> csvRowFieldValueMapp Try.of( () -> buildFieldsToAttributes(csvRow, headline), SourceException.class)), - fileName.toString()) - .transform( - stream -> stream.filter(map -> !map.isEmpty()), - e -> new SourceException("Parsing csv row failed.", e)); + fileName.toString(), + SourceException::new) + .transformS(stream -> stream.filter(map -> !map.isEmpty())); } } diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvIdCoordinateSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvIdCoordinateSource.java index 26038ee55..59c29d28c 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvIdCoordinateSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvIdCoordinateSource.java @@ -77,8 +77,7 @@ private Map setupIdToCoordinateMap() throws SourceException { fieldToValues -> new SimpleFactoryData(fieldToValues, IdCoordinateInput.class)) .map(factory::get)) - .flatMap( - s -> Try.scanStream(s, "Pair").transformF(SourceException::new)) + .flatMap(s -> Try.scanStream(s, "Pair", SourceException::new)) .getOrThrow() .toList(); diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvJointGridContainerSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvJointGridContainerSource.java index 2fd49c0f1..5796454a8 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvJointGridContainerSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvJointGridContainerSource.java @@ -89,8 +89,7 @@ public static JointGridContainer read( Try.getExceptions(rawGridElements, systemParticipants, graphicElements); if (!exceptions.isEmpty()) { - throw new SourceException( - exceptions.size() + " error(s) occurred while reading sources. ", exceptions); + throw new SourceException("Some exception(s) occurred while reading the grid.", exceptions); } else { // getOrThrow should not throw an exception in this context, because all exception are // filtered and thrown before diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvLoadProfileSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvLoadProfileSource.java index f3b271617..e17d07211 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvLoadProfileSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvLoadProfileSource.java @@ -116,8 +116,8 @@ protected LoadProfileTimeSeries buildLoadProfileTimeSeries( .buildStreamWithFieldsToAttributesMap(filePath, false) .flatMap( stream -> - Try.scanStream(stream.map(fieldToValueFunction), "LoadProfileEntry") - .transformF(SourceException::new)) + Try.scanStream( + stream.map(fieldToValueFunction), "LoadProfileEntry", SourceException::new)) .getOrThrow() .collect(Collectors.toSet()); diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSource.java index 4b5acd0ba..7b110711b 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSource.java @@ -166,8 +166,10 @@ protected IndividualTimeSeries buildIndividualTimeSeries( .buildStreamWithFieldsToAttributesMap(filePath, false) .flatMap( stream -> - Try.scanStream(stream.map(fieldToValueFunction), "TimeBasedValue") - .transformF(SourceException::new)); + Try.scanStream( + stream.map(fieldToValueFunction), + "TimeBasedValue", + SourceException::new)); return new IndividualTimeSeries<>( timeSeriesUuid, new HashSet<>(timeBasedValues.getOrThrow().toList())); } diff --git a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java index 803fd6c26..241442725 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/csv/CsvWeatherSource.java @@ -224,7 +224,7 @@ private Map> readWeatherTimeSeries( if (exceptions.isEmpty()) { return weatherTimeSeries; } else { - throw new SourceException("Due to: " + ExceptionUtils.getMessages(exceptions)); + throw new SourceException("Due to: " + ExceptionUtils.combineExceptions(exceptions)); } } diff --git a/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java b/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java index df8f03947..f700958bf 100644 --- a/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java @@ -5,11 +5,8 @@ */ package edu.ie3.datamodel.utils; -import edu.ie3.datamodel.models.Entity; -import java.util.Arrays; -import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; +import java.util.function.Function; public class ExceptionUtils { private ExceptionUtils() { @@ -22,45 +19,29 @@ private ExceptionUtils() { * @param exceptions list of exceptions * @return str containing the messages */ - public static String getMessages(List exceptions) { - return exceptions.stream() - .map(Throwable::getMessage) - .reduce("", (a, b) -> a + "\n " + b) - .replaceFirst("\n ", ""); - } + public static String combineExceptions(List exceptions) { + String messageSeparator = "\n "; - /** - * Creates a string containing multiple exception messages. - * - * @param exceptions list of exceptions - * @return str containing the messages - */ - public static String getFullMessages(List exceptions) { - return exceptions.stream() - .map(e -> e.getMessage() + printStackTrace(e.getStackTrace())) - .reduce("", (a, b) -> a + "\n " + b) - .replaceFirst("\n ", ""); - } + // function to convert an exception into a string + Function converter = + e -> { + String clazz = e.getClass().getName(); + String message = e.getMessage(); + Throwable cause = e.getCause(); - /** - * Combines multiple {@link Entity} into a string. - * - * @param entities to be combined - * @return a string - */ - public static String combine(Collection entities) { - return "{" + entities.stream().map(Entity::toString).collect(Collectors.joining(", ")) + "}"; - } + String res = clazz + ": " + message; - /** - * Method for combining {@link StackTraceElement}s. - * - * @param elements to be combined - * @return a string - */ - public static String printStackTrace(StackTraceElement... elements) { - return Arrays.stream(elements) - .map(StackTraceElement::toString) - .collect(Collectors.joining("\n ")); + if (cause != null) { + res += " Caused by: " + cause.getClass().getName() + ": " + cause.getMessage(); + } + + return res; + }; + + String messages = + exceptions.stream().map(converter).reduce("", (a, b) -> a + messageSeparator + b); + + // some formating + return messages.replaceAll("\n", "\n ").replaceFirst(messageSeparator, ""); } } diff --git a/src/main/java/edu/ie3/datamodel/utils/Try.java b/src/main/java/edu/ie3/datamodel/utils/Try.java index 7ff103cc8..9becdda01 100644 --- a/src/main/java/edu/ie3/datamodel/utils/Try.java +++ b/src/main/java/edu/ie3/datamodel/utils/Try.java @@ -7,7 +7,6 @@ import static java.util.stream.Collectors.partitioningBy; -import edu.ie3.datamodel.exceptions.FailureException; import edu.ie3.datamodel.exceptions.TryException; import java.util.*; import java.util.function.BiFunction; @@ -35,7 +34,7 @@ public static Try of(TrySupplier supplier, return new Success<>(supplier.get()); } catch (Exception e) { // this is necessary because we only want to catch exceptions that are of type E - if (e.getClass().isAssignableFrom(clazz)) { + if (clazz.isAssignableFrom(e.getClass())) { return new Failure<>((E) e); } else { throw new TryException("Wrongly caught exception: ", e); @@ -133,8 +132,7 @@ public static Try from( * @param tries collection of {@link Try} objects * @return a list of {@link Exception}'s */ - public static List getExceptions( - Collection> tries) { + public static List getExceptions(Collection> tries) { return getExceptions(tries.stream()); } @@ -144,7 +142,7 @@ public static List getExceptions( * @param tries stream of {@link Try} objects * @return a list of {@link Exception}'s */ - public static List getExceptions(Stream> tries) { + public static List getExceptions(Stream> tries) { return tries.filter(Try::isFailure).map(t -> ((Failure) t).get()).toList(); } @@ -163,13 +161,15 @@ public static List getExceptions(Try * Method to scan a collection of {@link Try} objects for {@link Failure}'s. * * @param c collection of {@link Try} objects - * @param typeOfData type of data + * @param typeOfData information added to exception to help identify the place, that needs to be + * fixed + * @param exceptionBuilder function to build the failure message * @return a {@link Success} if no {@link Failure}'s are found in the collection * @param type of data */ - public static Try, FailureException> scanCollection( - Collection> c, Class typeOfData) { - return scanStream(c.stream(), typeOfData.getSimpleName()) + public static Try, RE> scanCollection( + Collection> c, Class typeOfData, Function exceptionBuilder) { + return scanStream(c.stream(), typeOfData.getSimpleName(), exceptionBuilder) .transformS(stream -> stream.collect(Collectors.toSet())); } @@ -177,11 +177,14 @@ public static Try, FailureException> scanCollect * Method to scan a stream of {@link Try} objects for {@link Failure}'s. * * @param stream of {@link Try} objects + * @param typeOfData information added to exception to help identify the place, that needs to be + * fixed + * @param exceptionBuilder function to build the failure message * @return a {@link Success} if no {@link Failure}'s are found in the stream * @param type of data */ - public static Try, FailureException> scanStream( - Stream> stream, String typeOfData) { + public static Try, RE> scanStream( + Stream> stream, String typeOfData, Function exceptionBuilder) { Map>> map = stream.collect(partitioningBy(Try::isSuccess)); List> successes = map.get(true); @@ -191,16 +194,15 @@ public static Try, FailureException> scanStre assert successes != null && failures != null; if (!failures.isEmpty()) { - E first = ((Failure) failures.get(0)).exception; + List exceptions = failures.stream().map(f -> ((Failure) f).exception).toList(); return new Failure<>( - new FailureException( - failures.size() + exceptionBuilder.apply( + exceptions.size() + " exception(s) occurred within \"" + typeOfData - + "\" data, one is: " - + first, - first.getCause())); + + "\" data: \n " + + ExceptionUtils.combineExceptions(exceptions))); } else { return new Success<>(successes.stream().map(t -> ((Success) t).data)); } diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/EnergyManagementSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/EnergyManagementSourceTest.groovy index 2cdac0018..3fb52f9f5 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/EnergyManagementSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/EnergyManagementSourceTest.groovy @@ -171,7 +171,7 @@ class EnergyManagementSourceTest extends Specification { then: def exc = thrown(SourceException) - exc.cause.message.contains("test failure abc") + exc.message.contains("test failure abc") } def "An EnergyManagementSource should fail if a parent EM UUID is malformed"() { @@ -198,7 +198,7 @@ class EnergyManagementSourceTest extends Specification { then: def exc = thrown(SourceException) - exc.cause.message.contains("Exception while trying to parse UUID of field \"controllingEm\" with value \"not-a-uuid\"") + exc.message.contains("Exception while trying to parse UUID of field \"controllingEm\" with value \"not-a-uuid\"") } def "An EnergyManagementSource should fail if the factory fails for one EM"() { @@ -224,8 +224,8 @@ class EnergyManagementSourceTest extends Specification { then: def exc = thrown(SourceException) - exc.cause.message.contains("An error occurred when creating instance of EmInput") - exc.cause.cause.class == FactoryException + exc.message == "1 exception(s) occurred within \"EmInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of EmInput.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Field \"id\" not found in EntityData" } def "An EnergyManagementSource should fail if a parent em is not provided"() { diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy index 0c46d0c9a..801faeb4d 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy @@ -48,7 +48,8 @@ class EntitySourceTest extends Specification { then: SourceException ex = thrown() - ex.message == "edu.ie3.datamodel.exceptions.FailureException: 1 exception(s) occurred within \"OperatorInput\" data, one is: edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of OperatorInput.class." + ex.message == "1 exception(s) occurred within \"OperatorInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of OperatorInput.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Field \"id\" not found in EntityData" } def "An EntitySource can build EntityData correctly"() { diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/TimeSeriesMappingSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/TimeSeriesMappingSourceTest.groovy index 9b5da47e2..8d7f475ed 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/TimeSeriesMappingSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/TimeSeriesMappingSourceTest.groovy @@ -98,8 +98,7 @@ class TimeSeriesMappingSourceTest extends Specification { then: def ex = thrown(SourceException) - ex.cause.class == FailureException - ex.cause.message.startsWith("1 exception(s) occurred within \"MappingEntry\" data") + ex.message.startsWith("1 exception(s) occurred within \"MappingEntry\" data") } def "should throw SourceException for invalid timeSeries"(){ @@ -110,8 +109,7 @@ class TimeSeriesMappingSourceTest extends Specification { then: def ex = thrown(SourceException) - ex.cause.class == FailureException - ex.cause.message.startsWith("1 exception(s) occurred within \"MappingEntry\" data") + ex.message.startsWith("1 exception(s) occurred within \"MappingEntry\" data") } def "should throw SourceException for invalid timeSeries and asset"(){ @@ -122,7 +120,8 @@ class TimeSeriesMappingSourceTest extends Specification { then: def ex = thrown(SourceException) - ex.cause.class == FailureException - ex.cause.message.startsWith("2 exception(s) occurred within \"MappingEntry\" data") + ex.message == "2 exception(s) occurred within \"MappingEntry\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of MappingEntry.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Exception while trying to parse UUID of field \"asset\" with value \"invalidAsset\"\n" + + " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of MappingEntry.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Exception while trying to parse UUID of field \"asset\" with value \"invalidAsset2\"" } } diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvDataSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvDataSourceTest.groovy index 83c5108c3..754c62fa8 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvDataSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvDataSourceTest.groovy @@ -127,6 +127,18 @@ class CsvDataSourceTest extends Specification implements CsvTestDataMeta { ] as Set } + def "A CsvDataSource should throw an exception when retrieving column names from a valid CSV file using the wrong separator"() { + given: + DummyCsvSource source = new DummyCsvSource(";", participantsFolderPath, fileNamingStrategy) + + when: + source.getSourceFields(LoadInput) + + then: + SourceException ex = thrown(SourceException) + ex.message == "The given file has less than two columns! (Used separator ';' on headline 'uuid,cos_phi_rated,e_cons_annual,id,node,operates_from,operates_until,operator,q_characteristics,s_rated,load_profile,controlling_em')" + } + def "A CsvDataSource should return an empty result when retrieving column names for a non-existing CSV file"() { given: def path = Path.of("this/path/does-not-exist") @@ -322,16 +334,15 @@ class CsvDataSourceTest extends Specification implements CsvTestDataMeta { then: def exception = thrown(SourceException) - exception.getMessage().startsWith("The size of the headline (8) does not fit to the size of the attribute fields") + exception.getMessage() == expectedMessage where: - invalidCsvRow || explaination - "5ebd8f7e-dedb-4017-bb86-6373c4b68eb8;25.0;100.0;0.95;98.0;test_bmTypeInput;50.0;25.0" || "wrong separator" - "5ebd8f7e-dedb-4017-bb86-6373c4b68eb8,25.0,100.0,0.95,98.0,test_bmTypeInput" || "too little columns" - "5ebd8f7e-dedb-4017-bb86-6373c4b68eb8,25.0,100.0,0.95,98.0,test_bmTypeInput,,,," || "too many columns" + invalidCsvRow || explaination || expectedMessage + "5ebd8f7e-dedb-4017-bb86-6373c4b68eb8;25.0;100.0;0.95;98.0;test_bmTypeInput;50.0;25.0" || "wrong separator" || "The size of the headline (8) does not fit to the size of the attribute fields (1).\n Headline fields: ['uuid', 'active_power_gradient', 'capex', 'cosphi_rated', 'eta_conv', 'id', 'opex', 's_rated']\n Row values: ['5ebd8f7e-dedb-4017-bb86-6373c4b68eb8;25.0;100.0;0.95;98.0;test_bmTypeInput;50.0;25.0'].\n Please check:\n - is the csv separator in the row matching the provided separator ','\n - does the number of columns match the number of headline fields \n - are you using a valid RFC 4180 formatted csv row?" + "5ebd8f7e-dedb-4017-bb86-6373c4b68eb8,25.0,100.0,0.95,98.0,test_bmTypeInput" || "too little columns" || "The size of the headline (8) does not fit to the size of the attribute fields (6).\n Headline fields: ['uuid', 'active_power_gradient', 'capex', 'cosphi_rated', 'eta_conv', 'id', 'opex', 's_rated']\n Row values: ['5ebd8f7e-dedb-4017-bb86-6373c4b68eb8', '25.0', '100.0', '0.95', '98.0', 'test_bmTypeInput'].\n Please check:\n - is the csv separator in the row matching the provided separator ','\n - does the number of columns match the number of headline fields \n - are you using a valid RFC 4180 formatted csv row?" + "5ebd8f7e-dedb-4017-bb86-6373c4b68eb8,25.0,100.0,0.95,98.0,test_bmTypeInput,,,," || "too many columns" || "The size of the headline (8) does not fit to the size of the attribute fields (10).\n Headline fields: ['uuid', 'active_power_gradient', 'capex', 'cosphi_rated', 'eta_conv', 'id', 'opex', 's_rated']\n Row values: ['5ebd8f7e-dedb-4017-bb86-6373c4b68eb8', '25.0', '100.0', '0.95', '98.0', 'test_bmTypeInput', '', '', '', ''].\n Please check:\n - is the csv separator in the row matching the provided separator ','\n - does the number of columns match the number of headline fields \n - are you using a valid RFC 4180 formatted csv row?" } - def "A CsvDataSource should throw an exception if there are duplicate headlines"() { given: def invalidHeadline = [ diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvGraphicSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvGraphicSourceTest.groovy index 9a7b15fc5..b218968df 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvGraphicSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvGraphicSourceTest.groovy @@ -70,7 +70,9 @@ class CsvGraphicSourceTest extends Specification implements CsvTestDataMeta { Exception ex = graphicElements.exception.get() ex.class == GraphicSourceException - ex.message.startsWith("1 error(s) occurred while initializing graphic elements. edu.ie3.datamodel.exceptions.FailureException: 1 exception(s) occurred within \"LineGraphicInput\" data, one is: edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7 was not provided.") + ex.message == "Some exception(s) occurred while initializing graphic elements. \n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"LineGraphicInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7 was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7 was not provided." } @@ -143,8 +145,7 @@ class CsvGraphicSourceTest extends Specification implements CsvTestDataMeta { then: def e = thrown(SourceException) - e.cause.class == FailureException - e.cause.message.startsWith(expectedFailures + " exception(s) occurred") + e.message.startsWith(expectedFailures + " exception(s) occurred") where: nodeCollection || expectedFailures @@ -167,8 +168,7 @@ class CsvGraphicSourceTest extends Specification implements CsvTestDataMeta { then: def e = thrown(SourceException) - e.cause.class == FailureException - e.cause.message.startsWith(expectedFailures + " exception(s) occurred") + e.message.startsWith(expectedFailures + " exception(s) occurred") where: lineCollection || expectedFailures diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy index b3ad25998..282f1d16b 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy @@ -268,7 +268,8 @@ class CsvRawGridSourceTest extends Specification implements CsvTestDataMeta { then: "the optional is empty" actual == null SourceException ex = thrown() - ex.message == "edu.ie3.datamodel.exceptions.FailureException: 1 exception(s) occurred within \"NodeInput\" data, one is: edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of NodeInput.class." + ex.message == "1 exception(s) occurred within \"NodeInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of NodeInput.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Exception while trying to parse UUID of field \"uuid\" with value \"bd837a25-58f3-44ac-aa90-c6b6e3 cd91b2\"" } def "The CsvRawGridSource returns an empty grid, if the RawGridElements contain no single element"() { @@ -308,6 +309,8 @@ class CsvRawGridSourceTest extends Specification implements CsvTestDataMeta { Exception ex = rawGridElements.exception.get() ex.class == SourceException - ex.message.startsWith("edu.ie3.datamodel.exceptions.FailureException: 2 exception(s) occurred within \"LineInput\" data, one is: edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid ") + ex.message == "2 exception(s) occurred within \"LineInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid bd837a25-58f3-44ac-aa90-c6b6e3cd91b2 was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid bd837a25-58f3-44ac-aa90-c6b6e3cd91b2 was not provided." } } \ No newline at end of file diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy index 67316ab30..1e8285318 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy @@ -76,10 +76,27 @@ class CsvSystemParticipantSourceTest extends Specification implements CsvTestDat Exception ex = systemParticipants.exception.get() ex.class == SystemParticipantsException - ex.message.startsWith("10 error(s) occurred while initializing system participants. " + - "edu.ie3.datamodel.exceptions.FailureException: 1 exception(s) occurred within " + - "\"FixedFeedInInput\" data, one is: edu.ie3.datamodel.exceptions.FactoryException: " + - "edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.") + ex.message == "Some exception(s) occurred while initializing system participants.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"FixedFeedInInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"PvInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"LoadInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"BmInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"StorageInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"WecInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"EvInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"EvcsInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"ChpInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"HpInput\" data: \n" + + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided." } def "A SystemParticipantSource with csv input should return data from valid input file as expected"() { diff --git a/src/test/groovy/edu/ie3/datamodel/utils/TryTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/TryTest.groovy index b7d636a15..8ecd40bec 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/TryTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/TryTest.groovy @@ -233,17 +233,18 @@ class TryTest extends Specification { given: Set> set = Set.of( new Try.Success<>("one"), - new Try.Failure<>(new Exception("exception")), + new Try.Failure<>(new Exception("exception", new SourceException("source exception"))), new Try.Success<>("two"), new Try.Success<>("three") ) when: - Try, Exception> scan = Try.scanCollection(set, String) + Try, Exception> scan = Try.scanCollection(set, String, Exception::new) then: scan.failure - scan.exception.get().message == "1 exception(s) occurred within \"String\" data, one is: java.lang.Exception: exception" + scan.exception.get().message == "1 exception(s) occurred within \"String\" data: \n" + + " java.lang.Exception: exception Caused by: edu.ie3.datamodel.exceptions.SourceException: source exception" } def "A scan for exceptions should work as expected when no failures are included"() { @@ -255,7 +256,7 @@ class TryTest extends Specification { ) when: - Try, Exception> scan = Try.scanCollection(set, String) + Try, Exception> scan = Try.scanCollection(set, String, Exception::new) then: scan.success diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtilsTest.groovy index 0992c426b..a8c90b766 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtilsTest.groovy @@ -99,10 +99,8 @@ class SystemParticipantValidationUtilsTest extends Specification { SystemParticipantValidationUtils.check(invalidType) then: - Throwable topEx = thrown() - Throwable ex = topEx.cause - ex.class == expectedException.class - ex.message == expectedException.message + Throwable ex = thrown() + ex.message.contains(expectedException.message) where: invalidType || expectedException @@ -142,10 +140,8 @@ class SystemParticipantValidationUtilsTest extends Specification { ValidationUtils.check(invalidBmType) then: - Throwable topEx = thrown() - Throwable ex = topEx.cause - ex.class == expectedException.class - ex.message == expectedException.message + Throwable ex = thrown() + ex.message.contains(expectedException.message) where: invalidBmType || expectedException @@ -184,10 +180,8 @@ class SystemParticipantValidationUtilsTest extends Specification { SystemParticipantValidationUtils.check(invalidChpType) then: - Throwable topEx = thrown() - Throwable ex = topEx.cause - ex.class == expectedException.class - ex.message == expectedException.message + Throwable ex = thrown() + ex.message.contains(expectedException.message) where: invalidChpType || expectedException @@ -228,10 +222,8 @@ class SystemParticipantValidationUtilsTest extends Specification { SystemParticipantValidationUtils.check(invalidEvType) then: - Throwable topEx = thrown() - Throwable ex = topEx.cause - ex.class == expectedException.class - ex.message == expectedException.message + Throwable ex = thrown() + ex.message.contains(expectedException.message) where: invalidEvType || expectedException @@ -298,10 +290,8 @@ class SystemParticipantValidationUtilsTest extends Specification { SystemParticipantValidationUtils.check(invalidHpType) then: - Throwable topEx = thrown() - Throwable ex = topEx.cause - ex.class == expectedException.class - ex.message == expectedException.message + Throwable ex = thrown() + ex.message.contains(expectedException.message) where: invalidHpType || expectedException @@ -402,10 +392,8 @@ class SystemParticipantValidationUtilsTest extends Specification { SystemParticipantValidationUtils.check(invalidStorageType) then: - Throwable topEx = thrown() - Throwable ex = topEx.cause - ex.class == expectedException.class - ex.message == expectedException.message + Throwable ex = thrown() + ex.message.contains(expectedException.message) where: invalidStorageType || expectedException @@ -445,10 +433,8 @@ class SystemParticipantValidationUtilsTest extends Specification { SystemParticipantValidationUtils.check(invalidWecType) then: - Throwable topEx = thrown() - Throwable ex = topEx.cause - ex.class == expectedException.class - ex.message == expectedException.message + Throwable ex = thrown() + ex.message.contains(expectedException.message) where: invalidWecType || expectedException diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy index 82066c52c..4fb703f60 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy @@ -97,9 +97,8 @@ class UniquenessValidationUtilsTest extends Specification { then: DuplicateEntitiesException de = thrown() - de.message == "The following exception(s) occurred while checking the uniqueness of 'AssetInput' entities: " + - "'DummyAssetInput' entities with duplicated String key, but different field values found! " + - "Affected primary keys: [first]" + de.message == "The following exception(s) occurred while checking the uniqueness of 'AssetInput' entities: \n" + + " edu.ie3.datamodel.exceptions.DuplicateEntitiesException: 'DummyAssetInput' entities with duplicated String key, but different field values found! Affected primary keys: [first]" } def "Checking if result entities are unique"() { diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/ValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/ValidationUtilsTest.groovy index 43d3b518f..74bf0a1b4 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/ValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/ValidationUtilsTest.groovy @@ -86,7 +86,7 @@ class ValidationUtilsTest extends Specification { then: InvalidEntityException ex = thrown() - ex.message == "Entity is invalid because of: \nThe following quantities have to be zero or positive: -1 µS/km [LineTypeInput{uuid=3bed3eb3-9790-4874-89b5-a5434d408088, id=lineType_AtoB, b=-1 µS/km, g=0.0 µS/km, r=0.437 Ω/km, x=0.356 Ω/km, iMax=300 A, vRated=20 kV}]" + ex.message == "Entity is invalid because of: The following quantities have to be zero or positive: -1 µS/km [LineTypeInput{uuid=3bed3eb3-9790-4874-89b5-a5434d408088, id=lineType_AtoB, b=-1 µS/km, g=0.0 µS/km, r=0.437 Ω/km, x=0.356 Ω/km, iMax=300 A, vRated=20 kV}]" } def "The check for zero or negative entities should work as expected"() { @@ -123,7 +123,7 @@ class ValidationUtilsTest extends Specification { then: InvalidEntityException ex = thrown() - ex.message == "Entity is invalid because of: \nThe following quantities have to be positive: 0.0 µS/km [LineTypeInput{uuid=3bed3eb3-9790-4874-89b5-a5434d408088, id=lineType_AtoB, b=0.0 µS/km, g=0.0 µS/km, r=0.437 Ω/km, x=0.356 Ω/km, iMax=300 A, vRated=20 kV}]" + ex.message == "Entity is invalid because of: The following quantities have to be positive: 0.0 µS/km [LineTypeInput{uuid=3bed3eb3-9790-4874-89b5-a5434d408088, id=lineType_AtoB, b=0.0 µS/km, g=0.0 µS/km, r=0.437 Ω/km, x=0.356 Ω/km, iMax=300 A, vRated=20 kV}]" } def "Checking an asset type input without an id leads to an exception"() { @@ -136,6 +136,6 @@ class ValidationUtilsTest extends Specification { then: exceptions.size() == 1 def e = exceptions.get(0).exception.get() - e.message.startsWith("Entity is invalid because of: \nNo ID assigned [AssetTypeInput") + e.message.startsWith("Entity is invalid because of: No ID assigned [AssetTypeInput") } } From 39e1178340c076e428d9fd895f17843f6467c8db Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Wed, 9 Jul 2025 09:05:41 +0200 Subject: [PATCH 3/6] Implementing reviewer's comments. --- src/main/java/edu/ie3/datamodel/io/source/RawGridSource.java | 5 ++++- .../edu/ie3/datamodel/io/source/SystemParticipantSource.java | 5 ++++- .../io/source/csv/CsvSystemParticipantSourceTest.groovy | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/io/source/RawGridSource.java b/src/main/java/edu/ie3/datamodel/io/source/RawGridSource.java index 3d5f5e2ef..a6dc0ec3f 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/RawGridSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/RawGridSource.java @@ -158,7 +158,10 @@ public RawGridElements getGridData( if (!exceptions.isEmpty()) { throw new RawGridException( - "Some exception(s) occurred while initializing raw grid.", exceptions); + "Exception(s) occurred in " + + exceptions.size() + + " input files while initializing raw grid.", + exceptions); } else { /* build and return the grid if it is not empty */ // getOrThrow should not throw an exception in this context, because all exception are diff --git a/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java b/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java index dc240862a..00dfd4ce6 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java @@ -225,7 +225,10 @@ public SystemParticipants getSystemParticipants( if (!exceptions.isEmpty()) { throw new SystemParticipantsException( - "Some exception(s) occurred while initializing system participants.", exceptions); + "Exception(s) occurred in " + + exceptions.size() + + " input files while initializing system participants.", + exceptions); } else { // if everything is fine, return a system participants container // getOrThrow should not throw an exception in this context, because all exception are diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy index 1e8285318..b3d750a49 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy @@ -76,7 +76,7 @@ class CsvSystemParticipantSourceTest extends Specification implements CsvTestDat Exception ex = systemParticipants.exception.get() ex.class == SystemParticipantsException - ex.message == "Some exception(s) occurred while initializing system participants.\n" + + ex.message == "Exception(s) occurred in 10 input files while initializing system participants.\n" + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"FixedFeedInInput\" data: \n" + " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"PvInput\" data: \n" + From 50e8afad195b6ef2dec6be4362d33353e722e62b Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Wed, 9 Jul 2025 10:14:47 +0200 Subject: [PATCH 4/6] Fix sonarqube issues. --- src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java | 2 +- src/main/java/edu/ie3/datamodel/utils/Try.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java b/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java index f700958bf..e6dddb67d 100644 --- a/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java @@ -42,6 +42,6 @@ public static String combineExceptions(List exceptions) { exceptions.stream().map(converter).reduce("", (a, b) -> a + messageSeparator + b); // some formating - return messages.replaceAll("\n", "\n ").replaceFirst(messageSeparator, ""); + return messages.replace("\n", "\n ").replaceFirst(messageSeparator, ""); } } diff --git a/src/main/java/edu/ie3/datamodel/utils/Try.java b/src/main/java/edu/ie3/datamodel/utils/Try.java index 9becdda01..c03d0ea5e 100644 --- a/src/main/java/edu/ie3/datamodel/utils/Try.java +++ b/src/main/java/edu/ie3/datamodel/utils/Try.java @@ -167,8 +167,8 @@ public static List getExceptions(Try * @return a {@link Success} if no {@link Failure}'s are found in the collection * @param type of data */ - public static Try, RE> scanCollection( - Collection> c, Class typeOfData, Function exceptionBuilder) { + public static Try, R> scanCollection( + Collection> c, Class typeOfData, Function exceptionBuilder) { return scanStream(c.stream(), typeOfData.getSimpleName(), exceptionBuilder) .transformS(stream -> stream.collect(Collectors.toSet())); } @@ -183,8 +183,8 @@ public static Try, RE> sca * @return a {@link Success} if no {@link Failure}'s are found in the stream * @param type of data */ - public static Try, RE> scanStream( - Stream> stream, String typeOfData, Function exceptionBuilder) { + public static Try, R> scanStream( + Stream> stream, String typeOfData, Function exceptionBuilder) { Map>> map = stream.collect(partitioningBy(Try::isSuccess)); List> successes = map.get(true); From e85ae3aaf7ba726c32792872cce57db7a1850d48 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Wed, 9 Jul 2025 10:30:04 +0200 Subject: [PATCH 5/6] Improving the exceptions thrown by methods in `UniquenessValidationUtils`. --- .../exceptions/DuplicateEntitiesException.java | 2 +- .../ie3/datamodel/utils/ExceptionUtils.java | 18 ++++++++++++++++++ .../UniquenessValidationUtilsTest.groovy | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java b/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java index eee2942f1..21fd3adbe 100644 --- a/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java +++ b/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java @@ -20,6 +20,6 @@ public DuplicateEntitiesException( "The following exception(s) occurred while checking the uniqueness of '" + entityName + "' entities: \n" - + ExceptionUtils.combineExceptions(exceptions)); + + ExceptionUtils.combineMessages(exceptions)); } } diff --git a/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java b/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java index e6dddb67d..b3d2add80 100644 --- a/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java @@ -13,6 +13,24 @@ private ExceptionUtils() { throw new IllegalStateException("Utility classes cannot be instantiated"); } + /** + * Creates a string containing multiple exception messages. + * + * @param exceptions list of exceptions + * @return str containing the messages + */ + public static String combineMessages(List exceptions) { + String messageSeparator = "\n "; + + String messages = + exceptions.stream() + .map(Throwable::getMessage) + .reduce("", (a, b) -> a + messageSeparator + b); + + // some formating + return messages.replace("\n", "\n ").replaceFirst(messageSeparator, ""); + } + /** * Creates a string containing multiple exception messages. * diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy index 4fb703f60..92169b0bf 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy @@ -98,7 +98,7 @@ class UniquenessValidationUtilsTest extends Specification { then: DuplicateEntitiesException de = thrown() de.message == "The following exception(s) occurred while checking the uniqueness of 'AssetInput' entities: \n" + - " edu.ie3.datamodel.exceptions.DuplicateEntitiesException: 'DummyAssetInput' entities with duplicated String key, but different field values found! Affected primary keys: [first]" + " 'DummyAssetInput' entities with duplicated String key, but different field values found! Affected primary keys: [first]" } def "Checking if result entities are unique"() { From 077a760e5a26c02afd72cdd9b6bb06dc64c4e9a0 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Wed, 9 Jul 2025 15:22:34 +0200 Subject: [PATCH 6/6] Removing exception class information from combined exceptions. --- .../DuplicateEntitiesException.java | 2 +- .../exceptions/FailedValidationException.java | 2 +- .../edu/ie3/datamodel/io/factory/Factory.java | 2 +- .../ie3/datamodel/io/source/EntitySource.java | 26 ++++++------ .../datamodel/io/source/GraphicSource.java | 5 ++- .../datamodel/io/source/RawGridSource.java | 2 +- .../io/source/SystemParticipantSource.java | 2 +- .../ie3/datamodel/utils/ExceptionUtils.java | 29 +++---------- .../source/EnergyManagementSourceTest.groovy | 2 +- .../io/source/EntitySourceTest.groovy | 8 ++-- .../source/TimeSeriesMappingSourceTest.groovy | 4 +- .../io/source/csv/CsvGraphicSourceTest.groovy | 6 +-- .../io/source/csv/CsvRawGridSourceTest.groovy | 6 +-- .../csv/CsvSystemParticipantSourceTest.groovy | 42 +++++++++---------- .../edu/ie3/datamodel/utils/TryTest.groovy | 2 +- 15 files changed, 62 insertions(+), 78 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java b/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java index 21fd3adbe..eee2942f1 100644 --- a/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java +++ b/src/main/java/edu/ie3/datamodel/exceptions/DuplicateEntitiesException.java @@ -20,6 +20,6 @@ public DuplicateEntitiesException( "The following exception(s) occurred while checking the uniqueness of '" + entityName + "' entities: \n" - + ExceptionUtils.combineMessages(exceptions)); + + ExceptionUtils.combineExceptions(exceptions)); } } diff --git a/src/main/java/edu/ie3/datamodel/exceptions/FailedValidationException.java b/src/main/java/edu/ie3/datamodel/exceptions/FailedValidationException.java index 4b10acc06..25e1aa4de 100644 --- a/src/main/java/edu/ie3/datamodel/exceptions/FailedValidationException.java +++ b/src/main/java/edu/ie3/datamodel/exceptions/FailedValidationException.java @@ -23,6 +23,6 @@ public FailedValidationException(String message) { /** @param exceptions List of exceptions, which must not be empty */ public FailedValidationException(List exceptions) { - super("Validation failed due to: " + ExceptionUtils.combineExceptions(exceptions)); + super("Validation failed due to:\n " + ExceptionUtils.combineExceptions(exceptions)); } } diff --git a/src/main/java/edu/ie3/datamodel/io/factory/Factory.java b/src/main/java/edu/ie3/datamodel/io/factory/Factory.java index 9daff0c2d..c5da1cd14 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/Factory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/Factory.java @@ -73,7 +73,7 @@ public Try get(D data) { * {@link Failure} */ public Try get(Try data) { - return data.transformF(FactoryException::new).flatMap(this::get); + return data.transformF(e -> new FactoryException(e.getMessage(), e)).flatMap(this::get); } /** diff --git a/src/main/java/edu/ie3/datamodel/io/source/EntitySource.java b/src/main/java/edu/ie3/datamodel/io/source/EntitySource.java index 726a35279..0c4d9c1d6 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/EntitySource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/EntitySource.java @@ -205,11 +205,11 @@ protected static Stream getEntities( */ protected static Stream> buildEntityData( Class entityClass, DataSource dataSource) throws SourceException { - Stream> dataStream = - Try.of(() -> dataSource.getSourceData(entityClass), SourceException.class).getOrThrow(); - - return dataStream.map( - fieldsToAttributes -> new Try.Success<>(new EntityData(fieldsToAttributes, entityClass))); + return dataSource + .getSourceData(entityClass) + .map( + fieldsToAttributes -> + new Try.Success<>(new EntityData(fieldsToAttributes, entityClass))); } /** @@ -373,16 +373,14 @@ protected static Try extractFuncti return entityData.flatMap( data -> Try.of(() -> data.getUUID(fieldName), FactoryException.class) + .flatMap(entityUuid -> extractFunction(entityUuid, entities)) .transformF( exception -> new SourceException( - "Extracting UUID field " + "Extracting UUID for field '" + fieldName - + " from entity data " - + entityData - + " failed.", - exception)) - .flatMap(entityUuid -> extractFunction(entityUuid, entities))); + + "' failed. Caused by: " + + exception.getMessage()))); } /** @@ -393,13 +391,13 @@ protected static Try extractFuncti * @return a try of the {@link Entity} * @param type of entity */ - protected static Try extractFunction(UUID uuid, Map entityMap) { + protected static Try extractFunction(UUID uuid, Map entityMap) { return Optional.ofNullable(entityMap.get(uuid)) // We either find a matching entity for given UUID, thus return a success - .map(entity -> Try.of(() -> entity, SourceException.class)) + .map(entity -> Try.of(() -> entity, FactoryException.class)) // ... or find no matching entity, returning a failure. .orElse( - new Failure<>(new SourceException("Entity with uuid " + uuid + " was not provided."))); + new Failure<>(new FactoryException("Entity with uuid " + uuid + " was not provided."))); } // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= diff --git a/src/main/java/edu/ie3/datamodel/io/source/GraphicSource.java b/src/main/java/edu/ie3/datamodel/io/source/GraphicSource.java index d92336aa2..904e0a42d 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/GraphicSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/GraphicSource.java @@ -99,7 +99,10 @@ public GraphicElements getGraphicElements(Map nodes, Map exceptions) { - String messageSeparator = "\n "; - - String messages = - exceptions.stream() - .map(Throwable::getMessage) - .reduce("", (a, b) -> a + messageSeparator + b); - - // some formating - return messages.replace("\n", "\n ").replaceFirst(messageSeparator, ""); - } - /** * Creates a string containing multiple exception messages. * @@ -43,17 +25,18 @@ public static String combineExceptions(List exceptions) { // function to convert an exception into a string Function converter = e -> { - String clazz = e.getClass().getName(); String message = e.getMessage(); Throwable cause = e.getCause(); - String res = clazz + ": " + message; - if (cause != null) { - res += " Caused by: " + cause.getClass().getName() + ": " + cause.getMessage(); + String causeMessage = cause.getMessage(); + + if (!message.equalsIgnoreCase(causeMessage)) { + message += " Caused by: " + cause.getMessage(); + } } - return res; + return message; }; String messages = diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/EnergyManagementSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/EnergyManagementSourceTest.groovy index 3fb52f9f5..86d5edf77 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/EnergyManagementSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/EnergyManagementSourceTest.groovy @@ -225,7 +225,7 @@ class EnergyManagementSourceTest extends Specification { then: def exc = thrown(SourceException) exc.message == "1 exception(s) occurred within \"EmInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of EmInput.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Field \"id\" not found in EntityData" + " An error occurred when creating instance of EmInput.class. Caused by: Field \"id\" not found in EntityData" } def "An EnergyManagementSource should fail if a parent em is not provided"() { diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy index 801faeb4d..1061376f4 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/EntitySourceTest.groovy @@ -49,7 +49,7 @@ class EntitySourceTest extends Specification { then: SourceException ex = thrown() ex.message == "1 exception(s) occurred within \"OperatorInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of OperatorInput.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Field \"id\" not found in EntityData" + " An error occurred when creating instance of OperatorInput.class. Caused by: Field \"id\" not found in EntityData" } def "An EntitySource can build EntityData correctly"() { @@ -169,12 +169,12 @@ class EntitySourceTest extends Specification { then: actual.failure actual.exception.get().class == SourceException - actual.exception.get().message.contains(expectedMessage) + actual.exception.get().message == expectedMessage where: fieldsToAttributes | entityMap | expectedMessage - ["operator": "no uuid"] | map([OperatorInput.NO_OPERATOR_ASSIGNED]) | "Extracting UUID field operator from entity data" - ["operator": GridTestData.profBroccoli.uuid.toString()] | map([OperatorInput.NO_OPERATOR_ASSIGNED]) | "Entity with uuid f15105c4-a2de-4ab8-a621-4bc98e372d92 was not provided." + ["operator": "no uuid"] | map([OperatorInput.NO_OPERATOR_ASSIGNED]) | "Extracting UUID for field 'operator' failed. Caused by: Exception while trying to parse UUID of field \"operator\" with value \"no uuid\"" + ["operator": GridTestData.profBroccoli.uuid.toString()] | map([OperatorInput.NO_OPERATOR_ASSIGNED]) | "Extracting UUID for field 'operator' failed. Caused by: Entity with uuid f15105c4-a2de-4ab8-a621-4bc98e372d92 was not provided." } def "An EntitySource returns a failure if a given map does not contain the given uuid"() { diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/TimeSeriesMappingSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/TimeSeriesMappingSourceTest.groovy index 8d7f475ed..d706fffc8 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/TimeSeriesMappingSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/TimeSeriesMappingSourceTest.groovy @@ -121,7 +121,7 @@ class TimeSeriesMappingSourceTest extends Specification { then: def ex = thrown(SourceException) ex.message == "2 exception(s) occurred within \"MappingEntry\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of MappingEntry.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Exception while trying to parse UUID of field \"asset\" with value \"invalidAsset\"\n" + - " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of MappingEntry.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Exception while trying to parse UUID of field \"asset\" with value \"invalidAsset2\"" + " An error occurred when creating instance of MappingEntry.class. Caused by: Exception while trying to parse UUID of field \"asset\" with value \"invalidAsset\"\n" + + " An error occurred when creating instance of MappingEntry.class. Caused by: Exception while trying to parse UUID of field \"asset\" with value \"invalidAsset2\"" } } diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvGraphicSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvGraphicSourceTest.groovy index b218968df..24c33f1e7 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvGraphicSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvGraphicSourceTest.groovy @@ -70,9 +70,9 @@ class CsvGraphicSourceTest extends Specification implements CsvTestDataMeta { Exception ex = graphicElements.exception.get() ex.class == GraphicSourceException - ex.message == "Some exception(s) occurred while initializing graphic elements. \n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"LineGraphicInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7 was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7 was not provided." + ex.message == "Exception(s) occurred in 1 input file(s) while initializing graphic elements. \n" + + " 1 exception(s) occurred within \"LineGraphicInput\" data: \n" + + " Extracting UUID for field 'line' failed. Caused by: Entity with uuid 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7 was not provided." } diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy index 282f1d16b..6c62c4338 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvRawGridSourceTest.groovy @@ -269,7 +269,7 @@ class CsvRawGridSourceTest extends Specification implements CsvTestDataMeta { actual == null SourceException ex = thrown() ex.message == "1 exception(s) occurred within \"NodeInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: An error occurred when creating instance of NodeInput.class. Caused by: edu.ie3.datamodel.exceptions.FactoryException: Exception while trying to parse UUID of field \"uuid\" with value \"bd837a25-58f3-44ac-aa90-c6b6e3 cd91b2\"" + " An error occurred when creating instance of NodeInput.class. Caused by: Exception while trying to parse UUID of field \"uuid\" with value \"bd837a25-58f3-44ac-aa90-c6b6e3 cd91b2\"" } def "The CsvRawGridSource returns an empty grid, if the RawGridElements contain no single element"() { @@ -310,7 +310,7 @@ class CsvRawGridSourceTest extends Specification implements CsvTestDataMeta { Exception ex = rawGridElements.exception.get() ex.class == SourceException ex.message == "2 exception(s) occurred within \"LineInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid bd837a25-58f3-44ac-aa90-c6b6e3cd91b2 was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid bd837a25-58f3-44ac-aa90-c6b6e3cd91b2 was not provided." + " Extracting UUID for field 'nodeA' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " Extracting UUID for field 'nodeA' failed. Caused by: Entity with uuid bd837a25-58f3-44ac-aa90-c6b6e3cd91b2 was not provided." } } \ No newline at end of file diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy index b3d750a49..293ae514b 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy @@ -76,27 +76,27 @@ class CsvSystemParticipantSourceTest extends Specification implements CsvTestDat Exception ex = systemParticipants.exception.get() ex.class == SystemParticipantsException - ex.message == "Exception(s) occurred in 10 input files while initializing system participants.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"FixedFeedInInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"PvInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"LoadInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"BmInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"StorageInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"WecInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"EvInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"EvcsInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"ChpInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + - " edu.ie3.datamodel.exceptions.SourceException: 1 exception(s) occurred within \"HpInput\" data: \n" + - " edu.ie3.datamodel.exceptions.FactoryException: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided. Caused by: edu.ie3.datamodel.exceptions.SourceException: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided." + ex.message == "Exception(s) occurred in 10 input file(s) while initializing system participants.\n" + + " 1 exception(s) occurred within \"FixedFeedInInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"PvInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"LoadInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"BmInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"StorageInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"WecInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"EvInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"EvcsInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"ChpInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"HpInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided." } def "A SystemParticipantSource with csv input should return data from valid input file as expected"() { diff --git a/src/test/groovy/edu/ie3/datamodel/utils/TryTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/TryTest.groovy index 8ecd40bec..59909cb14 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/TryTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/TryTest.groovy @@ -244,7 +244,7 @@ class TryTest extends Specification { then: scan.failure scan.exception.get().message == "1 exception(s) occurred within \"String\" data: \n" + - " java.lang.Exception: exception Caused by: edu.ie3.datamodel.exceptions.SourceException: source exception" + " exception Caused by: source exception" } def "A scan for exceptions should work as expected when no failures are included"() {