diff --git a/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java b/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java index 834852e..3d3655b 100644 --- a/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java +++ b/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java @@ -23,7 +23,7 @@ public abstract class AbstractGlobalFilterService implements FilterLoader { protected List getFilteredIds(@NonNull final UUID networkUuid, @NonNull final String variantId, @NonNull final GlobalFilter globalFilter, @NonNull final List equipmentTypes) { final Network network = getNetwork(networkUuid, variantId); - return GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, List.of(), equipmentTypes, this) + return GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, equipmentTypes, this) .values() .stream() .filter(Objects::nonNull) diff --git a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java index 008a41c..3e3d05c 100644 --- a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java +++ b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java @@ -4,6 +4,7 @@ import com.powsybl.iidm.network.Country; import com.powsybl.iidm.network.Identifiable; import com.powsybl.iidm.network.Network; +import org.apache.commons.collections4.CollectionUtils; import org.gridsuite.filter.AbstractFilter; import org.gridsuite.filter.FilterLoader; import org.gridsuite.filter.expertfilter.ExpertFilter; @@ -140,23 +141,19 @@ public static AbstractExpertRule createFilterBasedRule(List filt } /** - * {@link FilterLoader#getFilters(List) Loads} generic filters by their {@link UUID UUIDs}, - * then builds {@link AbstractExpertRule expert rule}, taking into account the {@link EquipmentType equipment type}. - * @param genericFilterIds the generic filter {@link UUID UUIDs} to load and build rules for - * @return the {@link List list} of {@link AbstractExpertRule expert rules} built from the loaded generic filters. + * builds AbstractExpertRule expert rule + * @param genericFilters the generic filters to build rules for + * @return {@link AbstractExpertRule expert rules} built from the loaded generic filters. */ - public static AbstractExpertRule buildGenericFilterRule(@Nonnull final List genericFilterIds, - @Nonnull final EquipmentType actualType, - @Nonnull final FilterLoader filterLoader) { - /* note: We can't do a FilterUuidExpertRule IS_PART_OF rule here because we need to know the equipment type - * the filter is intended to deduce on what field to apply the rule. */ - final List rules = new ArrayList<>(genericFilterIds.size()); - List filters = filterLoader.getFilters(genericFilterIds); + public static AbstractExpertRule buildGenericFilterRule(@Nonnull final List genericFilters, + @Nonnull final EquipmentType actualType) { + final List rules = new ArrayList<>(); // Create only one OR rule for all filters with same type (matches actualType exclude substation and voltage levels) - if (!actualType.equals(EquipmentType.VOLTAGE_LEVEL) && !actualType.equals(EquipmentType.SUBSTATION)) { - List typeMatches = filters.stream().filter(abstractFilter -> - abstractFilter.getEquipmentType().equals(actualType)).toList(); + if (actualType != EquipmentType.VOLTAGE_LEVEL && actualType != EquipmentType.SUBSTATION) { + List typeMatches = genericFilters.stream() + .filter(abstractFilter -> abstractFilter.getEquipmentType() == actualType) + .toList(); AbstractExpertRule typeMatchesRule = createFilterBasedRule(typeMatches, Set.of(FieldType.ID)); if (typeMatchesRule != null) { @@ -168,8 +165,8 @@ public static AbstractExpertRule buildGenericFilterRule(@Nonnull final List subsStationsAndVoltageLevelsRules = new ArrayList<>(); // Create substations rule - List substations = filters.stream() - .filter(abstractFilter -> abstractFilter.getEquipmentType().equals(EquipmentType.SUBSTATION)) + List substations = genericFilters.stream() + .filter(abstractFilter -> abstractFilter.getEquipmentType() == EquipmentType.SUBSTATION) .toList(); if (!substations.isEmpty()) { AbstractExpertRule substationsRule = createFilterBasedRule(substations, @@ -180,8 +177,8 @@ public static AbstractExpertRule buildGenericFilterRule(@Nonnull final List voltageLevels = filters.stream() - .filter(abstractFilter -> abstractFilter.getEquipmentType().equals(EquipmentType.VOLTAGE_LEVEL)) + List voltageLevels = genericFilters.stream() + .filter(abstractFilter -> abstractFilter.getEquipmentType() == EquipmentType.VOLTAGE_LEVEL) .toList(); if (!voltageLevels.isEmpty()) { AbstractExpertRule voltageLevelsRule = createFilterBasedRule(voltageLevels, @@ -204,9 +201,23 @@ public static AbstractExpertRule buildGenericFilterRule(@Nonnull final List genericFilters) { final List andRules = new ArrayList<>(); + + // Generic filter have a priority on other filter types + if (!shouldProcessEquipmentType(equipmentType, genericFilters)) { + return null; + } + + if (CollectionUtils.isNotEmpty(genericFilters)) { + AbstractExpertRule genericRule = buildGenericFilterRule(genericFilters, equipmentType); + if (genericRule != null) { + andRules.add(genericRule); + } + } + if (globalFilter.getNominalV() != null) { buildNominalVoltageRules(globalFilter.getNominalV(), equipmentType).ifPresent(andRules::add); } @@ -217,12 +228,7 @@ public static ExpertFilter buildExpertFilter(@Nonnull final GlobalFilter globalF // custom extension with apps-metadata server buildSubstationPropertyRules(globalFilter.getSubstationProperty(), equipmentType).ifPresent(andRules::add); } - if (globalFilter.getGenericFilter() != null) { - AbstractExpertRule genericRule = buildGenericFilterRule(globalFilter.getGenericFilter(), equipmentType, filterLoader); - if (genericRule != null) { - andRules.add(genericRule); - } - } + return ExpertFilterUtils.buildAndCombination(andRules) .map(rule -> new ExpertFilter(UuidUtils.generateUUID(), TimeUtils.nowAsDate(), equipmentType, rule)) .orElse(null); @@ -257,27 +263,51 @@ public static List applyFilterOnNetwork(@Nonnull final AbstractFilter fi */ @Nonnull public static List applyGlobalFilterOnNetwork(@Nonnull final Network network, - @Nonnull final GlobalFilter globalFilter, @Nonnull final List genericFilters, - @Nonnull final EquipmentType equipmentType, @Nonnull final FilterLoader filterLoader) { - List> allFilterResults = new ArrayList<>(1 + genericFilters.size()); + @Nonnull final GlobalFilter globalFilter, + @Nonnull final EquipmentType equipmentType, + final List genericFilters, + @Nonnull final FilterLoader filterLoader) { + List allFilterResults = null; // Extract IDs from expert filter - final ExpertFilter expertFilter = buildExpertFilter(globalFilter, equipmentType, filterLoader); + final ExpertFilter expertFilter = buildExpertFilter(globalFilter, equipmentType, genericFilters); if (expertFilter != null) { - allFilterResults.add(filterNetwork(expertFilter, network, filterLoader)); + allFilterResults = filterNetwork(expertFilter, network, filterLoader); } - // Extract IDs from generic filters, case for computation backend columns filters - for (final AbstractFilter filter : genericFilters) { - final List filterResult = applyFilterOnNetwork(filter, equipmentType, network, filterLoader); - if (!filterResult.isEmpty()) { - allFilterResults.add(filterResult); - } - } + // return filters List + return allFilterResults != null ? allFilterResults : List.of(); + } + + /** + * When we are filtering on several equipment types, and we have generic filters, + * we consider only equipment types that have one or more generic filter. The other types are excluded. + * Substation and Voltage level types include all equipment types, only if there is no other equipment + * type filters + * @param equipmentType : equipment type that should be processed + * @param genericFilters : generic filters list + * **/ + public static boolean shouldProcessEquipmentType(@Nonnull final EquipmentType equipmentType, + @Nonnull final ListgenericFilters) { - // Combine results with appropriate logic - // Expert filters use OR between them, generic filters use AND - return FiltersUtils.combineFilterResults(allFilterResults, !genericFilters.isEmpty()); + // The current equipment type will be process IF + // list genericFilters is empty + if (CollectionUtils.isEmpty(genericFilters)) { + return true; + } else { + // OR (list genericFilters is not empty AND + // (it is present in genericFilters OR there isn't any other equipment type in genericFilters)) + + // all effective equipment types in genericFilters + List equipmentTypesInGenericFilters = genericFilters.stream() + .map(AbstractFilter::getEquipmentType) + .filter(elem -> + elem != EquipmentType.SUBSTATION && + elem != EquipmentType.VOLTAGE_LEVEL) + .distinct().toList(); + return equipmentTypesInGenericFilters.contains(equipmentType) || + CollectionUtils.isEmpty(equipmentTypesInGenericFilters); + } } /** @@ -286,11 +316,18 @@ public static List applyGlobalFilterOnNetwork(@Nonnull final Network net */ @Nonnull public static Map> applyGlobalFilterOnNetwork(@Nonnull final Network network, - @Nonnull final GlobalFilter globalFilter, @Nonnull final List genericFilters, - @Nonnull final List equipmentTypes, @Nonnull final FilterLoader filterLoader) { + @Nonnull final GlobalFilter globalFilter, + @Nonnull final List equipmentTypes, + @Nonnull final FilterLoader filterLoader) { Map> result = new EnumMap<>(EquipmentType.class); + + List genericFilters = null; + if (CollectionUtils.isNotEmpty(globalFilter.getGenericFilter())) { + genericFilters = filterLoader.getFilters(globalFilter.getGenericFilter()); + } + for (final EquipmentType equipmentType : equipmentTypes) { - final List filteredIds = applyGlobalFilterOnNetwork(network, globalFilter, genericFilters, equipmentType, filterLoader); + final List filteredIds = applyGlobalFilterOnNetwork(network, globalFilter, equipmentType, genericFilters, filterLoader); if (!filteredIds.isEmpty()) { result.put(equipmentType, filteredIds); } diff --git a/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java b/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java index 04c0ca6..8b9a47e 100644 --- a/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java +++ b/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java @@ -14,6 +14,7 @@ import org.gridsuite.filter.utils.FiltersUtils; import org.gridsuite.filter.utils.UuidUtils; import org.gridsuite.filter.utils.expertfilter.CombinatorType; +import org.gridsuite.filter.utils.expertfilter.DataType; import org.gridsuite.filter.utils.expertfilter.FieldType; import org.gridsuite.filter.utils.expertfilter.OperatorType; import org.junit.jupiter.api.DisplayName; @@ -29,7 +30,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.when; @@ -69,6 +70,63 @@ private static void testVariableOrCombinationRule } } + @Nested + @DisplayName("filterEquipmentTypes(...)") + class FilterEquipmentTypes { + + @Test + void testNoGenericFilters() { + List genericFilters = Collections.emptyList(); + + // Expect all equipment types to be returned + assertTrue(GlobalFilterUtils.shouldProcessEquipmentType(EquipmentType.LINE, genericFilters)); + assertTrue(GlobalFilterUtils.shouldProcessEquipmentType(EquipmentType.GENERATOR, genericFilters)); + } + + @Test + void testSubstationAndVoltageLevelFilters() { + final FilterLoader loader = Mockito.mock(FilterLoader.class); + List genericFiltersUuids = List.of(UUID.randomUUID(), UUID.randomUUID()); + + // Mock the return values for your generic filters + final AbstractFilter subStationFilter = Mockito.mock(AbstractFilter.class); + Mockito.when(subStationFilter.getEquipmentType()).thenReturn(EquipmentType.SUBSTATION); + final AbstractFilter voltageLevelfilter = Mockito.mock(AbstractFilter.class); + Mockito.when(voltageLevelfilter.getEquipmentType()).thenReturn(EquipmentType.VOLTAGE_LEVEL); + + Mockito.when(loader.getFilters(genericFiltersUuids)).thenReturn(List.of( + subStationFilter, voltageLevelfilter)); + + List genericFilters = loader.getFilters(genericFiltersUuids); + + // Expect all equipment types to be returned + assertTrue(GlobalFilterUtils.shouldProcessEquipmentType(EquipmentType.LINE, genericFilters)); + assertTrue(GlobalFilterUtils.shouldProcessEquipmentType(EquipmentType.TWO_WINDINGS_TRANSFORMER, genericFilters)); + } + + @Test + void testFiltersOnOtherEquipmentTypes() { + final FilterLoader loader = Mockito.mock(FilterLoader.class); + List genericFiltersUuids = List.of(UUID.randomUUID(), UUID.randomUUID()); + + // Mock the return values for your generic filters + final AbstractFilter lineFilter = Mockito.mock(AbstractFilter.class); + Mockito.when(lineFilter.getEquipmentType()).thenReturn(EquipmentType.LINE); + + final AbstractFilter voltageLevelFilter = Mockito.mock(AbstractFilter.class); + Mockito.when(voltageLevelFilter.getEquipmentType()).thenReturn(EquipmentType.VOLTAGE_LEVEL); + + Mockito.when(loader.getFilters(genericFiltersUuids)).thenReturn(List.of( + lineFilter, voltageLevelFilter)); + + List genericFilters = loader.getFilters(genericFiltersUuids); + + // Expect only TYPE_A to be returned + assertTrue(GlobalFilterUtils.shouldProcessEquipmentType(EquipmentType.LINE, genericFilters)); + assertFalse(GlobalFilterUtils.shouldProcessEquipmentType(EquipmentType.GENERATOR, genericFilters)); + } + } + /** Trick Java to create generic array */ @SafeVarargs private static ThrowingConsumer[] createAssertArray(final ThrowingConsumer... assertions) { @@ -237,7 +295,7 @@ class BuildExpertFilter { @Test void shouldReturnNullWhenNoExpertFiltersProvided() { final GlobalFilter globalFilter = new GlobalFilter(null, null, null, null); - assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR, null)) + assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR, List.of())) .as("result").isNull(); } @@ -245,7 +303,7 @@ void shouldReturnNullWhenNoExpertFiltersProvided() { void shouldReturnNullWhenNoRules() { final GlobalFilter globalFilter = new GlobalFilter(List.of(), List.of(), List.of(), Map.of()); assertTrue(globalFilter.isEmpty()); - assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR, uuids -> List.of())) + assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR, List.of())) .as("result").isNull(); } @@ -258,7 +316,7 @@ void shouldReturnResult() { new IdentifierListFilterEquipmentAttributes("GEN2", 50.) ))); final GlobalFilter globalFilter = new GlobalFilter(List.of("380", "225"), List.of(Country.FR, Country.BE), filterUuids, Map.of()); - assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR, uuids -> filters)) + assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR, filters)) .as("result").isNotNull(); } @@ -271,7 +329,7 @@ void shouldReturnResultWithGenericFilterTypeDifferentFromEquipmentType() { new IdentifierListFilterEquipmentAttributes("GEN2", 50.) ))); final GlobalFilter globalFilter = new GlobalFilter(List.of("380", "225"), List.of(Country.FR, Country.BE), filterUuids, Map.of()); - assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR, uuids -> filters)) + assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR, filters)) .as("result").isNotNull(); } } @@ -381,24 +439,43 @@ class ApplyGlobalFilterOnNetworkWithSingleEquipmentType { void shouldReturnFilteredNetworkWhenSameEquipmentType() { final Network network = Mockito.mock(Network.class); final FilterLoader loader = Mockito.mock(FilterLoader.class); - final AbstractFilter filter = Mockito.mock(AbstractFilter.class); + + final AbstractFilter genericFilter = Mockito.mock(AbstractFilter.class); + when(genericFilter.getEquipmentType()).thenReturn(EquipmentType.GENERATOR); + final UUID filterUuid = UuidUtils.createUUID(0); + when(genericFilter.getId()).thenReturn(filterUuid); + final GlobalFilter globalFilter = Mockito.mock(GlobalFilter.class); - when(filter.getEquipmentType()).thenReturn(EquipmentType.GENERATOR); + List genericFilterUuids = List.of(filterUuid); + when(globalFilter.getGenericFilter()).thenReturn(genericFilterUuids); + + when(loader.getFilters(genericFilterUuids)).thenReturn(List.of(genericFilter)); + try (final MockedStatic mockedFU = Mockito.mockStatic(FiltersUtils.class, Mockito.CALLS_REAL_METHODS)) { final Identifiable gen1 = Mockito.mock(Identifiable.class); when(gen1.getId()).thenReturn("gen1"); final Identifiable gen2 = Mockito.mock(Identifiable.class); when(gen2.getId()).thenReturn("gen2"); final List> attributes = List.of(gen1, gen2); - mockedFU.when(() -> FiltersUtils.getIdentifiables(filter, network, loader)).thenReturn(attributes); + mockedFU.when(() -> FiltersUtils.getIdentifiables(argThat((ExpertFilter isPartOfFilter) -> + isPartOfFilter != null && + isPartOfFilter.getRules().getDataType() == DataType.FILTER_UUID && + ((FilterUuidExpertRule) isPartOfFilter.getRules()).getValues().contains(filterUuid.toString()) + ), eq(network), eq(loader))).thenReturn(attributes); mockedFU.clearInvocations(); //important because stubbing static method counts as call - assertThat(GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, List.of(filter), EquipmentType.GENERATOR, loader)) - .as("result").containsExactlyInAnyOrder("gen1", "gen2"); - Mockito.verify(filter, Mockito.atLeastOnce()).getEquipmentType(); + + // call test method and check result + assertThat(GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, List.of(EquipmentType.GENERATOR), loader)) + .as("result").containsExactlyInAnyOrderEntriesOf(Map.of(EquipmentType.GENERATOR, List.of("gen1", "gen2"))); + + // check some interactions + Mockito.verify(genericFilter, Mockito.atLeastOnce()).getEquipmentType(); + Mockito.verify(genericFilter, Mockito.atLeastOnce()).getId(); + Mockito.verify(globalFilter, Mockito.atLeastOnce()).getGenericFilter(); Mockito.verify(gen1, Mockito.atLeastOnce()).getId(); Mockito.verify(gen2, Mockito.atLeastOnce()).getId(); - Mockito.verifyNoMoreInteractions(filter, network, gen1, gen2); - mockedFU.verify(() -> FiltersUtils.getIdentifiables(eq(filter), eq(network), eq(loader)), Mockito.atLeastOnce()); + Mockito.verifyNoMoreInteractions(genericFilter, network, gen1, gen2); + mockedFU.verify(() -> FiltersUtils.getIdentifiables(any(ExpertFilter.class), eq(network), eq(loader)), Mockito.atLeastOnce()); } } @@ -419,7 +496,7 @@ void shouldBuildVoltageLevelFilterWhenVoltageLevelType() { final List> attributes = List.of(line1, line2); mockedFU.when(() -> FiltersUtils.getIdentifiables(any(ExpertFilter.class), eq(network), eq(loader))).thenReturn(attributes); mockedFU.clearInvocations(); //important because stubbing static method counts as call - assertThat(GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, List.of(filter), EquipmentType.LINE, loader)) + assertThat(GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, EquipmentType.LINE, List.of(filter), loader)) .as("result").containsExactlyInAnyOrder("line1", "line2"); Mockito.verify(filter, Mockito.atLeastOnce()).getEquipmentType(); Mockito.verify(filter, Mockito.atLeastOnce()).getId(); @@ -437,7 +514,7 @@ void shouldReturnEmptyWhenDifferentEquipmentType() { final AbstractFilter filter = Mockito.mock(AbstractFilter.class); final GlobalFilter globalFilter = Mockito.mock(GlobalFilter.class); when(filter.getEquipmentType()).thenReturn(EquipmentType.LOAD); - assertThat(GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, List.of(filter), EquipmentType.GENERATOR, loader)) + assertThat(GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, EquipmentType.GENERATOR, List.of(filter), loader)) .as("result").isEmpty(); Mockito.verify(filter, Mockito.atLeastOnce()).getEquipmentType(); Mockito.verifyNoMoreInteractions(network, filter); @@ -451,25 +528,106 @@ class ApplyGlobalFilterOnNetworkWithMultipleEquipmentType { void shouldReturnFilteredNetwork() { final Network network = Mockito.mock(Network.class); final FilterLoader loader = Mockito.mock(FilterLoader.class); - final AbstractFilter filter = Mockito.mock(AbstractFilter.class); + + final AbstractFilter filterLine = Mockito.mock(AbstractFilter.class); + when(filterLine.getEquipmentType()).thenReturn(EquipmentType.LINE); + final UUID filterLineUuid = UuidUtils.createUUID(0); + when(filterLine.getId()).thenReturn(filterLineUuid); + + final AbstractFilter filterTrans = Mockito.mock(AbstractFilter.class); + when(filterTrans.getEquipmentType()).thenReturn(EquipmentType.TWO_WINDINGS_TRANSFORMER); + final UUID filterTransUuid = UuidUtils.createUUID(1); + when(filterTrans.getId()).thenReturn(filterTransUuid); + final GlobalFilter globalFilter = Mockito.mock(GlobalFilter.class); - when(filter.getEquipmentType()).thenReturn(EquipmentType.GENERATOR); + List genericFilterUuids = List.of(filterLineUuid, filterTransUuid); + when(globalFilter.getGenericFilter()).thenReturn(genericFilterUuids); + + when(loader.getFilters(genericFilterUuids)).thenReturn(List.of(filterLine, filterTrans)); + try (final MockedStatic mockedFU = Mockito.mockStatic(FiltersUtils.class, Mockito.CALLS_REAL_METHODS)) { final Identifiable line1 = Mockito.mock(Identifiable.class); when(line1.getId()).thenReturn("line1"); + final List> lineAttributes = List.of(line1); final Identifiable trf1 = Mockito.mock(Identifiable.class); when(trf1.getId()).thenReturn("trf1"); - final List> attributes = List.of(line1, trf1); - mockedFU.when(() -> FiltersUtils.getIdentifiables(filter, network, loader)).thenReturn(attributes); + final List> transAttributes = List.of(trf1); + mockedFU.when(() -> FiltersUtils.getIdentifiables(argThat((ExpertFilter isPartOfFilter) -> + isPartOfFilter != null && + isPartOfFilter.getRules().getOperator() == OperatorType.IS_PART_OF && + ((FilterUuidExpertRule) isPartOfFilter.getRules()).getValues().contains(filterLineUuid.toString()) + ), eq(network), eq(loader))).thenReturn(lineAttributes); + mockedFU.when(() -> FiltersUtils.getIdentifiables(argThat((ExpertFilter isPartOfFilter) -> + isPartOfFilter != null && + isPartOfFilter.getRules().getOperator() == OperatorType.IS_PART_OF && + ((FilterUuidExpertRule) isPartOfFilter.getRules()).getValues().contains(filterTransUuid.toString()) + ), eq(network), eq(loader))).thenReturn(transAttributes); mockedFU.clearInvocations(); //important because stubbing static method counts as call - assertThat(GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, List.of(filter), List.of(EquipmentType.GENERATOR), loader)) - .as("result").containsExactlyInAnyOrderEntriesOf(Map.of(EquipmentType.GENERATOR, List.of("line1", "trf1"))); - Mockito.verify(filter, Mockito.atLeastOnce()).getEquipmentType(); + + // call test method and check result + assertThat(GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, + List.of(EquipmentType.LINE, EquipmentType.TWO_WINDINGS_TRANSFORMER, EquipmentType.GENERATOR), loader)) + .as("result").containsExactlyInAnyOrderEntriesOf(Map.of(EquipmentType.LINE, List.of("line1"), EquipmentType.TWO_WINDINGS_TRANSFORMER, List.of("trf1"))); + + // check some interactions + Mockito.verify(filterLine, Mockito.atLeastOnce()).getEquipmentType(); + Mockito.verify(filterLine, Mockito.atLeastOnce()).getId(); + Mockito.verify(filterTrans, Mockito.atLeastOnce()).getEquipmentType(); + Mockito.verify(filterTrans, Mockito.atLeastOnce()).getId(); Mockito.verify(line1, Mockito.atLeastOnce()).getId(); Mockito.verify(trf1, Mockito.atLeastOnce()).getId(); - Mockito.verifyNoMoreInteractions(filter, network, line1, trf1); - mockedFU.verify(() -> FiltersUtils.getIdentifiables(eq(filter), eq(network), eq(loader)), Mockito.atLeastOnce()); + Mockito.verifyNoMoreInteractions(filterLine, filterTrans, network, line1, trf1); + mockedFU.verify(() -> FiltersUtils.getIdentifiables(any(ExpertFilter.class), eq(network), eq(loader)), Mockito.atLeastOnce()); } } } + + @Nested + @DisplayName("buildGenericFilterRule(...)") + class BuildGenericFilterRuleTests { + + @Test + void testSameEquipmentType() { + List filterUuids = List.of(UUID.randomUUID(), UUID.randomUUID()); + AbstractFilter filter1 = Mockito.mock(AbstractFilter.class); + AbstractFilter filter2 = Mockito.mock(AbstractFilter.class); + when(filter1.getEquipmentType()).thenReturn(EquipmentType.LINE); + when(filter2.getEquipmentType()).thenReturn(EquipmentType.LINE); + when(filter1.getId()).thenReturn(filterUuids.get(0)); + when(filter2.getId()).thenReturn(filterUuids.get(1)); + + List filters = Arrays.asList(filter1, filter2); + assertNotNull(GlobalFilterUtils.buildGenericFilterRule(filters, EquipmentType.LINE)); + } + + @Test + void testSubstationAndVoltageLevelOnAnyEquipmentType() { + List filterUuids = List.of(UUID.randomUUID(), UUID.randomUUID()); + AbstractFilter filter1 = Mockito.mock(AbstractFilter.class); + AbstractFilter filter2 = Mockito.mock(AbstractFilter.class); + when(filter1.getEquipmentType()).thenReturn(EquipmentType.VOLTAGE_LEVEL); + when(filter2.getEquipmentType()).thenReturn(EquipmentType.SUBSTATION); + when(filter1.getId()).thenReturn(filterUuids.get(0)); + when(filter2.getId()).thenReturn(filterUuids.get(1)); + + List filters = Arrays.asList(filter1, filter2); + assertNotNull(GlobalFilterUtils.buildGenericFilterRule(filters, EquipmentType.LINE)); + assertNotNull(GlobalFilterUtils.buildGenericFilterRule(filters, EquipmentType.GENERATOR)); + assertNotNull(GlobalFilterUtils.buildGenericFilterRule(filters, EquipmentType.TWO_WINDINGS_TRANSFORMER)); + } + + @Test + void testNotSameEquipmentType() { + List filterUuids = List.of(UUID.randomUUID(), UUID.randomUUID()); + AbstractFilter filter1 = Mockito.mock(AbstractFilter.class); + AbstractFilter filter2 = Mockito.mock(AbstractFilter.class); + when(filter1.getEquipmentType()).thenReturn(EquipmentType.LINE); + when(filter2.getEquipmentType()).thenReturn(EquipmentType.TWO_WINDINGS_TRANSFORMER); + when(filter1.getId()).thenReturn(filterUuids.get(0)); + when(filter2.getId()).thenReturn(filterUuids.get(1)); + + List filters = Arrays.asList(filter1, filter2); + assertNull(GlobalFilterUtils.buildGenericFilterRule(filters, EquipmentType.GENERATOR)); + } + } }