From dd7f61de4ba3c27e1781bde8ee1f04fe521b511a Mon Sep 17 00:00:00 2001 From: Florent MILLOT <75525996+flomillot@users.noreply.github.com> Date: Sat, 10 Oct 2026 17:04:43 +0200 Subject: [PATCH] Make root network applicabilities explicit Signed-off-by: Florent MILLOT <75525996+flomillot@users.noreply.github.com> --- .../modification/dto/ModificationInfos.java | 20 ++++++++--- .../NetworkModificationExceptionType.java | 3 +- .../dto/ModificationInfosTest.java | 36 ++++++++++++------- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/dto/ModificationInfos.java b/src/main/java/org/gridsuite/modification/dto/ModificationInfos.java index c23575dd4..427c696db 100644 --- a/src/main/java/org/gridsuite/modification/dto/ModificationInfos.java +++ b/src/main/java/org/gridsuite/modification/dto/ModificationInfos.java @@ -19,6 +19,7 @@ import org.gridsuite.modification.dto.tabular.LimitSetsTabularModificationInfos; import org.gridsuite.modification.dto.tabular.TabularCreationInfos; import org.gridsuite.modification.dto.tabular.TabularModificationInfos; +import org.gridsuite.modification.error.NetworkModificationException; import org.gridsuite.modification.modifications.AbstractModification; import java.time.Instant; @@ -26,6 +27,8 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; +import static org.gridsuite.modification.error.NetworkModificationExceptionType.MISSING_ROOT_NETWORK_APPLICABILITY; + /** * @author Slimane Amar */ @@ -161,16 +164,23 @@ public Map getMapMessageValues() { /** * A modification is activated on a root network when it is not stashed, when it is globally activated and when - * its applicability for that root network tag is not explicitly set to false. A tag without any entry is - * applicable, and a null tag matches any root network. + * its applicability for that root network tag is true. A null tag matches any root network. + * + * @throws NetworkModificationException when the modification holds no applicability for that tag */ public boolean isActivatedOn(String rootNetworkTag) { if (Boolean.TRUE.equals(stashed) || !Boolean.TRUE.equals(activated)) { return false; } - return rootNetworkTag == null - || applicabilityByRootNetworkTag == null - || !Boolean.FALSE.equals(applicabilityByRootNetworkTag.get(rootNetworkTag)); + if (rootNetworkTag == null) { + return true; + } + Boolean applicable = applicabilityByRootNetworkTag == null ? null : applicabilityByRootNetworkTag.get(rootNetworkTag); + if (applicable == null) { + throw new NetworkModificationException(MISSING_ROOT_NETWORK_APPLICABILITY, + String.format("modification %s, root network tag %s", uuid, rootNetworkTag)); + } + return applicable; } @JsonIgnore diff --git a/src/main/java/org/gridsuite/modification/error/NetworkModificationExceptionType.java b/src/main/java/org/gridsuite/modification/error/NetworkModificationExceptionType.java index 0432c1c34..dd590442a 100644 --- a/src/main/java/org/gridsuite/modification/error/NetworkModificationExceptionType.java +++ b/src/main/java/org/gridsuite/modification/error/NetworkModificationExceptionType.java @@ -79,7 +79,8 @@ public enum NetworkModificationExceptionType { UNSUPPORTED_HYBRID_HVDC("The hybrid HVDC line is not supported"), MODIFY_VOLTAGE_LEVEL_TOPOLOGY_ERROR("An error occurred while modifying the voltage level topology"), CREATE_VOLTAGE_LEVEL_TOPOLOGY_ERROR("An error occurred while creating the voltage level topology"), - MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR("An error occurred while moving the voltage level feeder bays"); + MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR("An error occurred while moving the voltage level feeder bays"), + MISSING_ROOT_NETWORK_APPLICABILITY("The modification has no applicability for the root network"); private final String message; diff --git a/src/test/java/org/gridsuite/modification/dto/ModificationInfosTest.java b/src/test/java/org/gridsuite/modification/dto/ModificationInfosTest.java index 85ec8361e..9faa43f6e 100644 --- a/src/test/java/org/gridsuite/modification/dto/ModificationInfosTest.java +++ b/src/test/java/org/gridsuite/modification/dto/ModificationInfosTest.java @@ -8,6 +8,7 @@ import com.powsybl.commons.report.ReportNode; import org.gridsuite.modification.context.ModificationContext; +import org.gridsuite.modification.error.NetworkModificationException; import org.junit.jupiter.api.Test; import java.util.Collections; @@ -116,24 +117,35 @@ void testActivatedWhenNoRootNetworkTagGiven() { } @Test - void testActivatedWhenNoApplicabilityDefined() { - assertTrue(modificationInfos(true, null).isActivatedOn(TAG), - "A modification without any applicability is activated on every root network"); + void testThrowsWhenNoApplicabilityDefined() { + ModificationInfos modificationInfos = modificationInfos(true, null); + assertThrows(NetworkModificationException.class, () -> modificationInfos.isActivatedOn(TAG), + "A modification without any applicability is associated with no root network"); + assertTrue(modificationInfos.isActivatedOn(null), + "Without a root network context, no applicability is needed"); } @Test - void testActivatedWhenTagHasNoEntry() { - assertTrue(modificationInfos(true, Map.of()).isActivatedOn(TAG), - "A modification without any applicability entry for a tag is activated on it"); - assertTrue(modificationInfos(true, Map.of(OTHER_TAG, false)).isActivatedOn(TAG), - "An entry deactivating another tag leaves this one applicable"); + void testThrowsWhenTagHasNoEntry() { + ModificationInfos withoutEntry = modificationInfos(true, Map.of()); + assertThrows(NetworkModificationException.class, () -> withoutEntry.isActivatedOn(TAG), + "A modification without any applicability entry for a tag is not associated with it"); + ModificationInfos withOtherEntry = modificationInfos(true, Map.of(OTHER_TAG, false)); + assertThrows(NetworkModificationException.class, () -> withOtherEntry.isActivatedOn(TAG), + "An entry for another tag says nothing about this one"); } @Test - void testActivatedWhenTagEntryIsNull() { - // singletonMap, not Map.of, which rejects a null value - assertTrue(modificationInfos(true, Collections.singletonMap(TAG, null)).isActivatedOn(TAG), - "A tag mapped to no value is applicable: only an explicit false deactivates it"); + void testThrowsWhenTagEntryIsNull() { + ModificationInfos modificationInfos = modificationInfos(true, Collections.singletonMap(TAG, null)); + assertThrows(NetworkModificationException.class, () -> modificationInfos.isActivatedOn(TAG), + "A tag mapped to no value is not an applicability"); + } + + @Test + void testNoApplicabilityNeededWhenNotActivated() { + assertFalse(modificationInfos(false, Map.of()).isActivatedOn(TAG), + "A deactivated modification is not applied, whether it is associated with the root network or not"); } @Test