CgmesGLExporterTest.java

/**
 * Copyright (c) 2019, RTE (http://www.rte-france.com)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * SPDX-License-Identifier: MPL-2.0
 */
package com.powsybl.cgmes.gl;

import com.google.common.collect.ImmutableList;
import com.powsybl.cgmes.model.CgmesNamespace;
import com.powsybl.cgmes.model.CgmesSubset;
import com.powsybl.commons.datasource.DataSource;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.Coordinate;
import com.powsybl.iidm.network.extensions.LinePosition;
import com.powsybl.iidm.network.extensions.SubstationPosition;
import com.powsybl.iidm.network.impl.extensions.LinePositionImpl;
import com.powsybl.iidm.network.impl.extensions.SubstationPositionImpl;
import com.powsybl.triplestore.api.PropertyBag;
import com.powsybl.triplestore.api.TripleStore;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;

import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 *
 * @author Massimo Ferraro {@literal <massimo.ferraro@techrain.eu>}
 */
class CgmesGLExporterTest {

    private static final Coordinate SUBSTATION_1 = new Coordinate(51.380348205566406, 0.5492960214614868);
    private static final Coordinate SUBSTATION_2 = new Coordinate(52.00010299682617, 0.30759671330451965);
    private static final Coordinate LINE_1 = new Coordinate(51.529258728027344, 0.5132722854614258);
    private static final Coordinate LINE_2 = new Coordinate(51.944923400878906, 0.4120868146419525);

    private Network network;

    @BeforeEach
    void setUp() {
        network = Network.create("Network", "test");
        network.setCaseDate(ZonedDateTime.parse("2018-01-01T00:30:00.000+01:00"));
        Substation substation1 = network.newSubstation()
                .setId("Substation1")
                .setCountry(Country.FR)
                .add();
        VoltageLevel voltageLevel1 = substation1.newVoltageLevel()
                .setId("VoltageLevel1")
                .setNominalV(400)
                .setTopologyKind(TopologyKind.BUS_BREAKER)
                .add();
        voltageLevel1.getBusBreakerView().newBus()
                .setId("Bus1")
                .add();
        Substation substation2 = network.newSubstation()
                .setId("Substation2")
                .setCountry(Country.FR)
                .add();
        VoltageLevel voltageLevel2 = substation2.newVoltageLevel()
                .setId("VoltageLevel2")
                .setNominalV(400)
                .setTopologyKind(TopologyKind.BUS_BREAKER)
                .add();
        voltageLevel2.getBusBreakerView().newBus()
                .setId("Bus2")
                .add();
        network.newLine()
                .setId("Line")
                .setVoltageLevel1(voltageLevel1.getId())
                .setBus1("Bus1")
                .setConnectableBus1("Bus1")
                .setVoltageLevel2(voltageLevel2.getId())
                .setBus2("Bus2")
                .setConnectableBus2("Bus2")
                .setR(3.0)
                .setX(33.0)
                .setG1(0.0)
                .setB1(386E-6 / 2)
                .setG2(0.0)
                .setB2(386E-6 / 2)
                .add();
    }

    @Test
    void test() {
        Substation substation1 = network.getSubstation("Substation1");
        SubstationPosition substationPosition1 = new SubstationPositionImpl(substation1, SUBSTATION_1);
        substation1.addExtension(SubstationPosition.class, substationPosition1);
        Substation substation2 = network.getSubstation("Substation2");
        SubstationPosition substationPosition2 = new SubstationPositionImpl(substation2, SUBSTATION_2);
        substation2.addExtension(SubstationPosition.class, substationPosition2);
        Line line = network.getLine("Line");
        line.addExtension(LinePosition.class, new LinePositionImpl<>(line, ImmutableList.of(SUBSTATION_1, LINE_1, LINE_2, SUBSTATION_2)));

        TripleStore tripleStore = Mockito.mock(TripleStore.class);
        Mockito.when(tripleStore.add(ArgumentMatchers.anyString(), ArgumentMatchers.eq(CgmesNamespace.CIM_16_NAMESPACE),
                        ArgumentMatchers.eq("CoordinateSystem"), ArgumentMatchers.any(PropertyBag.class)))
                                .thenReturn("CoordinateSystemId");

        DataSource dataSource = Mockito.mock(DataSource.class);
        Mockito.when(dataSource.getBaseName()).thenReturn(network.getId().toLowerCase());

        ArgumentCaptor<String> prefixCaptor = ArgumentCaptor.forClass(String.class);
        ArgumentCaptor<String> namespaceCaptor = ArgumentCaptor.forClass(String.class);
        ArgumentCaptor<String> contextCaptor = ArgumentCaptor.forClass(String.class);
        ArgumentCaptor<String> nsCaptor = ArgumentCaptor.forClass(String.class);
        ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class);
        ArgumentCaptor<PropertyBag> propertiesCaptor = ArgumentCaptor.forClass(PropertyBag.class);

        new CgmesGLExporter(network, tripleStore).exportData(dataSource);

        // check add namespace
        Mockito.verify(tripleStore, Mockito.times(3)).addNamespace(prefixCaptor.capture(), namespaceCaptor.capture());
        checkNamespace(prefixCaptor.getAllValues().get(0), namespaceCaptor.getAllValues().get(0), "data", "http://" + network.getId().toLowerCase() + "/#");
        checkNamespace(prefixCaptor.getAllValues().get(1), namespaceCaptor.getAllValues().get(1), "cim", CgmesNamespace.CIM_16_NAMESPACE);
        checkNamespace(prefixCaptor.getAllValues().get(2), namespaceCaptor.getAllValues().get(2), "md", CgmesGLExporter.MD_NAMESPACE);

        // check add statements
        Mockito.verify(tripleStore, Mockito.times(11)).add(contextCaptor.capture(), nsCaptor.capture(),
                       typeCaptor.capture(), propertiesCaptor.capture());
        checkCoordinateSystem(contextCaptor.getAllValues().get(1), nsCaptor.getAllValues().get(1), typeCaptor.getAllValues().get(1),
                              propertiesCaptor.getAllValues().get(1), network.getId().toLowerCase());
        checkLocation(contextCaptor.getAllValues().get(2), nsCaptor.getAllValues().get(2), typeCaptor.getAllValues().get(2),
                      propertiesCaptor.getAllValues().get(2), network.getId().toLowerCase(), "Substation1", "Substation1");
        checkPositionPoint(contextCaptor.getAllValues().get(3), nsCaptor.getAllValues().get(3), typeCaptor.getAllValues().get(3),
                           propertiesCaptor.getAllValues().get(3), network.getId().toLowerCase(), SUBSTATION_1, -1);
        checkLocation(contextCaptor.getAllValues().get(4), nsCaptor.getAllValues().get(4), typeCaptor.getAllValues().get(4),
                      propertiesCaptor.getAllValues().get(4), network.getId().toLowerCase(), "Substation2", "Substation2");
        checkPositionPoint(contextCaptor.getAllValues().get(5), nsCaptor.getAllValues().get(5), typeCaptor.getAllValues().get(5),
                           propertiesCaptor.getAllValues().get(5), network.getId().toLowerCase(), SUBSTATION_2, -1);
        checkLocation(contextCaptor.getAllValues().get(6), nsCaptor.getAllValues().get(6), typeCaptor.getAllValues().get(6),
                      propertiesCaptor.getAllValues().get(6), network.getId().toLowerCase(), "Line", "Line");
        checkPositionPoint(contextCaptor.getAllValues().get(7), nsCaptor.getAllValues().get(7), typeCaptor.getAllValues().get(7),
                           propertiesCaptor.getAllValues().get(7), network.getId().toLowerCase(), SUBSTATION_1, 1);
        checkPositionPoint(contextCaptor.getAllValues().get(8), nsCaptor.getAllValues().get(8), typeCaptor.getAllValues().get(8),
                           propertiesCaptor.getAllValues().get(8), network.getId().toLowerCase(), LINE_1, 2);
        checkPositionPoint(contextCaptor.getAllValues().get(9), nsCaptor.getAllValues().get(9), typeCaptor.getAllValues().get(9),
                           propertiesCaptor.getAllValues().get(9), network.getId().toLowerCase(), LINE_2, 3);
        checkPositionPoint(contextCaptor.getAllValues().get(10), nsCaptor.getAllValues().get(10), typeCaptor.getAllValues().get(10),
                           propertiesCaptor.getAllValues().get(10), network.getId().toLowerCase(), SUBSTATION_2, 4);
    }

    private void checkNamespace(String prefix, String ns, String expetedPrefix, String expectedNs) {
        assertEquals(expetedPrefix, prefix);
        assertEquals(expectedNs, ns);
    }

    private void checkProperties(String context, String namespace, String type, PropertyBag properties, String basename,
                                 String expectedType, List<String> expectedProperties, List<String> expectedResources,
                                 List<String> expectedClassProperties) {
        assertTrue(CgmesSubset.GEOGRAPHICAL_LOCATION.isValidName(context));
        assertEquals(basename + "_" + CgmesSubset.GEOGRAPHICAL_LOCATION.getIdentifier() + ".xml", context);
        assertEquals(CgmesNamespace.CIM_16_NAMESPACE, namespace);
        assertEquals(expectedType, type);
        assertEquals(expectedProperties.size(), properties.propertyNames().size());
        expectedProperties.forEach(property -> assertTrue(properties.propertyNames().contains(property)));
        expectedResources.forEach(resource -> assertTrue(properties.isResource(resource)));
        expectedClassProperties.forEach(classProperty -> assertTrue(properties.isClassProperty(classProperty)));
    }

    private void checkCoordinateSystem(String context, String namespace, String type, PropertyBag properties, String basename) {
        checkProperties(context, namespace, type, properties, basename, "CoordinateSystem",
                Arrays.asList("IdentifiedObject.name", "crsUrn"), Collections.emptyList(),
                List.of("IdentifiedObject.name"));
        assertEquals(CgmesGLUtils.COORDINATE_SYSTEM_URN, properties.get("crsUrn"));
    }

    private void checkLocation(String context, String namespace, String type, PropertyBag properties, String basename,
                               String expectedName, String expectedPowerSystemResource) {
        checkProperties(context, namespace, type, properties, basename, "Location",
                Arrays.asList("IdentifiedObject.name", "CoordinateSystem", "PowerSystemResources"),
                Arrays.asList("CoordinateSystem", "PowerSystemResources"),
                List.of("IdentifiedObject.name"));
        assertEquals(expectedName, properties.get("IdentifiedObject.name"));
        assertEquals("CoordinateSystemId", properties.get("CoordinateSystem"));
        assertEquals(expectedPowerSystemResource, properties.get("PowerSystemResources"));
    }

    private void checkPositionPoint(String context, String namespace, String type, PropertyBag properties, String basename,
                                    Coordinate expectedCoordinate, int expectedSeq) {
        checkProperties(context, namespace, type, properties, basename, "PositionPoint",
                expectedSeq == -1 ? Arrays.asList("xPosition", "yPosition", "Location") : Arrays.asList("xPosition", "yPosition", "sequenceNumber", "Location"),
                List.of("Location"), Collections.emptyList());
        assertEquals(expectedCoordinate.getLongitude(), properties.asDouble("xPosition"), 0);
        assertEquals(expectedCoordinate.getLatitude(), properties.asDouble("yPosition"), 0);
        if (expectedSeq != -1) {
            assertEquals(expectedSeq, properties.asInt("sequenceNumber"), 0);
        }
    }

}