diff --git a/pom.xml b/pom.xml index c1c3695ad..e15bab689 100644 --- a/pom.xml +++ b/pom.xml @@ -30,14 +30,13 @@ 17 - local-SNAPSHOT ${java.version} ${java.version} UTF-8 sct-coverage/** ../sct-coverage/target/site/jacoco-aggregate/jacoco.xml ${basedir}/${aggregate.report.dir} - 0.13.0 + 0.14.0 0.0.4 3.4.1 3.2.1 diff --git a/sct-app/src/test/resources/std_1.xml b/sct-app/src/test/resources/std_1.xml index de295e154..076f9b3a5 100644 --- a/sct-app/src/test/resources/std_1.xml +++ b/sct-app/src/test/resources/std_1.xml @@ -34,7 +34,11 @@ - + diff --git a/sct-app/src/test/resources/std_2.xml b/sct-app/src/test/resources/std_2.xml index 42228c889..e646dcb2f 100644 --- a/sct-app/src/test/resources/std_2.xml +++ b/sct-app/src/test/resources/std_2.xml @@ -34,7 +34,11 @@ - + diff --git a/sct-app/src/test/resources/std_3.xml b/sct-app/src/test/resources/std_3.xml index 38ce30c55..acf7a87f9 100644 --- a/sct-app/src/test/resources/std_3.xml +++ b/sct-app/src/test/resources/std_3.xml @@ -34,7 +34,11 @@ - + diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlockTarget.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlockTarget.java index 25a75f5ad..5db7173b1 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlockTarget.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlockTarget.java @@ -11,8 +11,6 @@ import java.util.Objects; import static org.lfenergy.compas.scl2007b4.model.TControlWithIEDName.IEDName; -import static org.lfenergy.compas.sct.commons.util.Utils.emptyIfBlank; -import static org.lfenergy.compas.sct.commons.util.Utils.nullIfBlank; /** * Record that hold the data for TClientLN and TControlWithIEDName.IEDName which have the same fields. @@ -50,8 +48,8 @@ public TClientLN toTClientLn() { newTClientLn.getLnClass().add(lnClass); } // LnInst is required on TClientLN, so it cannot be null, but it can be empty - newTClientLn.setLnInst(emptyIfBlank(lnInst)); - newTClientLn.setPrefix(nullIfBlank(prefix)); + newTClientLn.setLnInst(StringUtils.trimToEmpty(lnInst)); + newTClientLn.setPrefix(StringUtils.trimToNull(prefix)); newTClientLn.setDesc(desc); return newTClientLn; } @@ -69,8 +67,8 @@ public IEDName toIedName() { newIedName.getLnClass().add(lnClass); } // LnInst is optional on IEDName, so it can be null, but cannot be empty - newIedName.setLnInst(nullIfBlank(lnInst)); - newIedName.setPrefix(nullIfBlank(prefix)); + newIedName.setLnInst(StringUtils.trimToNull(lnInst)); + newIedName.setPrefix(StringUtils.trimToNull(prefix)); return newIedName; } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplate.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplate.java index f16c6dc2d..b41db1eee 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplate.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplate.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.*; +import org.apache.commons.lang3.StringUtils; import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.scl.ied.AbstractLNAdapter; import org.lfenergy.compas.sct.commons.util.SclConstructorHelper; @@ -15,7 +16,7 @@ import java.util.Optional; import static org.lfenergy.compas.sct.commons.util.CommonConstants.MOD_DO_NAME; -import static org.lfenergy.compas.sct.commons.util.CommonConstants.STVAL; +import static org.lfenergy.compas.sct.commons.util.CommonConstants.STVAL_DA_NAME; /** @@ -54,13 +55,23 @@ public class ResumedDataTemplate { /** * Constructor */ - public ResumedDataTemplate(AbstractLNAdapter lnAdapter, String doName, String daName) { + public ResumedDataTemplate(AbstractLNAdapter lnAdapter, DoTypeName doName, DaTypeName daName) { this.lnClass = lnAdapter.getLNClass(); this.lnInst = lnAdapter.getLNInst(); this.prefix = lnAdapter.getPrefix(); this.lnType = lnAdapter.getLnType(); - this.doName = new DoTypeName(doName); - this.daName = new DaTypeName(daName); + this.doName = doName; + this.daName = daName; + } + + public ResumedDataTemplate(TFCDA fcda) { + this.lnClass = fcda.isSetLnClass() ? fcda.getLnClass().get(0) : null; + this.lnInst = fcda.getLnInst(); + this.prefix = fcda.getPrefix(); + this.lnType = null; + this.doName = new DoTypeName(StringUtils.trimToEmpty(fcda.getDoName())); + this.daName = new DaTypeName(StringUtils.trimToEmpty(fcda.getDaName())); + if (daName.isDefined()) this.setFc(fcda.getFc()); } /** @@ -94,7 +105,7 @@ public boolean isUpdatable(){ * @return true if DO is "Mod" and DA is "stVal", false otherwise */ private boolean isDOModDAstVal(){ - return doName.getName().equals(MOD_DO_NAME) && daName.getName().equals(STVAL); + return doName.getName().equals(MOD_DO_NAME) && daName.getName().equals(STVAL_DA_NAME); } @JsonIgnore diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ExtRefService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ExtRefService.java index e1f54c278..e581ef34d 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ExtRefService.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ExtRefService.java @@ -4,7 +4,6 @@ package org.lfenergy.compas.sct.commons.scl; -import lombok.experimental.UtilityClass; import org.apache.commons.lang3.StringUtils; import org.lfenergy.compas.scl2007b4.model.SCL; import org.lfenergy.compas.scl2007b4.model.TCompasICDHeader; @@ -30,11 +29,14 @@ import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.*; import static org.lfenergy.compas.sct.commons.util.Utils.isExtRefFeedBySameControlBlock; -@UtilityClass -public class ExtRefService { +public final class ExtRefService { private static final String MESSAGE_MISSING_IED_NAME_PARAMETER = "IED.name parameter is missing"; + private ExtRefService() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + /** * Updates iedName attribute of all ExtRefs in the Scd. * @@ -203,7 +205,7 @@ private static List configureNetworkForControlBlocks(SCL scd, Con private static Optional configureControlBlockNetwork(ControlBlockNetworkSettings controlBlockNetworkSettings, PrimitiveIterator.OfLong appIdIterator, Iterator macAddressIterator, ControlBlockAdapter controlBlockAdapter) { SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter); - if (settingsOrError.errorMessage() != null){ + if (settingsOrError.errorMessage() != null) { return Optional.of(controlBlockAdapter.buildFatalReportItem( "Cannot configure network for this ControlBlock because: " + settingsOrError.errorMessage())); } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/HmiService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/HmiService.java new file mode 100644 index 000000000..9b72b2544 --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/HmiService.java @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2023 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.scl; + +import org.lfenergy.compas.scl2007b4.model.SCL; +import org.lfenergy.compas.scl2007b4.model.TFCDA; +import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter; + +import java.util.List; + +public final class HmiService { + + private HmiService() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + /** + * Create the DataSet and ReportControl Blocks for the HMI with the given FCDAs. + * + * @param fcdas List of FCDA for which we must create the DataSet and ReportControl Blocks + */ + public static void createAllHmiReportControlBlocks(SCL scd, List fcdas) { + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + sclRootAdapter.streamIEDAdapters() + .flatMap(IEDAdapter::streamLDeviceAdapters) + .forEach(lDeviceAdapter -> lDeviceAdapter.createHmiReportControlBlocks(fcdas)); + } + +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ObjectReference.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ObjectReference.java index 0701ea0e4..9f1c02d31 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ObjectReference.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ObjectReference.java @@ -9,7 +9,6 @@ import org.lfenergy.compas.scl2007b4.model.TExtRef; import org.lfenergy.compas.scl2007b4.model.TLLN0Enum; import org.lfenergy.compas.sct.commons.dto.ExtrefTarget; -import org.lfenergy.compas.sct.commons.util.Utils; /** * A representation of the model object @@ -55,16 +54,22 @@ public ObjectReference(String reference) { public ObjectReference(TExtRef extRef, ExtrefTarget target) { this.ldName = extRef.getIedName() + extRef.getLdInst(); if(target.equals(ExtrefTarget.SRC_REF)) { - this.lNodeName = Utils.emptyIfBlank(extRef.getPrefix()) - + (extRef.isSetLnClass() ? extRef.getLnClass().get(0): TLLN0Enum.LLN_0.value()) - + Utils.emptyIfBlank(extRef.getLnInst()); - this.dataAttributes = Utils.emptyIfBlank(extRef.getDoName()); + String s1 = extRef.getLnInst(); + String s2 = extRef.getPrefix(); + this.lNodeName = StringUtils.trimToEmpty(s2) + + (extRef.isSetLnClass() ? extRef.getLnClass().get(0) : TLLN0Enum.LLN_0.value()) + + StringUtils.trimToEmpty(s1); + String s = extRef.getDoName(); + this.dataAttributes = StringUtils.trimToEmpty(s); } if(target.equals(ExtrefTarget.SRC_CB)) { - this.lNodeName = Utils.emptyIfBlank(extRef.getSrcPrefix()) - + (extRef.isSetSrcLNClass() ? extRef.getSrcLNClass().get(0): TLLN0Enum.LLN_0.value()) - + Utils.emptyIfBlank(extRef.getSrcLNInst()); - this.dataAttributes = Utils.emptyIfBlank(extRef.getSrcCBName()); + String s1 = extRef.getSrcLNInst(); + String s2 = extRef.getSrcPrefix(); + this.lNodeName = StringUtils.trimToEmpty(s2) + + (extRef.isSetSrcLNClass() ? extRef.getSrcLNClass().get(0) : TLLN0Enum.LLN_0.value()) + + StringUtils.trimToEmpty(s1); + String s = extRef.getSrcCBName(); + this.dataAttributes = StringUtils.trimToEmpty(s); } this.reference = this.ldName + "/" + this.lNodeName + "." + this.dataAttributes; } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractDAIAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractDAIAdapter.java index 01f4c3d92..44b3b92de 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractDAIAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractDAIAdapter.java @@ -57,7 +57,7 @@ public void setValImport(boolean b) { private boolean isDOModDAstVal() { if (parentAdapter.getCurrentElem() instanceof final TDOI tdoi) { - return currentElem.getName().equals(CommonConstants.STVAL) && tdoi.getName().equals(CommonConstants.MOD_DO_NAME); + return currentElem.getName().equals(CommonConstants.STVAL_DA_NAME) && tdoi.getName().equals(CommonConstants.MOD_DO_NAME); } return false; } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractLNAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractLNAdapter.java index 9dbfac953..30bf9f5ed 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractLNAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractLNAdapter.java @@ -22,6 +22,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.lfenergy.compas.sct.commons.util.CommonConstants.MOD_DO_NAME; +import static org.lfenergy.compas.sct.commons.util.CommonConstants.STVAL_DA_NAME; + /** * A representation of the model object @@ -73,6 +76,10 @@ public abstract class AbstractLNAdapter extends SclElementAdapter { + public static final DoTypeName MOD_DO_TYPE_NAME = new DoTypeName(MOD_DO_NAME); + public static final DaTypeName STVAL_DA_TYPE_NAME = new DaTypeName(STVAL_DA_NAME); + private static final String DAI_MOD_STVAL_VALUE_ON = "on"; + /** * Constructor * @@ -967,6 +974,17 @@ public Stream streamControlBlocks(ControlBlockEnum controlB .map(tControl -> new ControlBlockAdapter(this, tControl)); } + /** + * Create ControlBlock if there is no ControlBlock of the same type (controlBlockEnum) and with the same cbName in this LN/LN0. + * When the controlBlock already exists, the id and datSet attributes are NOT updated with the given values. + * + * @param cbName cbName of the controlBlock to look for. When not found, the cbName of the controlBlock to create. + * @param id When controlBlock not found, the id of the controlBlock to create + * @param datSet the datSet of the controlBlock to create + * @param controlBlockEnum the type of ControlBlock to create + * @return existing controlBlock if a controlBlock of the same type and with same cbName was found in this LN/LN0, otherwise the created ControlBlock. + * The returned ControlBlock is always a child of this LN/LN0. + */ public ControlBlockAdapter createControlBlockIfNotExists(String cbName, String id, String datSet, ControlBlockEnum controlBlockEnum) { return findControlBlock(cbName, controlBlockEnum) .orElseGet(() -> addControlBlock( @@ -980,6 +998,25 @@ public ControlBlockAdapter createControlBlockIfNotExists(String cbName, String i ); } + /** + * Generate a ControlBlock Id based on the current LN and the given ldName (ldName can be different from the parent LD.name) + * + * @param ldName LD name to use for generating the id + * @param cbName name of the ControlBlock + * @return "ldName/LnPrefixLnClassLnInst.cbName". Blank values are omitted (e.g "IEDNAME1LD1/LLN0.CBNAME1") + */ + public String generateControlBlockId(String ldName, String cbName) { + String s = getLNInst(); + String s1 = getPrefix(); + return StringUtils.trimToEmpty(ldName) + + "/" + + StringUtils.trimToEmpty(s1) + + StringUtils.defaultString(getLNClass(), "") + + StringUtils.trimToEmpty(s) + + "." + + StringUtils.trimToEmpty(cbName); + } + /** * Finds all FCDAs in DataSet of Control Block feeding ExtRef * @@ -997,4 +1034,20 @@ public List getFCDAs(TExtRef tExtRef) { .flatMap(Collection::stream) .toList(); } + + /** + * Get the value of "Mod.stVal" of the current LN + * + * @return Mod.stVal value if present, else empty Optional + */ + public Optional getDaiModStValValue() { + return getDaiModStVal() + .flatMap(ResumedDataTemplate::findFirstValue); + } + + protected Optional getDaiModStVal() { + ResumedDataTemplate daiModFilter = new ResumedDataTemplate(this, MOD_DO_TYPE_NAME, STVAL_DA_TYPE_NAME); + return getDAI(daiModFilter, false).stream() + .findFirst(); + } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapter.java index d7259ca8a..a2a887624 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapter.java @@ -12,13 +12,14 @@ import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; import org.lfenergy.compas.sct.commons.scl.com.ConnectedAPAdapter; import org.lfenergy.compas.sct.commons.util.ControlBlockEnum; -import org.lfenergy.compas.sct.commons.util.SclConstructorHelper; import org.lfenergy.compas.sct.commons.util.Utils; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newDurationInMilliSec; +import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newP; import static org.lfenergy.compas.sct.commons.util.Utils.xpathAttributeFilter; /** @@ -147,16 +148,16 @@ public Optional configureNetwork(long appId, String macAddress, I } ConnectedAPAdapter connectedAPAdapter = optConApAdapter.get(); List listOfPs = new ArrayList<>(); - listOfPs.add(SclConstructorHelper.newP(APPID_P_TYPE, Utils.toHex(appId, APPID_LENGTH))); - listOfPs.add(SclConstructorHelper.newP(MAC_ADDRESS_P_TYPE, macAddress)); + listOfPs.add(newP(APPID_P_TYPE, Utils.toHex(appId, APPID_LENGTH))); + listOfPs.add(newP(MAC_ADDRESS_P_TYPE, macAddress)); if (vlanId != null) { - listOfPs.add(SclConstructorHelper.newP(VLAN_ID_P_TYPE, Utils.toHex(vlanId, VLAN_ID_LENGTH))); + listOfPs.add(newP(VLAN_ID_P_TYPE, Utils.toHex(vlanId, VLAN_ID_LENGTH))); if (vlanPriority != null) { - listOfPs.add(SclConstructorHelper.newP(VLAN_PRIORITY_P_TYPE, String.valueOf(vlanPriority))); + listOfPs.add(newP(VLAN_PRIORITY_P_TYPE, String.valueOf(vlanPriority))); } } switch (getControlBlockEnum()) { - case GSE -> connectedAPAdapter.updateGseOrCreateIfNotExists(getParentLDeviceAdapter().getInst(), currentElem.getName(), listOfPs, clone(minTime), clone(maxTime)); + case GSE -> connectedAPAdapter.updateGseOrCreateIfNotExists(getParentLDeviceAdapter().getInst(), currentElem.getName(), listOfPs, newDurationInMilliSec(minTime), newDurationInMilliSec(maxTime)); case SAMPLED_VALUE -> connectedAPAdapter.updateSmvOrCreateIfNotExists(getParentLDeviceAdapter().getInst(), currentElem.getName(), listOfPs); default -> { return Optional.of(buildFatalReportItem("configureNetwork not yet implemented for %s ControlBlocks".formatted(getControlBlockEnum()))); @@ -165,13 +166,6 @@ public Optional configureNetwork(long appId, String macAddress, I return Optional.empty(); } - private TDurationInMilliSec clone(TDurationInMilliSec tDurationInMilliSec){ - if (tDurationInMilliSec == null) { - return null; - } - return SclConstructorHelper.newDurationInMilliSec(tDurationInMilliSec.getValue(), tDurationInMilliSec.getUnit(), tDurationInMilliSec.getMultiplier()); - } - /** * Get parent LDevice * @return ControlBlock's parent lDeviceAdapter diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java index 65df19895..1d4d90937 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java @@ -5,9 +5,7 @@ package org.lfenergy.compas.sct.commons.scl.ied; import org.lfenergy.compas.scl2007b4.model.*; -import org.lfenergy.compas.sct.commons.dto.ExtrefTarget; -import org.lfenergy.compas.sct.commons.dto.ResumedDataTemplate; -import org.lfenergy.compas.sct.commons.dto.SclReportItem; +import org.lfenergy.compas.sct.commons.dto.*; import org.lfenergy.compas.sct.commons.scl.ObjectReference; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import org.lfenergy.compas.sct.commons.util.Utils; @@ -136,7 +134,7 @@ public List updateDaiFromExtRef(List tExtRefs) { } private Optional updateDAI(String daName, String value) { - ResumedDataTemplate daiFilterSrcRef = new ResumedDataTemplate(getParentAdapter(), getName(), daName); + ResumedDataTemplate daiFilterSrcRef = new ResumedDataTemplate(getParentAdapter(), new DoTypeName(getName()), new DaTypeName(daName)); Optional foundDais = getParentAdapter().getDAI(daiFilterSrcRef, true).stream().findFirst(); if (foundDais.isEmpty()) { return Optional.of(SclReportItem.warning(getXPath() + "/DAI@name=\"" + daName + "\"/Val", "The DAI cannot be updated")); diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DataSetAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DataSetAdapter.java index d89bd7234..b51440f2a 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DataSetAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DataSetAdapter.java @@ -17,7 +17,9 @@ import java.util.Objects; import java.util.Optional; -import static org.lfenergy.compas.sct.commons.util.Utils.*; +import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newFcda; +import static org.lfenergy.compas.sct.commons.util.Utils.equalsOrBothBlank; +import static org.lfenergy.compas.sct.commons.util.Utils.xpathAttributeFilter; /** * A representation of the model object @@ -47,13 +49,13 @@ public class DataSetAdapter extends SclElementAdapter fcdaComparator = Comparator - .comparing(TFCDA::getLdInst, Utils::blanksFirstComparator) - .thenComparing(TFCDA::getPrefix, Utils::blanksFirstComparator) - .thenComparing(tfcda -> tfcda.isSetLnClass() ? tfcda.getLnClass().get(0) : null, Utils::blanksFirstComparator) - .thenComparing(tfcda -> tfcda.getLnInst() != null ? Integer.valueOf(tfcda.getLnInst()) : null, Comparator.nullsFirst(Integer::compareTo)) - .thenComparing(TFCDA::getDoName, Utils::blanksFirstComparator) - .thenComparing(TFCDA::getDaName, Utils::blanksFirstComparator); + private static final Comparator FCDA_COMPARATOR = Comparator + .comparing(TFCDA::getLdInst, Utils::blanksFirstComparator) + .thenComparing(TFCDA::getPrefix, Utils::blanksFirstComparator) + .thenComparing(tfcda -> tfcda.isSetLnClass() ? tfcda.getLnClass().get(0) : null, Utils::blanksFirstComparator) + .thenComparing(tfcda -> tfcda.getLnInst() != null ? Integer.valueOf(tfcda.getLnInst()) : null, Comparator.nullsFirst(Integer::compareTo)) + .thenComparing(TFCDA::getDoName, Utils::blanksFirstComparator) + .thenComparing(TFCDA::getDaName, Utils::blanksFirstComparator); public DataSetAdapter(AbstractLNAdapter parentAdapter, TDataSet dataSet) { super(parentAdapter, dataSet); @@ -67,11 +69,12 @@ public DataSetAdapter(AbstractLNAdapter parentAdapter, TDataSe @Override protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().isSetDataSet() && parentAdapter.getCurrentElem().getDataSet().stream().anyMatch(dataSet -> - Objects.equals(currentElem.getName(), dataSet.getName())); + Objects.equals(currentElem.getName(), dataSet.getName())); } /** * Returns local XPath + * * @return XPath for current element (not including parent XPath) */ @Override @@ -81,13 +84,14 @@ protected String elementXPath() { /** * Find a FCDA matching all given criteria. - * @param ldInst FCDA ldInst attribute - * @param prefix FCDA prefix attribute + * + * @param ldInst FCDA ldInst attribute + * @param prefix FCDA prefix attribute * @param lnClass FCDA lnClass attribute - * @param lnInst FCDA lnInst attribute - * @param doName FCDA doName attribute - * @param daName FCDA daNae attribute - * @param fc FCDA fc attribute + * @param lnInst FCDA lnInst attribute + * @param doName FCDA doName attribute + * @param daName FCDA daNae attribute + * @param fc FCDA fc attribute * @return Matching FCDA in this DataSet when found, empty Optional otherwise. */ public Optional findFCDA(String ldInst, String prefix, String lnClass, String lnInst, String doName, String daName, TFCEnum fc) { @@ -95,48 +99,47 @@ public Optional findFCDA(String ldInst, String prefix, String lnClass, St return Optional.empty(); } return currentElem.getFCDA().stream() - .filter(tfcda -> - Objects.equals(ldInst, tfcda.getLdInst()) - && equalsOrBothBlank(prefix, tfcda.getPrefix()) - && Utils.lnClassEquals(tfcda.getLnClass(), lnClass) - && equalsOrBothBlank(lnInst, tfcda.getLnInst()) - && Objects.equals(doName, tfcda.getDoName()) - && Objects.equals(fc, tfcda.getFc()) - && equalsOrBothBlank(daName, tfcda.getDaName())) - .findFirst(); + .filter(tfcda -> + Objects.equals(ldInst, tfcda.getLdInst()) + && equalsOrBothBlank(prefix, tfcda.getPrefix()) + && Utils.lnClassEquals(tfcda.getLnClass(), lnClass) + && equalsOrBothBlank(lnInst, tfcda.getLnInst()) + && Objects.equals(doName, tfcda.getDoName()) + && Objects.equals(fc, tfcda.getFc()) + && equalsOrBothBlank(daName, tfcda.getDaName())) + .findFirst(); } /** * Create a new FCDA in this DataSet. * Does nothing if a FCDA with the given attribute already exists in this DataSet. - * @param ldInst FCDA ldInst attribute - * @param prefix FCDA prefix attribute + * + * @param ldInst FCDA ldInst attribute + * @param prefix FCDA prefix attribute * @param lnClass FCDA lnClass attribute - * @param lnInst FCDA lnInst attribute - * @param doName FCDA doName attribute - * @param daName FCDA daNae attribute - * @param fc FCDA fc attribute + * @param lnInst FCDA lnInst attribute + * @param doName FCDA doName attribute + * @param daName FCDA daNae attribute + * @param fc FCDA fc attribute * @return created FCDA, or existing FCDA with the given attributes */ public TFCDA createFCDAIfNotExists(String ldInst, String prefix, String lnClass, String lnInst, String doName, String daName, TFCEnum fc) { Objects.requireNonNull(fc); // fc is required by XSD Optional fcda = findFCDA(ldInst, prefix, lnClass, lnInst, doName, daName, fc); return fcda - .orElseGet(() -> { - TFCDA newFcda = new TFCDA(); - newFcda.setLdInst(nullIfBlank(ldInst)); - newFcda.setPrefix(nullIfBlank(prefix)); - if (StringUtils.isNotBlank(lnClass)) { - newFcda.getLnClass().add(lnClass); - } - newFcda.setLnInst(nullIfBlank(lnInst)); - newFcda.setDoName(nullIfBlank(doName)); - newFcda.setDaName(nullIfBlank(daName)); - newFcda.setFc(fc); - currentElem.getFCDA().add(newFcda); - currentElem.getFCDA().sort(fcdaComparator); - return newFcda; - }); + .orElseGet(() -> { + TFCDA newFcda = newFcda( + StringUtils.trimToNull(ldInst), + lnClass, + StringUtils.trimToNull(lnInst), + StringUtils.trimToNull(prefix), + StringUtils.trimToNull(doName), + StringUtils.trimToNull(daName), + fc); + currentElem.getFCDA().add(newFcda); + currentElem.getFCDA().sort(FCDA_COMPARATOR); + return newFcda; + }); } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapter.java index eebde2652..cf71ba2f1 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapter.java @@ -22,6 +22,7 @@ import java.util.*; import java.util.function.Predicate; +import static org.lfenergy.compas.sct.commons.util.CommonConstants.*; import static org.lfenergy.compas.sct.commons.util.LDeviceStatus.OFF; import static org.lfenergy.compas.sct.commons.util.LDeviceStatus.ON; @@ -60,9 +61,6 @@ public class InputsAdapter extends SclElementAdapter { private static final String MESSAGE_POLL_SERVICE_TYPE_NOT_SUPPORTED = "only GOOSE, SMV and REPORT ServiceType are allowed"; private static final int EXTREF_DESC_DA_NAME_POSITION = -2; - private static final String ATTRIBUTE_VALUE_SEPARATOR = "_"; - private static final String DATASET_NAME_PREFIX = "DS" + ATTRIBUTE_VALUE_SEPARATOR; - private static final String CONTROLBLOCK_NAME_PREFIX = "CB" + ATTRIBUTE_VALUE_SEPARATOR; /** * Constructor @@ -354,9 +352,10 @@ private void createDataSetWithFCDA(TExtRef extRef, LDeviceAdapter sourceLDevice, } private void createControlBlockWithTarget(TExtRef extRef, LDeviceAdapter sourceLDevice, ResumedDataTemplate sourceDa, String cbName, String datSet) { - String cbId = generateControlBlockId(cbName, sourceLDevice.getLdName(), getParentAdapter()); + String sourceLDName = sourceLDevice.getLdName(); + String cbId = getParentAdapter().generateControlBlockId(sourceLDName, cbName); ControlBlockAdapter controlBlockAdapter = sourceLDevice.getLN0Adapter().createControlBlockIfNotExists(cbName, cbId, datSet, ControlBlockEnum.from(extRef.getServiceType())); - if (sourceDa.getFc() != TFCEnum.ST && controlBlockAdapter.getCurrentElem() instanceof TReportControl tReportControl){ + if (sourceDa.getFc() != TFCEnum.ST && controlBlockAdapter.getCurrentElem() instanceof TReportControl tReportControl) { tReportControl.getTrgOps().setDchg(false); tReportControl.getTrgOps().setQchg(false); } @@ -373,24 +372,14 @@ private void setExtRefSrcAttributes(TExtRef extRef, String cbName) { } private static String generateDataSetSuffix(TExtRef extRef, ResumedDataTemplate sourceDa, boolean isBayInternal) { - return extRef.getLdInst() + ATTRIBUTE_VALUE_SEPARATOR - + switch (extRef.getServiceType()) { + return extRef.getLdInst().toUpperCase(Locale.ENGLISH) + ATTRIBUTE_VALUE_SEPARATOR + + switch (extRef.getServiceType()) { case GOOSE -> "G" + ((sourceDa.getFc() == TFCEnum.ST) ? "S" : "M"); case SMV -> "SV"; case REPORT -> (sourceDa.getFc() == TFCEnum.ST) ? "DQC" : "CYC"; case POLL -> throw new IllegalArgumentException(MESSAGE_POLL_SERVICE_TYPE_NOT_SUPPORTED); } - + (isBayInternal ? "I" : "E"); - } - - private String generateControlBlockId(String cbName, String sourceLDName, AbstractLNAdapter targetLn) { - return Utils.emptyIfBlank(sourceLDName) - + "/" - + Utils.emptyIfBlank(targetLn.getPrefix()) - + Objects.requireNonNullElse(targetLn.getLNClass(), "") - + Utils.emptyIfBlank(targetLn.getLNInst()) - + "." - + cbName; + + (isBayInternal ? "I" : "E"); } private Optional removeFilteredSourceDas(TExtRef extRef, final Set sourceDas) { diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java index cacde73a2..99ce8a387 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java @@ -13,11 +13,13 @@ import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import org.lfenergy.compas.sct.commons.scl.dtt.DataTypeTemplateAdapter; import org.lfenergy.compas.sct.commons.util.ControlBlockEnum; +import org.lfenergy.compas.sct.commons.util.LDeviceStatus; import org.lfenergy.compas.sct.commons.util.MonitoringLnClassEnum; import org.lfenergy.compas.sct.commons.util.Utils; import java.util.*; +import static org.lfenergy.compas.sct.commons.util.CommonConstants.*; import static org.lfenergy.compas.sct.commons.util.Utils.copySclElement; /** @@ -53,6 +55,8 @@ @Slf4j public class LDeviceAdapter extends SclElementAdapter { + private static final long INTG_PD_VALUE_FOR_FC_MX = 2000L; + private static final String DA_SETSRCREF = "setSrcRef"; /** @@ -65,6 +69,42 @@ public LDeviceAdapter(IEDAdapter parentAdapter, TLDevice currentElem) { super(parentAdapter, currentElem); } + /** + * Create DataSet and ReportControl Blocks for the HMI with the given FCDAs. + * DataSet and ReportControl are created in LN0, even if FCDA refers to another LN. + * + * @param fcdas List of FCDA for which we must create the DataSet and ReportControl + */ + public void createHmiReportControlBlocks(List fcdas) { + LN0Adapter ln0 = getLN0Adapter(); + if (!ln0.getDaiModStValValue().map(LDeviceStatus.ON::equals).orElse(false)) return; + fcdas.stream() + .filter(fcda -> getInst().equals(fcda.getLdInst()) && fcda.isSetLnClass()) + .forEach(fcda -> (fcda.getLnClass().get(0).equals(TLLN0Enum.LLN_0.value()) ? + Optional.of(ln0) // ln0 Mod stVal "ON" has already been checked, no need to check it again + : findLnAdapter(fcda.getLnClass().get(0), fcda.getLnInst(), fcda.getPrefix()).filter(lnAdapter -> lnAdapter.getDaiModStValValue().map(LDeviceStatus.ON::equals).orElse(true))) + .map(sourceLn -> sourceLn.getDAI(new ResumedDataTemplate(fcda), false)) + .filter(das -> das.stream().anyMatch(da -> fcda.getFc() == da.getFc())) // getDAI does not filter on DA. + .ifPresent(resumedDataTemplates -> createHmiReportCB(ln0, fcda))); + } + + private void createHmiReportCB(LN0Adapter ln0, TFCDA fcda) { + boolean isFcMx = fcda.getFc() == TFCEnum.MX; + String dataSetSuffix = getInst().toUpperCase(Locale.ENGLISH) + ATTRIBUTE_VALUE_SEPARATOR + (isFcMx ? "CYPO" : "DQPO"); + DataSetAdapter dataSet = ln0.createDataSetIfNotExists(DATASET_NAME_PREFIX + dataSetSuffix, ControlBlockEnum.REPORT); + dataSet.createFCDAIfNotExists(fcda.getLdInst(), fcda.getPrefix(), fcda.getLnClass().get(0), fcda.getLnInst(), fcda.getDoName(), fcda.getDaName(), fcda.getFc()); + String cbName = CONTROLBLOCK_NAME_PREFIX + dataSetSuffix; + String cbId = ln0.generateControlBlockId(getLdName(), cbName); + String datSet = dataSet.getCurrentElem().getName(); + ControlBlockAdapter controlBlockAdapter = ln0.createControlBlockIfNotExists(cbName, cbId, datSet, ControlBlockEnum.REPORT); + if (isFcMx) { + TReportControl tReportControl = (TReportControl) controlBlockAdapter.getCurrentElem(); + tReportControl.setIntgPd(INTG_PD_VALUE_FOR_FC_MX); + tReportControl.getTrgOps().setDchg(false); + tReportControl.getTrgOps().setQchg(false); + } + } + /** * Check if node is child of the reference node * @@ -293,7 +333,7 @@ public Optional getLDeviceStatus() { if (!hasLN0()) { return Optional.empty(); } - return getLN0Adapter().getLDeviceStatus(); + return getLN0Adapter().getDaiModStValValue(); } /** @@ -395,7 +435,7 @@ public Optional manageMonitoringLns(List tExtRefs, Strin return getLNAdapters().stream().filter(lnAdapter -> monitoringLnClassEnum.value().equals(lnAdapter.getLNClass())) .map(lnAdapter -> { Optional optionalSclReportItem = Optional.empty(); - ResumedDataTemplate filter = new ResumedDataTemplate(lnAdapter, doName, DA_SETSRCREF); + ResumedDataTemplate filter = new ResumedDataTemplate(lnAdapter, new DoTypeName(doName), new DaTypeName(DA_SETSRCREF)); Optional foundDai = lnAdapter.getDAI(filter, true).stream().findFirst(); if (foundDai.isEmpty()) { optionalSclReportItem = Optional.of(SclReportItem.warning(lnAdapter.getXPath() + "/DOI@name=\"" + doName + "\"/DAI@name=\"setSrcRef\"/Val", diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LN0Adapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LN0Adapter.java index ba83d9ecd..5bd312aa3 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LN0Adapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LN0Adapter.java @@ -17,7 +17,8 @@ import java.util.Set; import java.util.stream.Collectors; -import static org.lfenergy.compas.sct.commons.util.CommonConstants.*; +import static org.lfenergy.compas.sct.commons.util.CommonConstants.BEHAVIOUR_DO_NAME; +import static org.lfenergy.compas.sct.commons.util.CommonConstants.STVAL_DA_NAME; /** * A representation of the model object @@ -68,8 +69,6 @@ */ public class LN0Adapter extends AbstractLNAdapter { - public static final DoTypeName MOD_DO_TYPE_NAME = new DoTypeName(MOD_DO_NAME); - public static final DaTypeName STVAL_DA_TYPE_NAME = new DaTypeName(STVAL); public static final DoTypeName BEHAVIOUR_DO_TYPE_NAME = new DoTypeName(BEHAVIOUR_DO_NAME); public static final DaTypeName BEHAVIOUR_DA_TYPE_NAME = getDaTypeNameForBeh(); private static final String DAI_NAME_PURPOSE = "purpose"; @@ -172,24 +171,6 @@ public void removeAllControlBlocksAndDatasets() { currentElem.unsetSampledValueControl(); } - /** - * Construct ResumedDataTemplate object with DO and DA attributes - * - * @param doTypeName DoTypeName object - * @param daTypeName DaTypeName object - * @return ResumedDataTemplate - */ - private ResumedDataTemplate createDaiFilter(DoTypeName doTypeName, DaTypeName daTypeName) { - ResumedDataTemplate filter = new ResumedDataTemplate(); - filter.setLnClass(getLNClass()); - filter.setLnInst(getLNInst()); - filter.setPrefix(getPrefix()); - filter.setLnType(getLnType()); - filter.setDoName(doTypeName); - filter.setDaName(daTypeName); - return filter; - } - /** * Verify and update LDevice status in parent Node * @@ -200,7 +181,7 @@ public Optional updateLDeviceStatus(List> ie LDeviceActivation lDeviceActivation = new LDeviceActivation(iedNameLDeviceInstList); final String iedName = getParentAdapter().getParentAdapter().getName(); final String ldInst = getParentAdapter().getInst(); - ResumedDataTemplate daiBehFilter = createDaiFilter(BEHAVIOUR_DO_TYPE_NAME, BEHAVIOUR_DA_TYPE_NAME); + ResumedDataTemplate daiBehFilter = new ResumedDataTemplate(this, BEHAVIOUR_DO_TYPE_NAME, BEHAVIOUR_DA_TYPE_NAME); List daiBehList = getDAI(daiBehFilter, false); if (daiBehList.isEmpty()) { return Optional.of(buildFatalReportItem("The LDevice doesn't have a DO @name='Beh' OR its associated DA@fc='ST' AND DA@name='stVal'")); @@ -234,20 +215,9 @@ public Optional updateLDeviceStatus(List> ie return Optional.empty(); } - public Optional getLDeviceStatus() { - return getDaiModStVal() - .flatMap(ResumedDataTemplate::findFirstValue); - } - - private Optional getDaiModStVal() { - ResumedDataTemplate daiModFilter = createDaiFilter(MOD_DO_TYPE_NAME, STVAL_DA_TYPE_NAME); - return getDAI(daiModFilter, false).stream() - .findFirst(); - } - private static DaTypeName getDaTypeNameForBeh() { DaTypeName daTypeNameBeh = new DaTypeName(); - daTypeNameBeh.setName(STVAL); + daTypeNameBeh.setName(STVAL_DA_NAME); daTypeNameBeh.setBType(TPredefinedBasicTypeEnum.ENUM); daTypeNameBeh.setFc(TFCEnum.ST); return daTypeNameBeh; diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CommonConstants.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CommonConstants.java index f6dd373ad..e125f7af4 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CommonConstants.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CommonConstants.java @@ -17,7 +17,10 @@ public final class CommonConstants { public static final String HEADER_REVISION = "headerRevision"; public static final String BEHAVIOUR_DO_NAME = "Beh"; public static final String MOD_DO_NAME = "Mod"; - public static final String STVAL = "stVal"; + public static final String STVAL_DA_NAME = "stVal"; + public static final String ATTRIBUTE_VALUE_SEPARATOR = "_"; + public static final String CONTROLBLOCK_NAME_PREFIX = "CB" + ATTRIBUTE_VALUE_SEPARATOR; + public static final String DATASET_NAME_PREFIX = "DS" + ATTRIBUTE_VALUE_SEPARATOR; /** * Private Controlller, should not be instanced diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CsvUtils.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CsvUtils.java index 23a8d4377..fa87b8210 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CsvUtils.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CsvUtils.java @@ -7,7 +7,6 @@ import com.opencsv.bean.ColumnPositionMappingStrategy; import com.opencsv.bean.CsvToBeanBuilder; import com.opencsv.enums.CSVReaderNullFieldIndicator; -import lombok.experimental.UtilityClass; import java.io.*; import java.nio.charset.Charset; @@ -21,11 +20,14 @@ * - Lines starting with {@link CsvUtils#COMMENT_PREFIX} will be ignored. Allow to write copyright and headers at the beginning of the file for example. * - blank lines are ignored */ -@UtilityClass -public class CsvUtils { +public final class CsvUtils { private static final char SEPARATOR = ';'; private static final String COMMENT_PREFIX = "#"; + private CsvUtils() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + /** * Read CSV from a resource * @@ -43,6 +45,7 @@ public static List parseRows(String resourcePath, Charset charset, Class< /** * Read CSV from a Reader. * Reader will be automatically closed when the method returns or throw an exception. + * * @param csvSource CSV input * @param targetClass Each row will be mapped to this class. * @return list of rows, mapped as targetClass @@ -52,15 +55,15 @@ public static List parseRows(Reader csvSource, Class targetClass) { columnPositionMappingStrategy.setType(targetClass); try (csvSource) { return new CsvToBeanBuilder(csvSource) - .withType(targetClass) - .withSeparator(SEPARATOR) - .withIgnoreLeadingWhiteSpace(true) - .withIgnoreEmptyLine(true) - .withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS) - .withFilter(line -> line != null && line.length > 0 && (line[0] == null || !line[0].stripLeading().startsWith(COMMENT_PREFIX))) - .withMappingStrategy(columnPositionMappingStrategy) - .build() - .parse(); + .withType(targetClass) + .withSeparator(SEPARATOR) + .withIgnoreLeadingWhiteSpace(true) + .withIgnoreEmptyLine(true) + .withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS) + .withFilter(line -> line != null && line.length > 0 && (line[0] == null || !line[0].stripLeading().startsWith(COMMENT_PREFIX))) + .withMappingStrategy(columnPositionMappingStrategy) + .build() + .parse(); } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/FcdaCsvHelper.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/FcdaCsvHelper.java new file mode 100644 index 000000000..aec1aea4a --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/FcdaCsvHelper.java @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2023 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +import com.opencsv.bean.CsvBindByPosition; +import lombok.Getter; +import org.lfenergy.compas.scl2007b4.model.TFCDA; +import org.lfenergy.compas.scl2007b4.model.TFCEnum; + +import java.io.Reader; +import java.util.List; + +/** + * This class is a helper method to load FCDA from a CSV file for use with {@link org.lfenergy.compas.sct.commons.scl.HmiService#createAllHmiReportControlBlocks} + * Use the getter to access the list of parsed FCDA. + * + * @see CsvUtils + * @see org.lfenergy.compas.sct.commons.scl.HmiService#createAllHmiReportControlBlocks + */ +public class FcdaCsvHelper { + + @Getter + private final List fcdas; + + /** + * Constructor + * Provide the CSV file as a Reader. For example, you can create a reader like this : + * new InputStreamReader(getClass().getClassLoader().getResourceAsStream(fileName), StandardCharsets.UTF_8); + * + * @param csvSource a reader that provides the data as CSV + */ + public FcdaCsvHelper(Reader csvSource) { + fcdas = CsvUtils.parseRows(csvSource, Row.class).stream() + .map(row -> + SclConstructorHelper.newFcda(row.ldInst, row.lnClass, row.lnInst, row.prefix, row.doName, null, row.fc) + ) + .toList(); + } + + public static class Row { + @CsvBindByPosition(position = 0) + private String ldInst; + @CsvBindByPosition(position = 1) + private String prefix; + @CsvBindByPosition(position = 2) + private String lnClass; + @CsvBindByPosition(position = 3) + private String lnInst; + @CsvBindByPosition(position = 4) + private String doName; + @CsvBindByPosition(position = 5) + private TFCEnum fc; + } + +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/LDeviceStatus.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/LDeviceStatus.java index dcc392540..59282a30d 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/LDeviceStatus.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/LDeviceStatus.java @@ -6,14 +6,14 @@ package org.lfenergy.compas.sct.commons.util; -import lombok.experimental.UtilityClass; - /** * A representation of a specific object TDAI name that have attribute name STVal. - * */ -@UtilityClass -public class LDeviceStatus { +public final class LDeviceStatus { public static final String ON = "on"; public static final String OFF = "off"; + + private LDeviceStatus() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/SclConstructorHelper.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/SclConstructorHelper.java index a8452d18c..37d8eb913 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/SclConstructorHelper.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/SclConstructorHelper.java @@ -6,7 +6,7 @@ package org.lfenergy.compas.sct.commons.util; -import lombok.experimental.UtilityClass; +import org.apache.commons.lang3.StringUtils; import org.lfenergy.compas.scl2007b4.model.*; import java.math.BigDecimal; @@ -17,12 +17,15 @@ * xjc only provides NoArgConstructors on generated classes. * This utility class provides constructors with the most relevant attributes. */ -@UtilityClass -public class SclConstructorHelper { +public final class SclConstructorHelper { private static final String SECOND = "s"; private static final String MILLI = "m"; + private SclConstructorHelper() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + /** * Create new instance of TP * @@ -64,6 +67,20 @@ public static TDurationInMilliSec newDurationInMilliSec(long value) { return newDurationInMilliSec(new BigDecimal(value), SECOND, MILLI); } + /** + * Clone TDurationInMilliSec. The clone is independent of the tDurationInMilliSec because all fields are immutable. + * + * @param tDurationInMilliSec TDurationInMilliSec to clone + * @return new instance of TDurationInMilliSec initialized with the given parameters + * @see #newDurationInMilliSec(BigDecimal, String, String) + */ + public static TDurationInMilliSec newDurationInMilliSec(TDurationInMilliSec tDurationInMilliSec) { + if (tDurationInMilliSec == null) { + return null; + } + return newDurationInMilliSec(tDurationInMilliSec.getValue(), tDurationInMilliSec.getUnit(), tDurationInMilliSec.getMultiplier()); + } + /** * Create new instance of TAddress * @@ -117,4 +134,15 @@ public static TVal newVal(String value) { return newVal(value, null); } + public static TFCDA newFcda(String ldInst, String lnClass, String lnInst, String prefix, String doName, String daName, TFCEnum fc) { + TFCDA tfcda = new TFCDA(); + tfcda.setLdInst(ldInst); + if (StringUtils.isNotBlank(lnClass)) tfcda.getLnClass().add(lnClass); + tfcda.setLnInst(lnInst); + tfcda.setPrefix(prefix); + tfcda.setDoName(doName); + tfcda.setDaName(daName); + tfcda.setFc(fc); + return tfcda; + } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java index a9f80950d..b3248f301 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java @@ -225,26 +225,6 @@ public static String extractField(String s, String regexDelimiter, int index) { return 0 <= column && column < split.length ? split[column] : null; } - /** - * return null if input string is blank. - * Blank means : null, empty string or whitespaces (as defined by {@link Character#isWhitespace(char)}) only string. - * @param s string to split - * @return null if input string is blank, else s parameter - */ - public static String nullIfBlank(String s) { - return StringUtils.isBlank(s) ? null : s; - } - - /** - * return empty String (i.e "") if input string is blank. - * Blank means : null, empty string or whitespaces (as defined by {@link Character#isWhitespace(char)}) only string. - * @param s string to split - * @return empty string (i.e "") if input string is blank, else s parameter - */ - public static String emptyIfBlank(String s) { - return StringUtils.isBlank(s) ? "" : s; - } - /** * Check if lnClass as List os the same as lnClass as a String. * For some reason, xjc plugin generates a List<String> instead of a String for the lnClass attribute. diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/FCDARecordTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/FCDARecordTest.java new file mode 100644 index 000000000..73713220f --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/FCDARecordTest.java @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2023 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.dto; + +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl2007b4.model.TFCDA; +import org.lfenergy.compas.scl2007b4.model.TFCEnum; +import org.lfenergy.compas.sct.commons.testhelpers.FCDARecord; + +import static org.assertj.core.api.Assertions.assertThat; + +class FCDARecordTest { + + @Test + void from_TFCDA_should_create_instance_with_same_attributes() { + //Given + TFCDA tfcda = new TFCDA(); + tfcda.setLdInst("ldInst"); + tfcda.getLnClass().add("lnClass"); + tfcda.setLnInst("lnInst"); + tfcda.setPrefix("prefix"); + tfcda.setDoName("DoName.sdo"); + tfcda.setDaName("daName.bda"); + tfcda.setFc(TFCEnum.ST); + //When + FCDARecord fcdaRecord = FCDARecord.toFCDARecord(tfcda); + //Then + assertThat(fcdaRecord).isEqualTo( + new FCDARecord("ldInst", "lnClass", "lnInst", "prefix", "DoName.sdo", "daName.bda", TFCEnum.ST)); + } + +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplateTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplateTest.java index 988f9e0b1..385a09f01 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplateTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplateTest.java @@ -20,7 +20,8 @@ import static org.junit.jupiter.api.Assertions.*; import static org.lfenergy.compas.sct.commons.testhelpers.DataTypeUtils.createDa; import static org.lfenergy.compas.sct.commons.util.CommonConstants.MOD_DO_NAME; -import static org.lfenergy.compas.sct.commons.util.CommonConstants.STVAL; +import static org.lfenergy.compas.sct.commons.util.CommonConstants.STVAL_DA_NAME; +import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newFcda; class ResumedDataTemplateTest { @@ -177,12 +178,12 @@ void isUpdatable_case0(String testName, String daName, TFCEnum fc, boolean valIm private static Stream daParametersProviderUpdatable() { return Stream.of( - Arguments.of("should return true when Mod", STVAL, TFCEnum.CF, true), - Arguments.of("should return true when Mod", STVAL, TFCEnum.CF, false), - Arguments.of("should return true when Mod", STVAL, TFCEnum.MX, true), - Arguments.of("should return true when Mod", STVAL, TFCEnum.MX, false), - Arguments.of("should return true when Mod", STVAL, null, true), - Arguments.of("should return true when Mod", STVAL, null, false), + Arguments.of("should return true when Mod", STVAL_DA_NAME, TFCEnum.CF, true), + Arguments.of("should return true when Mod", STVAL_DA_NAME, TFCEnum.CF, false), + Arguments.of("should return true when Mod", STVAL_DA_NAME, TFCEnum.MX, true), + Arguments.of("should return true when Mod", STVAL_DA_NAME, TFCEnum.MX, false), + Arguments.of("should return true when Mod", STVAL_DA_NAME, null, true), + Arguments.of("should return true when Mod", STVAL_DA_NAME, null, false), Arguments.of("should return true when Mod", CTL_MODEL, TFCEnum.CF, true) ); } @@ -276,25 +277,60 @@ void setVal_should_replace_reference_val(){ } @Test - void constructorTest() { + void constructor_should_create_new_instance() { // Given TLN tln = new TLN(); tln.setLnType("T1"); tln.getLnClass().add(TLLN0Enum.LLN_0.value()); tln.setPrefix("P1"); + tln.setInst("1"); LNAdapter lnAdapter = new LNAdapter(null, tln); + DoTypeName doName = new DoTypeName("do"); + DaTypeName daName = new DaTypeName("da"); // When - ResumedDataTemplate expected = new ResumedDataTemplate(lnAdapter, "do", "da"); + ResumedDataTemplate expected = new ResumedDataTemplate(lnAdapter, doName, daName); // Then - assertThat(expected.getLnClass()).isEqualTo(TLLN0Enum.LLN_0.value()); - assertThat(expected.getLnType()).isEqualTo("T1"); - assertThat(expected.getPrefix()).isEqualTo("P1"); - assertThat(expected.getDoName().getName()).isEqualTo("do"); - assertThat(expected.getDoName().getName()).isEqualTo("do"); - assertThat(expected.getDoName().getStructNames()).isEmpty(); - assertThat(expected.getDaName().getName()).isEqualTo("da"); - assertThat(expected.getDaName().getDaiValues()).isEmpty(); - assertThat(expected.getDaName().isValImport()).isFalse(); - assertThat(expected.getDaName().isUpdatable()).isFalse(); + assertThat(expected).extracting(ResumedDataTemplate::getLnType, ResumedDataTemplate::getLnClass, ResumedDataTemplate::getPrefix, ResumedDataTemplate::getLnInst) + .containsExactly("T1", TLLN0Enum.LLN_0.value(), "P1", "1"); + assertThat(expected.getDoName()).isEqualTo(new DoTypeName("do")); + assertThat(expected.getDaName()).isEqualTo(new DaTypeName("da")); + } + + + @Test + void constructor_from_TFCDA_should_create_new_instance_with_same_attributes() { + //Given + TFCDA tfcda = newFcda("ldInst", "lnClass", "lnInst", "prefix", "DoName.sdo", "daName.bda", TFCEnum.ST); + //When + ResumedDataTemplate resumedDataTemplate = new ResumedDataTemplate(tfcda); + //Then + assertThat(resumedDataTemplate.getLNRef()) + .isEqualTo("prefixlnClasslnInst.DoName.sdo.daName.bda"); + DaTypeName expectedDa = new DaTypeName("daName.bda"); + expectedDa.setFc(TFCEnum.ST); + assertThat(resumedDataTemplate.getDaName()).isEqualTo(expectedDa); + } + + @Test + void constructor_from_TFCDA_should_ignore_blank_DaName() { + //Given + TFCDA tfcda = newFcda("ldInst", "lnClass", "lnInst", "prefix", "DoName.sdo", "", TFCEnum.ST); + //When + ResumedDataTemplate resumedDataTemplate = new ResumedDataTemplate(tfcda); + //Then + assertThat(resumedDataTemplate.isDaNameDefined()).isFalse(); + assertThat(resumedDataTemplate.getFc()).isNull(); + } + + @Test + void constructor_from_TFCDA_should_ignore_blank_fc() { + //Given + TFCDA tfcda = newFcda("ldInst", "lnClass", "lnInst", "prefix", "DoName.sdo", "daName.bda", null); + //When + ResumedDataTemplate resumedDataTemplate = new ResumedDataTemplate(tfcda); + //Then + assertThat(resumedDataTemplate.getLNRef()) + .isEqualTo("prefixlnClasslnInst.DoName.sdo.daName.bda"); + assertThat(resumedDataTemplate.getFc()).isNull(); } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ExtRefServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ExtRefServiceTest.java index 673128728..9ccf3e0af 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ExtRefServiceTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ExtRefServiceTest.java @@ -15,7 +15,6 @@ import org.lfenergy.compas.sct.commons.dto.SclReport; import org.lfenergy.compas.sct.commons.dto.SclReportItem; import org.lfenergy.compas.sct.commons.exception.ScdException; -import org.lfenergy.compas.sct.commons.scl.ied.ControlBlockAdapter; import org.lfenergy.compas.sct.commons.scl.ied.DataSetAdapter; import org.lfenergy.compas.sct.commons.scl.ied.LDeviceAdapter; import org.lfenergy.compas.sct.commons.testhelpers.FCDARecord; @@ -247,9 +246,7 @@ void createDataSetAndControlBlocks_should_create_ControlBlocks() { assertControlBlockExists(sclReport, "IED_NAME2", "LD_INST21", "CB_LD_INST21_GSI", "DS_LD_INST21_GSI", "IED_NAME2LD_INST21/LLN0.CB_LD_INST21_GSI", GSE); // Check one ControlBlock content (ReportControl with sourceDA.fc=MX) - ControlBlockAdapter reportControlBlock = findControlBlock(sclReport.getSclRootAdapter(), "IED_NAME2", "LD_INST21", "CB_LD_INST21_CYCI", REPORT); - assertThat(reportControlBlock.getCurrentElem()).isInstanceOf(TReportControl.class); - TReportControl tReportControl = (TReportControl) reportControlBlock.getCurrentElem(); + TReportControl tReportControl = findControlBlock(sclReport.getSclRootAdapter(), "IED_NAME2", "LD_INST21", "CB_LD_INST21_CYCI", TReportControl.class); assertThat(tReportControl).extracting(TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, TControlWithTriggerOpt::getIntgPd) .containsExactly(1L, true, 0L, true, 60000L); diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/HmiServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/HmiServiceTest.java new file mode 100644 index 000000000..4c2cda805 --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/HmiServiceTest.java @@ -0,0 +1,178 @@ +// SPDX-FileCopyrightText: 2023 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.scl; + +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl2007b4.model.*; +import org.lfenergy.compas.sct.commons.scl.ied.DataSetAdapter; +import org.lfenergy.compas.sct.commons.scl.ied.LN0Adapter; +import org.lfenergy.compas.sct.commons.scl.ied.LNAdapter; +import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; +import org.lfenergy.compas.sct.commons.util.CommonConstants; +import org.lfenergy.compas.sct.commons.util.LDeviceStatus; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.*; +import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newFcda; + +class HmiServiceTest { + + @Test + void createAllIhmReportControlBlocks_with_fc_ST_should_create_dataset_and_controlblock() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); + TFCDA fcda = newFcda("LdInst11", "ANCR", "1", null, "DoName1", null, TFCEnum.ST); + // When + HmiService.createAllHmiReportControlBlocks(scd, List.of(fcda)); + // Then + // Check DataSet is created + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + DataSetAdapter dataSet = findDataSet(sclRootAdapter, "IedName1", "LdInst11", "DS_LDINST11_DQPO"); + assertThat(dataSet.getCurrentElem().getFCDA()).hasSize(1).first() + .usingRecursiveComparison().isEqualTo(fcda); + // Check ControlBlock is created + LN0Adapter ln0 = findLn0(sclRootAdapter, "IedName1", "LdInst11"); + assertThat(ln0.getTControlsByType(TReportControl.class)).hasSize(1); + TReportControl reportControl = findControlBlock(sclRootAdapter, "IedName1", "LdInst11", "CB_LDINST11_DQPO", TReportControl.class); + assertThat(reportControl).extracting(TReportControl::getRptID, TControl::getDatSet, TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, + TControlWithTriggerOpt::getIntgPd) + .containsExactly("IedName1LdInst11/LLN0.CB_LDINST11_DQPO", "DS_LDINST11_DQPO", 1L, true, 0L, true, 60000L); + assertThat(reportControl.getTrgOps()) + .extracting(TTrgOps::isDchg, TTrgOps::isQchg, TTrgOps::isDupd, TTrgOps::isPeriod, TTrgOps::isGi) + .containsExactly(true, true, false, true, true); + assertThat(reportControl.getRptEnabled().getMax()).isEqualTo(1); + assertThat(reportControl.getRptEnabled().isSetClientLN()).isFalse(); + } + + @Test + void createAllIhmReportControlBlocks_with_fc_MX_should_create_dataset_and_controlblock() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); + TFCDA fcda = newFcda("LdInst11", "PVOC", "1", null, "DoName2", null, TFCEnum.MX); + // When + HmiService.createAllHmiReportControlBlocks(scd, List.of(fcda)); + // Then + // Check DataSet is created + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + DataSetAdapter dataSet = findDataSet(sclRootAdapter, "IedName1", "LdInst11", "DS_LDINST11_CYPO"); + assertThat(dataSet.getCurrentElem().getFCDA()).hasSize(1).first() + .usingRecursiveComparison().isEqualTo(fcda); + // Check ControlBlock is created + LN0Adapter ln0 = findLn0(sclRootAdapter, "IedName1", "LdInst11"); + assertThat(ln0.getTControlsByType(TReportControl.class)).hasSize(1); + + TReportControl reportControl = findControlBlock(sclRootAdapter, "IedName1", "LdInst11", "CB_LDINST11_CYPO", TReportControl.class); + assertThat(reportControl).extracting(TReportControl::getRptID, TControl::getDatSet, TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, + TControlWithTriggerOpt::getIntgPd) + .containsExactly("IedName1LdInst11/LLN0.CB_LDINST11_CYPO", "DS_LDINST11_CYPO", 1L, true, 0L, true, 2000L); + assertThat(reportControl.getTrgOps()) + .extracting(TTrgOps::isDchg, TTrgOps::isQchg, TTrgOps::isDupd, TTrgOps::isPeriod, TTrgOps::isGi) + .containsExactly(false, false, false, true, true); + assertThat(reportControl.getRptEnabled().getMax()).isEqualTo(1); + assertThat(reportControl.getRptEnabled().isSetClientLN()).isFalse(); + } + + @Test + void createAllIhmReportControlBlocks_with_FCDA_on_ln0_should_create_dataset_and_controlblock() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); + TFCDA fcda = newFcda("LdInst11", "LLN0", null, null, "DoName0", null, TFCEnum.ST); + // When + HmiService.createAllHmiReportControlBlocks(scd, List.of(fcda)); + // Then + // Check DataSet is created + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + DataSetAdapter dataSet = findDataSet(sclRootAdapter, "IedName1", "LdInst11", "DS_LDINST11_DQPO"); + assertThat(dataSet.getCurrentElem().getFCDA()).hasSize(1).first() + .usingRecursiveComparison().isEqualTo(fcda); + // Check ControlBlock is created + LN0Adapter ln0 = findLn0(sclRootAdapter, "IedName1", "LdInst11"); + assertThat(ln0.getTControlsByType(TReportControl.class)).hasSize(1); + TReportControl reportControl = findControlBlock(sclRootAdapter, "IedName1", "LdInst11", "CB_LDINST11_DQPO", TReportControl.class); + assertThat(reportControl).extracting(TReportControl::getRptID, TControl::getDatSet, TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, + TControlWithTriggerOpt::getIntgPd) + .containsExactly("IedName1LdInst11/LLN0.CB_LDINST11_DQPO", "DS_LDINST11_DQPO", 1L, true, 0L, true, 60000L); + assertThat(reportControl.getTrgOps()) + .extracting(TTrgOps::isDchg, TTrgOps::isQchg, TTrgOps::isDupd, TTrgOps::isPeriod, TTrgOps::isGi) + .containsExactly(true, true, false, true, true); + assertThat(reportControl.getRptEnabled().getMax()).isEqualTo(1); + assertThat(reportControl.getRptEnabled().isSetClientLN()).isFalse(); + } + + @Test + void createAllIhmReportControlBlocks_when_lDevice_ON_but_LN_Mod_StVal_missing_should_create_dataset_and_controlblock() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + LNAdapter ln = findLn(sclRootAdapter, "IedName1", "LdInst11", "ANCR", "1", null); + ln.getCurrentElem().unsetDOI(); + TFCDA fcda = newFcda("LdInst11", "ANCR", "1", null, "DoName1", null, TFCEnum.ST); + // When + HmiService.createAllHmiReportControlBlocks(scd, List.of(fcda)); + // Then + // Check DataSet is created + DataSetAdapter dataSet = findDataSet(sclRootAdapter, "IedName1", "LdInst11", "DS_LDINST11_DQPO"); + assertThat(dataSet.getCurrentElem().getFCDA()).hasSize(1).first() + .usingRecursiveComparison().isEqualTo(fcda); + // Check ControlBlock is created + LN0Adapter ln0 = findLn0(sclRootAdapter, "IedName1", "LdInst11"); + assertThat(ln0.getTControlsByType(TReportControl.class)).hasSize(1); + TReportControl reportControl = findControlBlock(sclRootAdapter, "IedName1", "LdInst11", "CB_LDINST11_DQPO", TReportControl.class); + assertThat(reportControl).extracting(TReportControl::getRptID, TControl::getDatSet, TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, + TControlWithTriggerOpt::getIntgPd) + .containsExactly("IedName1LdInst11/LLN0.CB_LDINST11_DQPO", "DS_LDINST11_DQPO", 1L, true, 0L, true, 60000L); + } + + @Test + void createAllIhmReportControlBlocks_when_lDevice_ON_but_LN_Mod_StVal_OFF_should_not_create_dataset() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + LNAdapter ln = findLn(sclRootAdapter, "IedName1", "LdInst11", "ANCR", "1", null); + ln.getDOIAdapterByName(CommonConstants.MOD_DO_NAME).getDataAdapterByName(CommonConstants.STVAL_DA_NAME).setVal("off"); + assertThat(ln.getDaiModStValValue()).hasValue("off"); + TFCDA fcda = newFcda("LdInst11", "ANCR", "1", null, "DoName1", null, TFCEnum.ST); + // When + HmiService.createAllHmiReportControlBlocks(scd, List.of(fcda)); + // Then + assertThat(streamAllDataSets(sclRootAdapter)).isEmpty(); + assertThat(streamAllControlBlocks(sclRootAdapter, TReportControl.class)).isEmpty(); + } + + @Test + void createAllIhmReportControlBlocks_when_lDevice_OFF_should_not_create_dataset() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + LN0Adapter ln0 = findLn0(sclRootAdapter, "IedName1", "LdInst11"); + ln0.getDOIAdapterByName(CommonConstants.MOD_DO_NAME).getDataAdapterByName(CommonConstants.STVAL_DA_NAME).setVal("off"); + assertThat(findLDevice(sclRootAdapter, "IedName1", "LdInst11").getLDeviceStatus()).hasValue(LDeviceStatus.OFF); + TFCDA fcda = newFcda("LdInst11", "ANCR", "1", null, "DoName1", null, TFCEnum.ST); + // When + HmiService.createAllHmiReportControlBlocks(scd, List.of(fcda)); + // Then + assertThat(streamAllDataSets(sclRootAdapter)).isEmpty(); + assertThat(streamAllControlBlocks(sclRootAdapter, TReportControl.class)).isEmpty(); + } + + @Test + void createAllIhmReportControlBlocks_when_LDevice_has_no_status_should_not_create_dataset() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + LN0Adapter ln0 = findLn0(sclRootAdapter, "IedName1", "LdInst11"); + ln0.getDOIAdapterByName(CommonConstants.MOD_DO_NAME).getDataAdapterByName(CommonConstants.STVAL_DA_NAME).getCurrentElem().unsetVal(); + assertThat(findLDevice(sclRootAdapter, "IedName1", "LdInst11").getLDeviceStatus()).isEmpty(); + TFCDA fcda = newFcda("LdInst11", "ANCR", "1", null, "DoName1", null, TFCEnum.ST); + // When + HmiService.createAllHmiReportControlBlocks(scd, List.of(fcda)); + // Then + assertThat(streamAllDataSets(sclRootAdapter)).isEmpty(); + assertThat(streamAllControlBlocks(sclRootAdapter, TReportControl.class)).isEmpty(); + } + +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java index d6e561178..d8e359197 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java @@ -175,7 +175,7 @@ void DAIAdapter_update_when_valImport_is_set_to_false_should_throw_exception() { void DAIAdapter_update_when_valImport_is_set_to_false_but_da_is_Mod_StVal_should_update_value() { // Given String newValue = "newValue"; - DOIAdapter.DAIAdapter daiAdapter = initInnerDAIAdapter(CommonConstants.MOD_DO_NAME, CommonConstants.STVAL); + DOIAdapter.DAIAdapter daiAdapter = initInnerDAIAdapter(CommonConstants.MOD_DO_NAME, CommonConstants.STVAL_DA_NAME); daiAdapter.setValImport(false); // When daiAdapter.update(0L, newValue); diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapterTest.java index 638b4f036..b8ff373e4 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapterTest.java @@ -228,7 +228,7 @@ public static Stream provideDoNotCreateFCDA() { } @Test - void updateAllSourceDataSetsAndControlBlocks_when_AceessPoint_does_not_have_dataset_creation_capability_should_report_error() { + void updateAllSourceDataSetsAndControlBlocks_when_AccessPoint_does_not_have_dataset_creation_capability_should_report_error() { // Given SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml"); SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LN0AdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LN0AdapterTest.java index fbde82f6e..eee07ad71 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LN0AdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LN0AdapterTest.java @@ -678,23 +678,27 @@ void elementXPath() { } @Test - void getLDeviceStatus_should_succeed() { + void getLnStatus_should_return_ModStValValue() { // Given SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-iedname/scd_set_extref_iedname_with_extref_errors.xml"); SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); - Optional optionalLN0Adapter = sclRootAdapter.streamIEDAdapters() - .flatMap(IEDAdapter::streamLDeviceAdapters) - .filter(lDeviceAdapter -> "IED_NAME1LD_INST13".equals(lDeviceAdapter.getLdName())) - .map(LDeviceAdapter::getLN0Adapter) - .findFirst(); - assertThat(optionalLN0Adapter).isPresent(); - LN0Adapter ln0Adapter = optionalLN0Adapter.get(); + LN0Adapter ln0 = findLn0(sclRootAdapter, "IED_NAME1", "LD_INST13"); // When - Optional result = ln0Adapter.getLDeviceStatus(); + Optional lnStatus = ln0.getDaiModStValValue(); // Then - assertThat(result) - .isPresent() - .hasValue("test"); + assertThat(lnStatus).hasValue("test"); + } + + @Test + void getLnStatus_should_return_empty_Optional() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-iedname/scd_set_extref_iedname_with_extref_errors.xml"); + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + LN0Adapter ln0 = findLn0(sclRootAdapter, "IED_NAME1", "LD_INST14"); + // When + Optional lnStatus = ln0.getDaiModStValValue(); + // Then + assertThat(lnStatus).isEmpty(); } @Test diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclHelper.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclHelper.java index 835e4d459..a853792a8 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclHelper.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclHelper.java @@ -4,7 +4,6 @@ package org.lfenergy.compas.sct.commons.testhelpers; -import lombok.experimental.UtilityClass; import org.assertj.core.api.Assertions; import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.dto.SclReport; @@ -27,8 +26,11 @@ * Methods throw AssertionFailedError when element not found (equivalent of calling JUnit Assert.fail()) * which stops the test nicely (compared to an exception error), with a message and a failed status. */ -@UtilityClass -public class SclHelper { +public final class SclHelper { + + private SclHelper() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } public static final String DO_GOCBREF = "GoCBRef"; public static final String DO_SVCBREF = "SvCBRef"; @@ -164,14 +166,23 @@ public static ControlBlockAdapter findControlBlock(SclRootAdapter sclRootAdapter controlBlockEnum.getControlBlockClass().getSimpleName(), cbName, iedName, ldInst))); } + public static T findControlBlock(SclRootAdapter sclRootAdapter, String iedName, String ldInst, String cbName, Class controlBlockClass) { + LN0Adapter ln0 = findLn0(sclRootAdapter, iedName, ldInst); + return ln0.getTControlsByType(controlBlockClass).stream() + .filter(t -> cbName.equals(t.getName())) + .findFirst() + .orElseThrow(() -> new AssertionFailedError(String.format("%s name=%s not found in IED.name=%s,LDevice.inst=%s,LN0", + controlBlockClass.getSimpleName(), cbName, iedName, ldInst))); + } + public static void assertControlBlockExists(SclReport sclReport, String iedName, String ldInst, String cbName, String datSet, String id, ControlBlockEnum controlBlockEnum) { - ControlBlockAdapter controlBlock = findControlBlock(sclReport.getSclRootAdapter(), iedName, ldInst, cbName, controlBlockEnum); - assertThat(controlBlock.getCurrentElem().getDatSet()).isEqualTo(datSet); - assertThat(getControlBlockId(controlBlock.getCurrentElem())).isEqualTo(id); + TControl controlBlock = findControlBlock(sclReport.getSclRootAdapter(), iedName, ldInst, cbName, controlBlockEnum.getControlBlockClass()); + assertThat(controlBlock.getDatSet()).isEqualTo(datSet); + assertThat(getControlBlockId(controlBlock)).isEqualTo(id); } - private String getControlBlockId(TControl tControl) { + private static String getControlBlockId(TControl tControl) { if (tControl instanceof TGSEControl tgseControl) { return tgseControl.getAppID(); } @@ -190,6 +201,12 @@ public static Stream streamAllDataSets(SclRootAdapter sclRootAdapter) .flatMap(List::stream); } + public static Stream streamAllControlBlocks(SclRootAdapter sclRootAdapter, Class controlBlockClass) { + return streamAllLn0Adapters(sclRootAdapter) + .map(ln0Adapter -> ln0Adapter.getTControlsByType(controlBlockClass)) + .flatMap(List::stream); + } + public static Stream streamAllLn0Adapters(SclRootAdapter sclRootAdapter) { return sclRootAdapter .streamIEDAdapters() diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/FcdaCsvHelperTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/FcdaCsvHelperTest.java new file mode 100644 index 000000000..355353cfa --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/FcdaCsvHelperTest.java @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2023 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl2007b4.model.TFCDA; +import org.lfenergy.compas.scl2007b4.model.TFCEnum; + +import java.io.StringReader; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class FcdaCsvHelperTest { + + @Test + void getFcdaRecords_should_parse_csv_file() { + //Given + StringReader csvReader = new StringReader(""" + LDGRP1;;GAPC;12;Ind1;ST + LDCMDSS2;;LLN0;;Health;MX + """); + FcdaCsvHelper fcdaCsvHelper = new FcdaCsvHelper(csvReader); + //When + List fcdaRecords = fcdaCsvHelper.getFcdas(); + //Then + assertThat(fcdaRecords).hasSize(2); + assertThat(fcdaRecords.get(0)).usingRecursiveComparison().isEqualTo( + SclConstructorHelper.newFcda("LDGRP1", "GAPC", "12", null, "Ind1", null, TFCEnum.ST)); + assertThat(fcdaRecords.get(1)).usingRecursiveComparison().isEqualTo( + SclConstructorHelper.newFcda("LDCMDSS2", "LLN0", null, null, "Health", null, TFCEnum.MX)); + } +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/SclConstructorHelperTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/SclConstructorHelperTest.java index f680c3a3f..ec48f52d1 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/SclConstructorHelperTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/SclConstructorHelperTest.java @@ -51,22 +51,37 @@ void newDurationInMilliSec_should_create_new_instance_with_given_parameters() { } @Test - void testNewDurationInMilliSec_should_create_new_instance_with_given_parameters() { + void newDurationInMilliSec_with_value_only_should_create_new_instance_with_given_value_and_default_unit_and_multiplier() { //Given long value = 5L; //When TDurationInMilliSec durationInMilliSec = SclConstructorHelper.newDurationInMilliSec(value); //Then assertThat(durationInMilliSec).extracting(TDurationInMilliSec::getValue, TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier) - .containsExactly(new BigDecimal(value), "s", "m"); + .containsExactly(new BigDecimal(value), "s", "m"); + } + + @Test + void newDurationInMilliSec_should_clone_given_instance() { + //Given + BigDecimal value = new BigDecimal(5); + String unit = "unit"; + String multiplier = "multiplier"; + TDurationInMilliSec input = SclConstructorHelper.newDurationInMilliSec(value, unit, multiplier); + //When + TDurationInMilliSec durationInMilliSec = SclConstructorHelper.newDurationInMilliSec(input); + //Then + assertThat(durationInMilliSec).extracting(TDurationInMilliSec::getValue, TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier) + .containsExactly(value, unit, multiplier); + assertThat(durationInMilliSec).isNotSameAs(input); } @Test void newAddress_should_create_new_instance_with_given_parameters() { //Given List listOfP = List.of( - SclConstructorHelper.newP("type1", "value1"), - SclConstructorHelper.newP("type2", "value2")); + SclConstructorHelper.newP("type1", "value1"), + SclConstructorHelper.newP("type2", "value2")); //When TAddress tAddress = SclConstructorHelper.newAddress(listOfP); //Then @@ -106,6 +121,39 @@ void newVal_should_create_new_instance_with_sGroup() { TVal tVal = SclConstructorHelper.newVal(value, sGroup); //Then assertThat(tVal).extracting(TVal::getValue, TVal::getSGroup) - .containsExactly(value, sGroup); + .containsExactly(value, sGroup); + } + + @Test + void newFcda_should_create_new_instance_with_given_parameters() { + //Given + String ldinst = "ldinst"; + String lnClass = "lnClass"; + String lnInst = "lnInst"; + String prefix = "prefix"; + String doName = "doName"; + String daName = "daName"; + TFCEnum fc = TFCEnum.ST; + //When + TFCDA tfcda = SclConstructorHelper.newFcda(ldinst, lnClass, lnInst, prefix, doName, daName, fc); + //Then + assertThat(tfcda).extracting(TFCDA::getLdInst, TFCDA::getLnClass, TFCDA::getLnInst, TFCDA::getPrefix, TFCDA::getDoName, TFCDA::getDaName, TFCDA::getFc) + .containsExactly(ldinst, List.of(lnClass), lnInst, prefix, doName, daName, fc); + } + + @Test + void newFcda_should_when_blank_lnClass_should_not_set_lnClass() { + //Given + String ldinst = "ldinst"; + String lnClass = ""; + String lnInst = "lnInst"; + String prefix = "prefix"; + String doName = "doName"; + String daName = "daName"; + TFCEnum fc = TFCEnum.ST; + //When + TFCDA tfcda = SclConstructorHelper.newFcda(ldinst, lnClass, lnInst, prefix, doName, daName, fc); + //Then + assertThat(tfcda.isSetLnClass()).isFalse(); } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java index b0330603a..0b7157abd 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java @@ -23,7 +23,6 @@ import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Named.named; import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.createExtRefExample; import static org.lfenergy.compas.sct.commons.util.Utils.copySclElement; @@ -339,44 +338,6 @@ public static Stream provideBlankFirstComparatorSource() { ); } - @ParameterizedTest - @MethodSource("provideBlankStrings") - void nullIfBlank_when_input_is_blank_should_return_null(String input){ - // Given : Parameter - // When - String result = Utils.nullIfBlank(input); - // Then - assertThat(result).isNull(); - } - - public static Stream provideBlankStrings() { - return Stream.of( - Arguments.of(named("null", null)), - Arguments.of(""), - Arguments.of(" ") - ); - } - - @Test - void nullIfBlank_when_input_is_not_blank_should_return_same_string(){ - // Given - String input = "a"; - // When - String result = Utils.nullIfBlank(input); - // Then - assertThat(result).isEqualTo(input); - } - - @ParameterizedTest - @MethodSource("provideBlankStrings") - void emptyIfBlank_when_input_is_blank_should_return_null(String input){ - // Given : Parameter - // When - String result = Utils.emptyIfBlank(input); - // Then - assertThat(result).isEmpty(); - } - @ParameterizedTest @MethodSource("provideLnClassEqualsSourceResultTrue") void lnClassEquals_when_input_matches_should_return_true(List lnClass1, String lnClass2){ diff --git a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml index 2686501b4..85f985873 100644 --- a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml +++ b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml @@ -12,10 +12,14 @@ - + - + @@ -56,7 +60,7 @@ - + @@ -109,7 +113,7 @@ - + diff --git a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_extref_errors.xml b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_extref_errors.xml index 0aa4abf82..63047c685 100644 --- a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_extref_errors.xml +++ b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_extref_errors.xml @@ -7,10 +7,13 @@
- + - + @@ -39,10 +42,13 @@ - + - + diff --git a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_ied_errors.xml b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_ied_errors.xml index 2eac0b60f..61da3b513 100644 --- a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_ied_errors.xml +++ b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_ied_errors.xml @@ -8,7 +8,10 @@ - + @@ -33,10 +36,13 @@ - + - + @@ -57,10 +63,13 @@ - + - + @@ -85,7 +94,10 @@ - + diff --git a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml index 1c6acbf12..e235d298a 100644 --- a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml +++ b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml @@ -7,10 +7,13 @@
- + - + @@ -91,10 +94,13 @@ - + - + @@ -122,10 +128,13 @@ - + - + diff --git a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success_analyze.xml b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success_analyze.xml index 177659525..d14daf0f7 100644 --- a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success_analyze.xml +++ b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success_analyze.xml @@ -7,10 +7,13 @@
- + - + @@ -41,10 +44,13 @@ - + - + @@ -75,10 +81,13 @@ - + - + diff --git a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success_test_fcda_sort.xml b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success_test_fcda_sort.xml index 567eb21ac..fec1fb02d 100644 --- a/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success_test_fcda_sort.xml +++ b/sct-commons/src/test/resources/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success_test_fcda_sort.xml @@ -7,10 +7,13 @@
- + - + @@ -41,10 +44,13 @@ - + - + @@ -75,10 +81,13 @@ - + - + diff --git a/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_success.xml b/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_success.xml index c7869dfd7..7cd696da4 100644 --- a/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_success.xml +++ b/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_success.xml @@ -7,7 +7,10 @@
- + @@ -33,7 +36,10 @@ - + diff --git a/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_with_extref_errors.xml b/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_with_extref_errors.xml index 3fd8ae780..f5a281d3d 100644 --- a/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_with_extref_errors.xml +++ b/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_with_extref_errors.xml @@ -7,7 +7,10 @@
- + @@ -104,7 +107,10 @@ - + diff --git a/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_with_ied_errors.xml b/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_with_ied_errors.xml index 5955cca60..ad441a2cf 100644 --- a/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_with_ied_errors.xml +++ b/sct-commons/src/test/resources/scd-extref-iedname/scd_set_extref_iedname_with_ied_errors.xml @@ -8,7 +8,11 @@ - + @@ -21,7 +25,11 @@ - + @@ -46,7 +54,10 @@ - + @@ -60,7 +71,10 @@ - + diff --git a/sct-commons/src/test/resources/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml b/sct-commons/src/test/resources/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml new file mode 100644 index 000000000..e50105482 --- /dev/null +++ b/sct-commons/src/test/resources/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml @@ -0,0 +1,76 @@ + + + + + + +
+ + + + + + + + + + + + + on + + + + + + + on + + + + + + + on + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + on + off + test + + + diff --git a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd.xml b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd.xml index 61c829f27..f12214343 100644 --- a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd.xml +++ b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd.xml @@ -14,7 +14,8 @@ 0 - + @@ -25,7 +26,13 @@ - + diff --git a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd_lnode_with_many_compas_icdheader.xml b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd_lnode_with_many_compas_icdheader.xml index e89ea6852..889ad177b 100644 --- a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd_lnode_with_many_compas_icdheader.xml +++ b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd_lnode_with_many_compas_icdheader.xml @@ -14,7 +14,8 @@ 0 - + @@ -25,13 +26,31 @@ - + - + - + diff --git a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd_with_same_compas_icd_header_in_different_functions.xml b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd_with_same_compas_icd_header_in_different_functions.xml index d06f64392..6740a061e 100644 --- a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd_with_same_compas_icd_header_in_different_functions.xml +++ b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/scd_with_same_compas_icd_header_in_different_functions.xml @@ -16,14 +16,26 @@ - + - + diff --git a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/ssd.xml b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/ssd.xml index 591e03dd0..b1d3c399f 100644 --- a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/ssd.xml +++ b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/ssd.xml @@ -16,7 +16,13 @@ - + diff --git a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std.xml b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std.xml index 9428ba6d9..6037fdd5d 100644 --- a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std.xml +++ b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std.xml @@ -34,7 +34,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_SITESITE1SCU1.xml b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_SITESITE1SCU1.xml index 33c6aa8bb..2d0d3367e 100644 --- a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_SITESITE1SCU1.xml +++ b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_SITESITE1SCU1.xml @@ -34,7 +34,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_SITESITE1SCU2.xml b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_SITESITE1SCU2.xml index 43b7712f7..06fe92ae0 100644 --- a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_SITESITE1SCU2.xml +++ b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_SITESITE1SCU2.xml @@ -34,7 +34,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_with_same_ICDSystemVersionUUID.xml b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_with_same_ICDSystemVersionUUID.xml index 54a7c0cb7..13c70c849 100644 --- a/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_with_same_ICDSystemVersionUUID.xml +++ b/sct-commons/src/test/resources/scd-ied-dtt-com-import-stds/std_with_same_ICDSystemVersionUUID.xml @@ -34,7 +34,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test1_LD_STATUS_INACTIVE.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test1_LD_STATUS_INACTIVE.scd index cad226b1d..33fc9cba8 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test1_LD_STATUS_INACTIVE.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test1_LD_STATUS_INACTIVE.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,12 +31,22 @@ - + - + @@ -75,7 +86,11 @@ - + @@ -112,7 +127,11 @@ - + @@ -149,7 +168,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test2_LD_STATUS_INACTIVE.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test2_LD_STATUS_INACTIVE.scd index 76dd3fce0..72b928c71 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test2_LD_STATUS_INACTIVE.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test2_LD_STATUS_INACTIVE.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,7 +31,12 @@ - + @@ -70,7 +76,11 @@ - + @@ -107,7 +117,11 @@ - + @@ -144,7 +158,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingBeh.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingBeh.scd index b29dcd927..9e88bb19e 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingBeh.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingBeh.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,7 +31,12 @@ - + @@ -60,7 +66,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivate.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivate.scd index 09f288ffa..49cb8aac5 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivate.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivate.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,7 +31,12 @@ - + @@ -60,7 +66,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivateAttribute.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivateAttribute.scd index 83961dcac..b592f569d 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivateAttribute.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivateAttribute.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,7 +31,12 @@ - + @@ -60,7 +66,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingMod.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingMod.scd index 41c519502..27b6c193d 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingMod.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_KO_MissingMod.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,7 +31,12 @@ - + @@ -60,7 +66,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_LD_STATUS_ACTIVE.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_LD_STATUS_ACTIVE.scd index 5dc4b89f4..87ca28bf1 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_LD_STATUS_ACTIVE.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_LD_STATUS_ACTIVE.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,7 +31,12 @@ - + @@ -70,7 +76,11 @@ - + @@ -107,7 +117,11 @@ - + @@ -144,7 +158,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_LD_STATUS_UNTESTED.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_LD_STATUS_UNTESTED.scd index 3cf0dad8e..c6f31cdb5 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_LD_STATUS_UNTESTED.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_LD_STATUS_UNTESTED.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,7 +31,12 @@ - + @@ -70,7 +76,11 @@ - + @@ -107,7 +117,11 @@ - + @@ -144,7 +158,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_Template.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_Template.scd index 7a79a5be2..f5107142e 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_Template.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue68_Test_Template.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,7 +31,12 @@ - + @@ -70,7 +76,11 @@ - + @@ -107,7 +117,11 @@ - + @@ -144,7 +158,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/issue_165_enhance_68_Test_Dai_Updatable.scd b/sct-commons/src/test/resources/scd-refresh-lnode/issue_165_enhance_68_Test_Dai_Updatable.scd index e3fae2ae9..01a4b2e29 100644 --- a/sct-commons/src/test/resources/scd-refresh-lnode/issue_165_enhance_68_Test_Dai_Updatable.scd +++ b/sct-commons/src/test/resources/scd-refresh-lnode/issue_165_enhance_68_Test_Dai_Updatable.scd @@ -19,7 +19,8 @@ 0 - + @@ -30,7 +31,12 @@ - + @@ -70,7 +76,11 @@ - + @@ -107,7 +117,11 @@ - + @@ -144,7 +158,11 @@ - + @@ -176,7 +194,11 @@ - + @@ -213,7 +235,11 @@ - + diff --git a/sct-commons/src/test/resources/scd-substation-import-ssd/scd_with_substation.xml b/sct-commons/src/test/resources/scd-substation-import-ssd/scd_with_substation.xml index 60df1a663..362fd268f 100644 --- a/sct-commons/src/test/resources/scd-substation-import-ssd/scd_with_substation.xml +++ b/sct-commons/src/test/resources/scd-substation-import-ssd/scd_with_substation.xml @@ -10,7 +10,8 @@ 90 - + @@ -27,7 +28,13 @@ - + diff --git a/sct-commons/src/test/resources/scd-substation-import-ssd/ssd.xml b/sct-commons/src/test/resources/scd-substation-import-ssd/ssd.xml index 37b4f304d..9f05e267c 100644 --- a/sct-commons/src/test/resources/scd-substation-import-ssd/ssd.xml +++ b/sct-commons/src/test/resources/scd-substation-import-ssd/ssd.xml @@ -12,7 +12,8 @@ 0 - + @@ -23,14 +24,26 @@ - + - + @@ -40,7 +53,8 @@ 90 - + @@ -57,14 +71,21 @@ - + - + diff --git a/sct-commons/src/test/resources/scl-ln-adapter/scd_with_ln.xml b/sct-commons/src/test/resources/scl-ln-adapter/scd_with_ln.xml index d1493e76f..ff26c96d2 100644 --- a/sct-commons/src/test/resources/scl-ln-adapter/scd_with_ln.xml +++ b/sct-commons/src/test/resources/scl-ln-adapter/scd_with_ln.xml @@ -8,10 +8,13 @@ - + - + @@ -42,10 +45,13 @@ - + - + diff --git a/sct-commons/src/test/resources/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml b/sct-commons/src/test/resources/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml index d395939f3..682334769 100644 --- a/sct-commons/src/test/resources/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml +++ b/sct-commons/src/test/resources/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml @@ -33,7 +33,11 @@ - +