From a989b1a39e0e84c7a2f39f9b3633c106efa3eb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Hiszpa=C5=84ski?= Date: Mon, 20 Nov 2023 13:46:31 +0100 Subject: [PATCH] Refactoring and bug fixing Increased tests coverage to over 80% and locked limit in Jacoco plugin Sonar --- pom.xml | 38 ++- .../annotation/AnnotationService.java | 24 +- .../configuration/dictionary/Dictionary.java | 22 +- .../load/mapper/AutolinkMapper.java | 3 + .../load/mapper/AutonameMapper.java | 3 + .../load/mapper/ContextMapper.java | 6 +- .../load/mapper/DictionaryValueMapper.java | 3 + .../load/mapper/PropertyPageMapper.java | 3 + .../load/mapper/TemplateMapper.java | 3 + .../propertypage/content/control/Table.java | 3 - .../content/mapper/BaseControlsMapper.java | 36 +++ .../content/mapper/ControlMapper.java | 28 ++ .../mapper/DictionaryControlLoader.java | 128 ++++++++ .../content/mapper/PropertyPageMapper.java | 280 +----------------- .../content/mapper/SimpleControlMapper.java | 104 +++++++ .../content/mapper/TableMapper.java | 156 ++++++++++ .../java/com/avispa/ecm/util/Generated.java | 34 +++ .../com/avispa/ecm/util/SpringContext.java | 1 + src/test/java/com/avispa/ecm/UUIDTest.java | 63 ---- .../dictionary/DictionaryServiceTest.java | 14 +- .../dictionary/DictionaryTest.java | 151 ++++++++++ .../display/DisplayServiceTest.java | 58 ++++ .../load/mapper/ContextMapperTest.java | 200 +++++++++++++ .../load/mapper/UpsertMapperTest.java | 136 +++++++++ .../mapper/DictionaryControlLoaderTest.java | 151 ++++++++++ ...=> PropertyPageMapperIntegrationTest.java} | 22 +- .../mapper/SimpleControlMapperTest.java | 148 +++++++++ .../content/mapper/TableMapperTest.java | 153 ++++++++++ .../com/avispa/ecm/util/NestedObject.java | 4 +- .../com/avispa/ecm/util/TestDocument.java | 2 +- .../util/condition/ConditionParserTest.java | 30 +- .../ecm/util/json/JsonValidatorTest.java | 4 +- .../content/dictionaryFromProperty.json | 2 +- .../resources/content/dictionaryOverride.json | 2 +- src/test/resources/content/radio.json | 2 +- 35 files changed, 1606 insertions(+), 411 deletions(-) create mode 100644 src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/BaseControlsMapper.java create mode 100644 src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/ControlMapper.java create mode 100644 src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/DictionaryControlLoader.java create mode 100644 src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/SimpleControlMapper.java create mode 100644 src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/TableMapper.java create mode 100644 src/main/java/com/avispa/ecm/util/Generated.java delete mode 100644 src/test/java/com/avispa/ecm/UUIDTest.java create mode 100644 src/test/java/com/avispa/ecm/model/configuration/dictionary/DictionaryTest.java create mode 100644 src/test/java/com/avispa/ecm/model/configuration/display/DisplayServiceTest.java create mode 100644 src/test/java/com/avispa/ecm/model/configuration/load/mapper/ContextMapperTest.java create mode 100644 src/test/java/com/avispa/ecm/model/configuration/load/mapper/UpsertMapperTest.java create mode 100644 src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/DictionaryControlLoaderTest.java rename src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/{PropertyPageMapperTest.java => PropertyPageMapperIntegrationTest.java} (95%) create mode 100644 src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/SimpleControlMapperTest.java create mode 100644 src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/TableMapperTest.java diff --git a/pom.xml b/pom.xml index 1a34ac5..25fa334 100644 --- a/pom.xml +++ b/pom.xml @@ -44,9 +44,20 @@ UTF-8 11 4.4.6 - 1.5.5.Final + 1.6.0.Beta1 + true + + + sonar + + + false + + + + org.springframework.boot @@ -169,6 +180,11 @@ jacoco-maven-plugin 0.8.11 + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.10.0.2594 + @@ -232,6 +248,26 @@ verify + + jacoco-check + + check + + + + + BUNDLE + + + INSTRUCTION + COVEREDRATIO + 0.80 + + + + + + diff --git a/src/main/java/com/avispa/ecm/model/configuration/annotation/AnnotationService.java b/src/main/java/com/avispa/ecm/model/configuration/annotation/AnnotationService.java index 728172d..ec457de 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/annotation/AnnotationService.java +++ b/src/main/java/com/avispa/ecm/model/configuration/annotation/AnnotationService.java @@ -18,6 +18,7 @@ package com.avispa.ecm.model.configuration.annotation; +import com.avispa.ecm.util.exception.EcmException; import com.avispa.ecm.util.reflect.PropertyUtils; import lombok.extern.slf4j.Slf4j; @@ -36,15 +37,19 @@ protected A getFromAnnotation(Class annotationClass, C Field classMemberField = PropertyUtils.getField(actualClass, actualProperty); - if (null != classMemberField && classMemberField.isAnnotationPresent(annotationClass)) { - return classMemberField.getAnnotation(annotationClass); - } - - if(log.isWarnEnabled()) { - log.warn("{} annotation not found for {} field", annotationClass.getSimpleName(), propertyName); + if (null != classMemberField) { + if(classMemberField.isAnnotationPresent(annotationClass)){ + return classMemberField.getAnnotation(annotationClass); + } else { + if (log.isWarnEnabled()) { + log.warn("{} annotation not found for {} field", annotationClass.getSimpleName(), propertyName); + } + return null; + } + } else { + log.error("There is no field {} in {} class", propertyName, objectClass); + throw new EcmException("Can't determine display name for non existing '" + propertyName + "' property"); } - - return null; } /** @@ -61,7 +66,8 @@ private Class getActualClass(Class objectClass, String[] individualPropert Field field = PropertyUtils.getField(actualClass, individual); if(null == field) { - log.error("Error"); + log.error("There is no field {} in {} class", individual, actualClass); + throw new EcmException("Can't determine display name for non existing '" + individual + "' property"); } else { actualClass = field.getType(); } diff --git a/src/main/java/com/avispa/ecm/model/configuration/dictionary/Dictionary.java b/src/main/java/com/avispa/ecm/model/configuration/dictionary/Dictionary.java index 32386fb..471713d 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/dictionary/Dictionary.java +++ b/src/main/java/com/avispa/ecm/model/configuration/dictionary/Dictionary.java @@ -31,7 +31,6 @@ import javax.persistence.OneToMany; import java.util.ArrayList; import java.util.List; -import java.util.UUID; /** * @author Rafał Hiszpański @@ -41,6 +40,9 @@ @Entity @Slf4j public class Dictionary extends EcmConfig { + private static final String UNKNOWN_COLUMN = "UNKNOWN COLUMN"; + private static final String UNKNOWN_KEY = "UNKNOWN KEY"; + private String description; @OneToMany(cascade = CascadeType.ALL, mappedBy = "dictionary") @@ -57,7 +59,7 @@ public String getLabel(String key) { .filter(dictionaryValue -> dictionaryValue.getKey().equals(key)) .map(DictionaryValue::getLabel) .findFirst() - .orElse("UNKNOWN KEY"); + .orElse(UNKNOWN_KEY); } public String getColumnValue(String key, String columnName) { @@ -67,21 +69,9 @@ public String getColumnValue(String key, String columnName) { return values.stream() .filter(dictionaryValue -> dictionaryValue.getKey().equals(key)) - .map(dictionaryValue -> dictionaryValue.getColumns().get(columnName)) - .findFirst() - .orElse("UNKNOWN COLUMN"); - } - - public String getColumnValue(UUID valueId, String columnName) { - if (isEmpty()) { - return null; - } - - return values.stream() - .filter(dictionaryValue -> dictionaryValue.getId().equals(valueId)) - .map(dictionaryValue -> dictionaryValue.getColumns().get(columnName)) + .map(dictionaryValue -> dictionaryValue.getColumns().getOrDefault(columnName, UNKNOWN_COLUMN)) .findFirst() - .orElse("UNKNOWN COLUMN"); + .orElse(UNKNOWN_COLUMN); } public DictionaryValue getValue(String key) { diff --git a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/AutolinkMapper.java b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/AutolinkMapper.java index 42ff29b..3414841 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/AutolinkMapper.java +++ b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/AutolinkMapper.java @@ -20,6 +20,8 @@ import com.avispa.ecm.model.configuration.callable.autolink.Autolink; import com.avispa.ecm.model.configuration.load.dto.AutolinkDto; +import com.avispa.ecm.util.Generated; +import org.mapstruct.AnnotateWith; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingConstants; @@ -29,6 +31,7 @@ /** * @author Rafał Hiszpański */ +@AnnotateWith(Generated.class) @Mapper(componentModel = MappingConstants.ComponentModel.SPRING, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface AutolinkMapper extends EcmConfigMapper { @Override diff --git a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/AutonameMapper.java b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/AutonameMapper.java index 9f9c8e1..6bf59b4 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/AutonameMapper.java +++ b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/AutonameMapper.java @@ -20,6 +20,8 @@ import com.avispa.ecm.model.configuration.callable.autoname.Autoname; import com.avispa.ecm.model.configuration.load.dto.AutonameDto; +import com.avispa.ecm.util.Generated; +import org.mapstruct.AnnotateWith; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingConstants; @@ -29,6 +31,7 @@ /** * @author Rafał Hiszpański */ +@AnnotateWith(Generated.class) @Mapper(componentModel = MappingConstants.ComponentModel.SPRING, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface AutonameMapper extends EcmConfigMapper { @Override diff --git a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/ContextMapper.java b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/ContextMapper.java index f1bd12b..6d3a36d 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/ContextMapper.java +++ b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/ContextMapper.java @@ -47,15 +47,15 @@ public abstract class ContextMapper implements EcmConfigMapper configNameToConfigObject(List configNames); - @Override @Mapping(source = "name", target = "objectName") @Mapping(source = "configNames", target = "ecmConfigs") @Mapping(target = "matchRule", defaultValue = "{}") public abstract Context convertToEntity(ContextDto dto); + @IterableMapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT) + protected abstract List configNameToConfigObject(List configNames); + protected EcmConfig configNameToConfigObject(String configName) { return ecmConfigRepository.findByObjectName(configName).orElseThrow(RepositoryCorruptionError::new); } diff --git a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/DictionaryValueMapper.java b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/DictionaryValueMapper.java index c99f8aa..eedf7b8 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/DictionaryValueMapper.java +++ b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/DictionaryValueMapper.java @@ -20,6 +20,8 @@ import com.avispa.ecm.model.configuration.dictionary.DictionaryValue; import com.avispa.ecm.model.configuration.load.dto.DictionaryValueDto; +import com.avispa.ecm.util.Generated; +import org.mapstruct.AnnotateWith; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingConstants; @@ -29,6 +31,7 @@ /** * @author Rafał Hiszpański */ +@AnnotateWith(Generated.class) @Mapper(componentModel = MappingConstants.ComponentModel.SPRING, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface DictionaryValueMapper extends EcmConfigMapper { @Override diff --git a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/PropertyPageMapper.java b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/PropertyPageMapper.java index a2d765e..f76869f 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/PropertyPageMapper.java +++ b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/PropertyPageMapper.java @@ -20,6 +20,8 @@ import com.avispa.ecm.model.configuration.load.dto.PropertyPageDto; import com.avispa.ecm.model.configuration.propertypage.PropertyPage; +import com.avispa.ecm.util.Generated; +import org.mapstruct.AnnotateWith; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingConstants; @@ -29,6 +31,7 @@ /** * @author Rafał Hiszpański */ +@AnnotateWith(Generated.class) @Mapper(componentModel = MappingConstants.ComponentModel.SPRING, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface PropertyPageMapper extends EcmConfigMapper { @Override diff --git a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/TemplateMapper.java b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/TemplateMapper.java index 912f552..8863d23 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/load/mapper/TemplateMapper.java +++ b/src/main/java/com/avispa/ecm/model/configuration/load/mapper/TemplateMapper.java @@ -20,6 +20,8 @@ import com.avispa.ecm.model.configuration.load.dto.TemplateDto; import com.avispa.ecm.model.configuration.template.Template; +import com.avispa.ecm.util.Generated; +import org.mapstruct.AnnotateWith; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingConstants; @@ -29,6 +31,7 @@ /** * @author Rafał Hiszpański */ +@AnnotateWith(Generated.class) @Mapper(componentModel = MappingConstants.ComponentModel.SPRING, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface TemplateMapper extends EcmConfigMapper { @Override diff --git a/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/control/Table.java b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/control/Table.java index 2ae6a8f..f144752 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/control/Table.java +++ b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/control/Table.java @@ -18,7 +18,6 @@ package com.avispa.ecm.model.configuration.propertypage.content.control; -import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; @@ -31,8 +30,6 @@ @Setter public class Table extends PropertyControl { private List controls; - @JsonIgnore - private Class propertyType; // TODO: required? private int size; diff --git a/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/BaseControlsMapper.java b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/BaseControlsMapper.java new file mode 100644 index 0000000..a4ac0ad --- /dev/null +++ b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/BaseControlsMapper.java @@ -0,0 +1,36 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.propertypage.content.mapper; + +import com.avispa.ecm.model.configuration.propertypage.content.control.Control; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * @author Rafał Hiszpański + */ +@Slf4j +@RequiredArgsConstructor +abstract class BaseControlsMapper implements ControlMapper { + protected static final String OBJECT_NAME = "objectName"; + + protected final DictionaryControlLoader dictionaryControlLoader; + protected final ObjectMapper objectMapper; +} \ No newline at end of file diff --git a/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/ControlMapper.java b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/ControlMapper.java new file mode 100644 index 0000000..dec271a --- /dev/null +++ b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/ControlMapper.java @@ -0,0 +1,28 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.propertypage.content.mapper; + +import com.avispa.ecm.model.configuration.propertypage.content.control.Control; + +/** + * @author Rafał Hiszpański + */ +interface ControlMapper { + void processControl(C control, Object context); +} \ No newline at end of file diff --git a/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/DictionaryControlLoader.java b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/DictionaryControlLoader.java new file mode 100644 index 0000000..aba5c2d --- /dev/null +++ b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/DictionaryControlLoader.java @@ -0,0 +1,128 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.propertypage.content.mapper; + +import com.avispa.ecm.model.EcmEntity; +import com.avispa.ecm.model.EcmObject; +import com.avispa.ecm.model.configuration.dictionary.Dictionary; +import com.avispa.ecm.model.configuration.dictionary.DictionaryNotFoundException; +import com.avispa.ecm.model.configuration.dictionary.DictionaryService; +import com.avispa.ecm.model.configuration.dictionary.DictionaryValue; +import com.avispa.ecm.model.configuration.propertypage.content.control.ComboRadio; +import com.avispa.ecm.model.type.Type; +import com.avispa.ecm.model.type.TypeService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author Rafał Hiszpański + */ +@Component +@RequiredArgsConstructor +@Slf4j +class DictionaryControlLoader { + private final DictionaryService dictionaryService; + private final TypeService typeService; + + @PersistenceContext + private final EntityManager entityManager; + + /** + * Loads dictionary used by combo boxes and radio buttons + * @param comboRadio + * @param contextClass + */ + public void loadDictionary(ComboRadio comboRadio, Class contextClass) { + if(StringUtils.isNotEmpty(comboRadio.getTypeName())) { + loadValuesFromObject(comboRadio); + } else { + Dictionary dictionary = getDictionary(comboRadio, contextClass); + loadValuesFromDictionary(comboRadio, dictionary); + } + } + + private void loadValuesFromObject(ComboRadio comboRadio) { + Type type = typeService.getType(comboRadio.getTypeName()); + if (null != type) { + List ecmObjects = getEcmObjects(type); + + Map values = ecmObjects.stream() + .filter(ecmObject -> StringUtils.isNotEmpty(ecmObject.getObjectName())) // filter out incorrect values with empty object name + .sorted(Comparator.comparing(EcmObject::getObjectName)) + .collect(Collectors.toMap(ecmObject -> ecmObject.getId().toString(), EcmObject::getObjectName, (x, y) -> x, LinkedHashMap::new)); + + comboRadio.setOptions(values); + } else { + log.error("Type '{}' was not found", comboRadio.getTypeName()); + } + } + + private List getEcmObjects(Type type) { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cr = cb.createQuery(EcmObject.class); + Root root = cr.from(type.getEntityClass()); + cr.select(root); + + TypedQuery query = entityManager.createQuery(cr); + return query.getResultList(); + } + + private Dictionary getDictionary(ComboRadio comboRadio, Class contextClass) { + String dictionaryName = comboRadio.getDictionary(); + + // if dictionary was not retrieved from property page, try with annotation + if(StringUtils.isEmpty(dictionaryName)) { + dictionaryName = dictionaryService.getDictionaryNameFromAnnotation(contextClass, comboRadio.getProperty()); + } + + // if dictionary name is still not resolved throw an exception + if(StringUtils.isEmpty(dictionaryName)) { + throw new DictionaryNotFoundException( + String.format("Dictionary is not specified in property page configuration or using annotation in entity definition. Related property: '%s'", comboRadio.getProperty()) + ); + } + + return dictionaryService.getDictionary(dictionaryName); + } + + private void loadValuesFromDictionary(ComboRadio comboRadio, Dictionary dictionary) { + log.debug("Loading values from {} dictionary", dictionary.getObjectName()); + + Map values = dictionary.getValues().stream() + .filter(value -> StringUtils.isNotEmpty(value.getLabel())) // filter out incorrect values with empty object name + .sorted(Comparator.comparing(EcmEntity::getObjectName)) + .collect(Collectors.toMap(DictionaryValue::getKey, DictionaryValue::getLabel, (x, y) -> x, LinkedHashMap::new)); + + comboRadio.setOptions(values); + } +} diff --git a/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapper.java b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapper.java index 1d67ca0..9e2e721 100644 --- a/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapper.java +++ b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapper.java @@ -18,56 +18,25 @@ package com.avispa.ecm.model.configuration.propertypage.content.mapper; -import com.avispa.ecm.model.EcmEntity; -import com.avispa.ecm.model.EcmObject; -import com.avispa.ecm.model.configuration.dictionary.Dictionary; -import com.avispa.ecm.model.configuration.dictionary.DictionaryService; -import com.avispa.ecm.model.configuration.dictionary.DictionaryValue; -import com.avispa.ecm.model.configuration.display.DisplayService; import com.avispa.ecm.model.configuration.propertypage.PropertyPage; import com.avispa.ecm.model.configuration.propertypage.content.PropertyPageContent; import com.avispa.ecm.model.configuration.propertypage.content.control.Columns; -import com.avispa.ecm.model.configuration.propertypage.content.control.ComboRadio; import com.avispa.ecm.model.configuration.propertypage.content.control.Control; import com.avispa.ecm.model.configuration.propertypage.content.control.Group; -import com.avispa.ecm.model.configuration.propertypage.content.control.Hidden; -import com.avispa.ecm.model.configuration.propertypage.content.control.Label; -import com.avispa.ecm.model.configuration.propertypage.content.control.PropertyControl; import com.avispa.ecm.model.configuration.propertypage.content.control.Tab; import com.avispa.ecm.model.configuration.propertypage.content.control.Table; import com.avispa.ecm.model.configuration.propertypage.content.control.Tabs; import com.avispa.ecm.model.content.Content; -import com.avispa.ecm.model.type.Type; -import com.avispa.ecm.model.type.TypeService; -import com.avispa.ecm.util.expression.ExpressionResolver; -import com.avispa.ecm.util.expression.ExpressionResolverException; -import com.avispa.ecm.util.reflect.PropertyUtils; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.util.Strings; -import org.springframework.data.jpa.repository.support.SimpleJpaRepository; import org.springframework.stereotype.Component; -import org.springframework.util.ReflectionUtils; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.ParameterizedType; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; /** * @author Rafał Hiszpański @@ -76,16 +45,11 @@ @RequiredArgsConstructor @Slf4j public class PropertyPageMapper { - private static final String OBJECT_NAME = "objectName"; - - private final ExpressionResolver expressionResolver; - private final TypeService typeService; + private final ObjectMapper objectMapper; - private final DictionaryService dictionaryService; - private final DisplayService displayService; - @PersistenceContext - private EntityManager entityManager; + private final SimpleControlMapper simpleControlMapper; + private final TableMapper tableMapper; public PropertyPageContent convertToContent(PropertyPage propertyPage, Object context, boolean readonly) { PropertyPageContent propertyPageContent = getPropertyPageContent(propertyPage.getPrimaryContent()).orElseThrow(); @@ -132,244 +96,10 @@ private void processControls(List controls, Object context) { } } else if(control instanceof Table) { Table table = (Table)control; - - Class rowClass = getTableRowClass(table, context.getClass()); - if(null == rowClass) { - String errorMessage = String.format("Class of the table row can't be identified based on the '%s' property of '%s' context type.", table.getProperty(), context.getClass()); - log.error(errorMessage); - throw new IllegalStateException(errorMessage); - } - table.setPropertyType(rowClass); - - processTableControls(table, context); + tableMapper.processControl(table, context); } else { - processControl(control, context); - } - } - } - - /** - * Identifies table data type. It uses following approach: - * 1. Get field from context class of name defined in the table configuration - * 2. Check if field is a list - * 3. Extract info about type of elements in the list - * 4. Found value is the table data type. - * @param table - * @param contextClass - * @return - */ - private Class getTableRowClass(Table table, Class contextClass) { - Field field = ReflectionUtils.findField(contextClass, table.getProperty()); - if(field != null && field.getType().isAssignableFrom(List.class)) { - java.lang.reflect.Type genericFieldType = field.getGenericType(); - - if (genericFieldType instanceof ParameterizedType) { - ParameterizedType aType = (ParameterizedType) genericFieldType; - java.lang.reflect.Type[] fieldArgTypes = aType.getActualTypeArguments(); - if(fieldArgTypes.length > 0) { - Class rowClass = (Class) fieldArgTypes[0]; - log.debug("Found table type class: '{}'", rowClass); - return rowClass; - } else { - log.error("Type of the '{}' not found", table.getProperty()); - } - } - } else { - log.error("Property '{}' not found in class '{}' or the property is not of the List type.", table.getProperty(), contextClass); - } - return null; - } - - private void processTableControls(Table table, Object context) { - table.getControls().stream() - .filter(ComboRadio.class::isInstance) - .map(ComboRadio.class::cast) - .forEach(comboRadio -> { - if(StringUtils.isNotEmpty(comboRadio.getTypeName())) { - log.info("Type name for tables is ignored. Use dictionaries only."); - comboRadio.setTypeName(""); - } - loadDictionary(comboRadio, table.getPropertyType()); - }); - - // table controls are always required - table.getControls() - .forEach(control -> control.setRequired(true)); - - // always add row id - Hidden hidden = new Hidden(); - hidden.setProperty("id"); - table.getControls().add(hidden); - - fillTablePropertyValue(table, context); - } - - private void fillTablePropertyValue(Table table, Object context) { - String propertyName = table.getProperty(); // get property path - - // convert context object to tree representation and navigate to the node - JsonNode root = objectMapper.valueToTree(context); - - int size = getTableSize(table, context); - table.setSize(size); - - for (PropertyControl control : table.getControls()) { - List row = new ArrayList<>(); - for (int i = 0; i < size; i++) { - String jsonPtrExpression = "/" + propertyName.replace(".", "/") + "/" + i + "/" + control.getProperty(); - JsonNode node = root.at(jsonPtrExpression); - - if (node.isMissingNode()) { - log.warn("Value for {} property has bee not found", propertyName); - row.add(""); // empty - } else if (node.isObject()) { - Map map = new HashMap<>(); - map.put(OBJECT_NAME, node.get(OBJECT_NAME)); - map.put("id", node.get("id")); - row.add(map); - } else { - row.add(node.asText()); - } - } - control.setValue(row); - } - } - - private static int getTableSize(Table table, Object context) { - int rows = 0; - var value = PropertyUtils.getPropertyValue(context, table.getProperty()); - if(value instanceof Collection) { - rows = ((Collection) value).size(); - } else { - log.warn("Property {} does not contain a collection of values", table.getProperty()); - } - return rows; - } - - private void processControl(Control control, Object context) { - if(control instanceof Label) { - Label label = (Label)control; - try { - label.setExpression(expressionResolver.resolve(context, label.getExpression())); - } catch (ExpressionResolverException e) { - log.error("Label expression couldn't be resolved", e); - } - } else if(control instanceof PropertyControl) { - // TODO: validate if property is accessible? - PropertyControl propertyControl = (PropertyControl) control; - if(Strings.isEmpty(propertyControl.getLabel())) { - propertyControl.setLabel(displayService.getDisplayValueFromAnnotation(context.getClass(), propertyControl.getProperty())); - } - - if(control instanceof ComboRadio) { - ComboRadio comboRadio = (ComboRadio) control; - try { - if (StringUtils.isEmpty(comboRadio.getTypeName()) && StringUtils.isNotEmpty(comboRadio.getTypeNameExpression())) { - comboRadio.setTypeName(expressionResolver.resolve(context, comboRadio.getTypeNameExpression())); - } - } catch (ExpressionResolverException e) { - log.error("Type name expression couldn't be resolved", e); - } - loadDictionary(comboRadio, context.getClass()); + simpleControlMapper.processControl(control, context); } - - fillPropertyValue(propertyControl, context); - } - } - - private void fillPropertyValue(PropertyControl propertyControl, Object context) { - String propertyName = propertyControl.getProperty(); // get property path - - // convert context object to tree representation and navigate to the node - JsonNode root = objectMapper.valueToTree(context); - JsonNode node = root.at("/" + propertyName.replace(".", "/")); - - if(node.isMissingNode()) { - log.warn("Value for {} property has bee not found", propertyName); - propertyControl.setValue(""); // empty - } else if(node.isObject()) { - Map map = new HashMap<>(); - map.put(OBJECT_NAME, node.get(OBJECT_NAME)); - map.put("id", node.get("id")); - propertyControl.setValue(map); - } else { - propertyControl.setValue(node.asText()); - } - } - - /** - * Loads dictionary used by combo boxes and radio buttons - * @param comboRadio - * @param contextClass - */ - private void loadDictionary(ComboRadio comboRadio, Class contextClass) { - if(StringUtils.isNotEmpty(comboRadio.getTypeName())) { - loadValuesFromObject(comboRadio); - } else { - Dictionary dictionary = getDictionary(comboRadio, contextClass); - loadValuesFromDictionary(comboRadio, dictionary); - } - } - - private void loadValuesFromObject(ComboRadio comboRadio) { - Type type = typeService.getType(comboRadio.getTypeName()); - if (null != type) { - List ecmObjects = getEcmObjects(type); - - Map values = ecmObjects.stream() - .filter(ecmObject -> StringUtils.isNotEmpty(ecmObject.getObjectName())) // filter out incorrect values with empty object name - .sorted(Comparator.comparing(EcmObject::getObjectName)) - .collect(Collectors.toMap(ecmObject -> ecmObject.getId().toString(), EcmObject::getObjectName, (x, y) -> x, LinkedHashMap::new)); - - comboRadio.setOptions(values); - } else { - log.error("Type '{}' was not found", comboRadio.getTypeName()); } } - - private List getEcmObjects(Type type) { - SimpleJpaRepository jpaRepository = getSimpleRepository(type); - return jpaRepository.findAll(); - } - - /** - * Creates simple repository for specific type. This will create repositories even for the - * abstract types allowing to get all concrete subtypes objects. - * @param type type for which we want to get repository - * @return - */ - private SimpleJpaRepository getSimpleRepository(Type type) { - SimpleJpaRepository jpaRepository; - jpaRepository = new SimpleJpaRepository<>(type.getEntityClass(), entityManager); - return jpaRepository; - } - - private Dictionary getDictionary(ComboRadio comboRadio, Class contextClass) { - String dictionaryName = comboRadio.getDictionary(); - - // if dictionary was not retrieved from property page, try with annotation - if(StringUtils.isEmpty(dictionaryName)) { - dictionaryName = dictionaryService.getDictionaryNameFromAnnotation(contextClass, comboRadio.getProperty()); - } - - // if dictionary name is still not resolved throw an exception - if(StringUtils.isEmpty(dictionaryName)) { - throw new IllegalStateException( - String.format("Dictionary is not specified in property page configuration or using annotation in entity definition. Related property: '%s'", comboRadio.getProperty()) - ); - } - - return dictionaryService.getDictionary(dictionaryName); - } - - private void loadValuesFromDictionary(ComboRadio comboRadio, Dictionary dictionary) { - log.debug("Loading values from {} dictionary", dictionary.getObjectName()); - - Map values = dictionary.getValues().stream() - .filter(value -> StringUtils.isNotEmpty(value.getLabel())) // filter out incorrect values with empty object name - .sorted(Comparator.comparing(EcmEntity::getObjectName)) - .collect(Collectors.toMap(DictionaryValue::getKey, DictionaryValue::getLabel, (x, y) -> x, LinkedHashMap::new)); - - comboRadio.setOptions(values); - } } \ No newline at end of file diff --git a/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/SimpleControlMapper.java b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/SimpleControlMapper.java new file mode 100644 index 0000000..0296d75 --- /dev/null +++ b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/SimpleControlMapper.java @@ -0,0 +1,104 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.propertypage.content.mapper; + +import com.avispa.ecm.model.configuration.display.DisplayService; +import com.avispa.ecm.model.configuration.propertypage.content.control.ComboRadio; +import com.avispa.ecm.model.configuration.propertypage.content.control.Control; +import com.avispa.ecm.model.configuration.propertypage.content.control.Label; +import com.avispa.ecm.model.configuration.propertypage.content.control.PropertyControl; +import com.avispa.ecm.util.expression.ExpressionResolver; +import com.avispa.ecm.util.expression.ExpressionResolverException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.NullNode; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Strings; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Rafał Hiszpański + */ +@Component +@Slf4j +class SimpleControlMapper extends BaseControlsMapper { + private final ExpressionResolver expressionResolver; + private final DisplayService displayService; + + SimpleControlMapper(DictionaryControlLoader dictionaryControlLoader, ObjectMapper objectMapper, ExpressionResolver expressionResolver, DisplayService displayService) { + super(dictionaryControlLoader, objectMapper); + this.expressionResolver = expressionResolver; + this.displayService = displayService; + } + + public void processControl(Control control, Object context) { + if(control instanceof Label) { + Label label = (Label)control; + try { + label.setExpression(expressionResolver.resolve(context, label.getExpression())); + } catch (ExpressionResolverException e) { + log.error("Label expression couldn't be resolved", e); + } + } else if(control instanceof PropertyControl) { + // TODO: validate if property is accessible? + PropertyControl propertyControl = (PropertyControl) control; + if(Strings.isEmpty(propertyControl.getLabel())) { + propertyControl.setLabel(displayService.getDisplayValueFromAnnotation(context.getClass(), propertyControl.getProperty())); + } + + if(control instanceof ComboRadio) { + ComboRadio comboRadio = (ComboRadio) control; + try { + if (StringUtils.isEmpty(comboRadio.getTypeName()) && StringUtils.isNotEmpty(comboRadio.getTypeNameExpression())) { + comboRadio.setTypeName(expressionResolver.resolve(context, comboRadio.getTypeNameExpression())); + } + } catch (ExpressionResolverException e) { + log.error("Type name expression couldn't be resolved", e); + } + dictionaryControlLoader.loadDictionary(comboRadio, context.getClass()); + } + + fillPropertyValue(propertyControl, context); + } + } + + private void fillPropertyValue(PropertyControl propertyControl, Object context) { + String propertyName = propertyControl.getProperty(); // get property path + + // convert context object to tree representation and navigate to the node + JsonNode root = objectMapper.valueToTree(context); + JsonNode node = root.at("/" + propertyName.replace(".", "/")); + + if(node instanceof NullNode || node.isMissingNode()) { + log.warn("Value for {} property has bee not found", propertyName); + propertyControl.setValue(""); // empty + } else if(node.isObject()) { + Map map = new HashMap<>(); + map.put(OBJECT_NAME, node.get(OBJECT_NAME).asText()); + map.put("id", node.get("id").asText()); + propertyControl.setValue(map); + } else { + propertyControl.setValue(node.asText()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/TableMapper.java b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/TableMapper.java new file mode 100644 index 0000000..adfd20c --- /dev/null +++ b/src/main/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/TableMapper.java @@ -0,0 +1,156 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.propertypage.content.mapper; + +import com.avispa.ecm.model.configuration.propertypage.content.control.ComboRadio; +import com.avispa.ecm.model.configuration.propertypage.content.control.Hidden; +import com.avispa.ecm.model.configuration.propertypage.content.control.PropertyControl; +import com.avispa.ecm.model.configuration.propertypage.content.control.Table; +import com.avispa.ecm.util.exception.EcmException; +import com.avispa.ecm.util.reflect.PropertyUtils; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Rafał Hiszpański + */ +@Component +@Slf4j +class TableMapper extends BaseControlsMapper { + + TableMapper(DictionaryControlLoader dictionaryControlLoader, ObjectMapper objectMapper) { + super(dictionaryControlLoader, objectMapper); + } + + public void processControl(Table table, Object context) { + Class tableRowClass = getTableRowClass(table, context.getClass()); + + table.getControls().stream() + .filter(ComboRadio.class::isInstance) + .map(ComboRadio.class::cast) + .forEach(comboRadio -> { + if(log.isDebugEnabled() && StringUtils.isNotEmpty(comboRadio.getTypeName())) { + log.debug("Type name for tables is ignored. Dictionary will be used if exists."); + } + dictionaryControlLoader.loadDictionary(comboRadio, tableRowClass); + }); + + // table controls are always required + table.getControls() + .forEach(control -> control.setRequired(true)); + + // always add row id + Hidden hidden = new Hidden(); + hidden.setProperty("id"); + table.getControls().add(hidden); + + fillPropertyValue(table, context); + } + + /** + * Identifies table data type. It uses following approach: + * 1. Get field from context class of name defined in the table configuration + * 2. Check if field is a list + * 3. Extract info about type of elements in the list + * 4. Found value is the table data type. + * @param table + * @param contextClass + * @return + */ + private Class getTableRowClass(Table table, Class contextClass) { + Field field = ReflectionUtils.findField(contextClass, table.getProperty()); + if(field != null && field.getType().isAssignableFrom(List.class)) { + java.lang.reflect.Type genericFieldType = field.getGenericType(); + + if (genericFieldType instanceof ParameterizedType) { + ParameterizedType aType = (ParameterizedType) genericFieldType; + java.lang.reflect.Type[] fieldArgTypes = aType.getActualTypeArguments(); + if(fieldArgTypes.length > 0) { + Class rowClass = (Class) fieldArgTypes[0]; + log.debug("Found table type class: '{}'", rowClass); + return rowClass; + } else { + log.error("Type of the '{}' not found", table.getProperty()); + } + } + } else { + log.error("Property '{}' not found in class '{}' or the property is not of the List type.", table.getProperty(), contextClass); + } + + String errorMessage = String.format("Class of the table row can't be identified based on the '%s' property of '%s' context type.", table.getProperty(), contextClass); + log.error(errorMessage); + + throw new EcmException(errorMessage); + } + + private void fillPropertyValue(Table table, Object context) { + String propertyName = table.getProperty(); // get property path + + // convert context object to tree representation and navigate to the node + JsonNode root = objectMapper.valueToTree(context); + + int size = getTableSize(table, context); + table.setSize(size); + + for (PropertyControl control : table.getControls()) { + List row = new ArrayList<>(); + for (int i = 0; i < size; i++) { + String jsonPtrExpression = "/" + propertyName.replace(".", "/") + "/" + i + "/" + control.getProperty(); + JsonNode node = root.at(jsonPtrExpression); + + if (node.isMissingNode()) { + log.warn("Value for {} property has bee not found", propertyName); + row.add(""); // empty + } else if (node.isObject()) { + Map map = new HashMap<>(); + map.put(OBJECT_NAME, node.get(OBJECT_NAME).asText()); + map.put("id", node.get("id").asText()); + row.add(map); + } else { + row.add(node.asText()); + } + } + control.setValue(row); + } + } + + private static int getTableSize(Table table, Object context) { + int rows = 0; + var value = PropertyUtils.getPropertyValue(context, table.getProperty()); + if(value == null) { + log.warn("Property '{}' is null. The size will be assumed to 0.", table.getProperty()); + } else if(value instanceof List) { + rows = ((List) value).size(); + } else { + log.warn("Property '{}' does not contain a list of values", table.getProperty()); + } + return rows; + } +} diff --git a/src/main/java/com/avispa/ecm/util/Generated.java b/src/main/java/com/avispa/ecm/util/Generated.java new file mode 100644 index 0000000..aec5606 --- /dev/null +++ b/src/main/java/com/avispa/ecm/util/Generated.java @@ -0,0 +1,34 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.util; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Retention(RUNTIME) +@Target({TYPE, METHOD, CONSTRUCTOR}) +public @interface Generated { +} \ No newline at end of file diff --git a/src/main/java/com/avispa/ecm/util/SpringContext.java b/src/main/java/com/avispa/ecm/util/SpringContext.java index a3be17e..932a9c3 100644 --- a/src/main/java/com/avispa/ecm/util/SpringContext.java +++ b/src/main/java/com/avispa/ecm/util/SpringContext.java @@ -50,6 +50,7 @@ public static T getBean(String beanName, Class beanClass) { } @Override + @SuppressWarnings("java:S2696") public void setApplicationContext(ApplicationContext context) throws BeansException { // store ApplicationContext reference to access required beans later on SpringContext.context = context; diff --git a/src/test/java/com/avispa/ecm/UUIDTest.java b/src/test/java/com/avispa/ecm/UUIDTest.java deleted file mode 100644 index ceb6739..0000000 --- a/src/test/java/com/avispa/ecm/UUIDTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Avispa ECM - a small framework for implementing basic ECM solution - * Copyright (C) 2023 Rafał Hiszpański - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.avispa.ecm; - -import org.apache.commons.lang3.StringUtils; -import org.junit.jupiter.api.Test; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Base64; -import java.util.UUID; - -/** - * @author Rafał Hiszpański - */ -class UUIDTest { - - @Test - void basicTest() { - System.out.println("Random: " + UUID.randomUUID()); - UUID uuid = UUID.fromString("123e4567-e89b-12d3-a456-556642440000"); - System.out.println("From string: " + uuid); - String encoded = Base64.getUrlEncoder().encodeToString(asBytes(uuid)); - System.out.println("Original Array: " + Arrays.toString(asBytes(uuid))); - System.out.println("Encoded: " + encoded); - System.out.println("Decoded: " + asUuid(Base64.getUrlDecoder().decode(encoded))); - System.out.println("Decoded Array: " + Arrays.toString(Base64.getUrlDecoder().decode(encoded))); - - System.out.println("Decoded: " + asUuid(Base64.getUrlDecoder().decode("vytxeTZskVKR7C7WgdSP3d=="))); - - System.out.println(StringUtils.rightPad("Ej5FZ-ibEtOkVlVmQkQAAA", 24, '=')); - } - - public static UUID asUuid(byte[] bytes) { - ByteBuffer bb = ByteBuffer.wrap(bytes); - long firstLong = bb.getLong(); - long secondLong = bb.getLong(); - return new UUID(firstLong, secondLong); - } - - public static byte[] asBytes(UUID uuid) { - ByteBuffer bb = ByteBuffer.wrap(new byte[16]); - bb.putLong(uuid.getMostSignificantBits()); - bb.putLong(uuid.getLeastSignificantBits()); - return bb.array(); - } -} diff --git a/src/test/java/com/avispa/ecm/model/configuration/dictionary/DictionaryServiceTest.java b/src/test/java/com/avispa/ecm/model/configuration/dictionary/DictionaryServiceTest.java index 8ce09a7..0754705 100644 --- a/src/test/java/com/avispa/ecm/model/configuration/dictionary/DictionaryServiceTest.java +++ b/src/test/java/com/avispa/ecm/model/configuration/dictionary/DictionaryServiceTest.java @@ -48,17 +48,17 @@ class DictionaryServiceTest { @BeforeEach void init() { lenient().when(dictionaryRepository.findByObjectName(anyString())).thenAnswer(invocation -> { - if(invocation.getArgument(0).equals("TestDict")) { + if(invocation.getArgument(0).equals("Test Dictionary")) { return Optional.of(getTestDictionary()); } - throw new DictionaryNotFoundException("TestDict"); + throw new DictionaryNotFoundException("Test Dictionary"); }); } private Dictionary getTestDictionary() { Dictionary testDict = new Dictionary(); - testDict.setObjectName("TestDict"); + testDict.setObjectName("Test Dictionary"); DictionaryValue dv1 = new DictionaryValue(); dv1.setKey("first"); @@ -81,9 +81,9 @@ private Dictionary getTestDictionary() { @Test void givenDictionaryName_whenGetDictionary_thenReturnDictionary() { - Dictionary dictionary = dictionaryService.getDictionary("TestDict"); + Dictionary dictionary = dictionaryService.getDictionary("Test Dictionary"); - assertEquals("TestDict", dictionary.getObjectName()); + assertEquals("Test Dictionary", dictionary.getObjectName()); } @Test @@ -94,14 +94,14 @@ void givenIncorrectDictionaryName_whenGetDictionary_thenThrowException() { @Test void givenEntityClassAndPropertyName_whenGetDictionaryName_thenReturnDictionary() { - assertEquals("TestDict", dictionaryService.getDictionaryNameFromAnnotation(TestDocument.class, "testString")); + assertEquals("Test Dictionary", dictionaryService.getDictionaryNameFromAnnotation(TestDocument.class, "testString")); } @Test void givenEntityClassAndPropertyName_whenGetDictionary_thenReturnDictionary() { Dictionary dictionary = dictionaryService.getDictionary(TestDocument.class, "testString"); - assertEquals("TestDict", dictionary.getObjectName()); + assertEquals("Test Dictionary", dictionary.getObjectName()); } @Test diff --git a/src/test/java/com/avispa/ecm/model/configuration/dictionary/DictionaryTest.java b/src/test/java/com/avispa/ecm/model/configuration/dictionary/DictionaryTest.java new file mode 100644 index 0000000..d7263f1 --- /dev/null +++ b/src/test/java/com/avispa/ecm/model/configuration/dictionary/DictionaryTest.java @@ -0,0 +1,151 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.dictionary; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Rafał Hiszpański + */ +class DictionaryTest { + @Test + void givenDictionary_whenAddValue_thenItIsAccessible() { + Dictionary dictionary = new Dictionary(); + dictionary.setObjectName("Dictionary"); + dictionary.setDescription("Description"); + + DictionaryValue dictionaryValue = getDictionaryValue(); + + dictionary.addValue(dictionaryValue); + + assertFalse(dictionary.isEmpty()); + assertEquals(dictionaryValue, dictionary.getValue("Key 1")); + assertEquals(dictionary, dictionaryValue.getDictionary()); + } + + @Test + void givenDictionaryWithValue_whenRemoveValue_thenDictionaryIsEmpty() { + Dictionary dictionary = new Dictionary(); + dictionary.setObjectName("Dictionary"); + dictionary.setDescription("Description"); + + DictionaryValue dictionaryValue = getDictionaryValue(); + + dictionary.addValue(dictionaryValue); + dictionary.removeValue(dictionaryValue); + + assertTrue(dictionary.isEmpty()); + assertNull(dictionary.getValue("Key 1")); + } + + @Test + void givenDictionaryWithMultipleValues_whenClearValues_thenDictionaryIsEmpty() { + Dictionary dictionary = new Dictionary(); + dictionary.setObjectName("Dictionary"); + dictionary.setDescription("Description"); + + DictionaryValue dictionaryValue = getDictionaryValue(); + DictionaryValue dictionaryValue2 = getDictionaryValue("Key 2", "Label 2", Map.of()); + + dictionary.addValue(dictionaryValue); + dictionary.addValue(dictionaryValue2); + + dictionary.clearValues(); + + assertTrue(dictionary.isEmpty()); + } + + @ParameterizedTest + @CsvSource(value = { + "Key 1,Label 1", + "Key 3, UNKNOWN KEY" + }) + void givenDictionaryWithValue_whenGetLabel_thenLabelIsReturned(String key, String label) { + Dictionary dictionary = new Dictionary(); + dictionary.setObjectName("Dictionary"); + dictionary.setDescription("Description"); + + DictionaryValue dictionaryValue = getDictionaryValue(); + + dictionary.addValue(dictionaryValue); + + assertEquals(label, dictionary.getLabel(key)); + } + + @Test + void givenEmptyDictionary_whenGetLabel_thenReturnNull() { + Dictionary dictionary = new Dictionary(); + dictionary.setObjectName("Dictionary"); + dictionary.setDescription("Description"); + + assertNull(dictionary.getLabel("Key 1")); + } + + @ParameterizedTest + @CsvSource(value = { + "Key 1,Column 1,Value 1", + "Key 1,Column 3,UNKNOWN COLUMN", + "Key 3,Column 1,UNKNOWN COLUMN" + }) + void givenDictionaryWithValue_whenGetColumnValue_thenColumnValueIsReturned(String key, String column, String columnValue) { + Dictionary dictionary = new Dictionary(); + dictionary.setObjectName("Dictionary"); + dictionary.setDescription("Description"); + + DictionaryValue dictionaryValue = getDictionaryValue(); + + dictionary.addValue(dictionaryValue); + + assertEquals(columnValue, dictionary.getColumnValue(key, column)); + } + + @Test + void givenEmptyDictionary_whenGetColumnValue_thenReturnNull() { + Dictionary dictionary = new Dictionary(); + dictionary.setObjectName("Dictionary"); + dictionary.setDescription("Description"); + + assertNull(dictionary.getColumnValue("Key 1", "Column 1")); + } + + private static DictionaryValue getDictionaryValue() { + return getDictionaryValue("Key 1", "Label 1", Map.of("Column 1", "Value 1", "Column 2", "Value 2")); + } + + private static DictionaryValue getDictionaryValue(String key, String label, Map columns) { + Map mutableColumns = new HashMap<>(columns); + + DictionaryValue dictionaryValue = new DictionaryValue(); + dictionaryValue.setKey(key); + dictionaryValue.setLabel(label); + dictionaryValue.setColumns(mutableColumns); + + return dictionaryValue; + } +} \ No newline at end of file diff --git a/src/test/java/com/avispa/ecm/model/configuration/display/DisplayServiceTest.java b/src/test/java/com/avispa/ecm/model/configuration/display/DisplayServiceTest.java new file mode 100644 index 0000000..5c42923 --- /dev/null +++ b/src/test/java/com/avispa/ecm/model/configuration/display/DisplayServiceTest.java @@ -0,0 +1,58 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.display; + +import com.avispa.ecm.util.TestDocument; +import com.avispa.ecm.util.exception.EcmException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Rafał Hiszpański + */ +class DisplayServiceTest { + private static final DisplayService displayService = new DisplayService(); + + @Test + void whenGetNameOnPropertyWithDisplayAnnotation_thenNameIsReturned() { + assertEquals("Some test integer", displayService.getDisplayValueFromAnnotation(TestDocument.class, "testInt")); + } + + @Test + void whenGetNameOnPropertyWithoutDisplayAnnotation_thenPropertyNameIsReturned() { + assertEquals("testString", displayService.getDisplayValueFromAnnotation(TestDocument.class, "testString")); + } + + @Test + void whenGetNameOnNestedPropertyWithDisplayAnnotation_thenNameIsReturned() { + assertEquals("Nested field", displayService.getDisplayValueFromAnnotation(TestDocument.class, "nestedObject.nestedField")); + } + + @Test + void whenGetNameOnNonExistingProperty_thenExceptionIsThrown() { + assertThrows(EcmException.class, () -> displayService.getDisplayValueFromAnnotation(TestDocument.class, "nonExisting")); + } + + @Test + void whenGetNameOnNonExistingNestedProperty_thenExceptionIsThrown() { + assertThrows(EcmException.class, () -> displayService.getDisplayValueFromAnnotation(TestDocument.class, "nestedObject.nonExisting")); + } +} \ No newline at end of file diff --git a/src/test/java/com/avispa/ecm/model/configuration/load/mapper/ContextMapperTest.java b/src/test/java/com/avispa/ecm/model/configuration/load/mapper/ContextMapperTest.java new file mode 100644 index 0000000..d7eba7d --- /dev/null +++ b/src/test/java/com/avispa/ecm/model/configuration/load/mapper/ContextMapperTest.java @@ -0,0 +1,200 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.load.mapper; + +import com.avispa.ecm.model.configuration.EcmConfig; +import com.avispa.ecm.model.configuration.EcmConfigRepository; +import com.avispa.ecm.model.configuration.callable.autolink.Autolink; +import com.avispa.ecm.model.configuration.callable.autoname.Autoname; +import com.avispa.ecm.model.configuration.context.Context; +import com.avispa.ecm.model.configuration.load.dto.ContextDto; +import com.avispa.ecm.model.document.Document; +import com.avispa.ecm.model.type.Type; +import com.avispa.ecm.model.type.TypeService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +/** + * @author Rafał Hiszpański + */ +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {ContextMapperImpl.class}) +class ContextMapperTest { + + @Autowired + private ContextMapper mapper; + + @MockBean + private EcmConfigRepository ecmConfigRepository; + + @MockBean + private TypeService typeService; + + @Test + void givenDto_whenConvert_thenCorrectEntity() { + ContextDto contextDto = getSampleDto(); + + Type type = getType(); + when(typeService.getType("Document")).thenReturn(type); + + Autolink autolink = getAutolinkConfig(); + when(ecmConfigRepository.findByObjectName("Autolink")).thenReturn(Optional.of(autolink)); + + Autoname autoname = getAutonameConfig(); + when(ecmConfigRepository.findByObjectName("Autoname")).thenReturn(Optional.of(autoname)); + + Context convertedEntity = mapper.convertToEntity(contextDto); + + assertAll(() -> { + assertEquals("Context Dto", convertedEntity.getObjectName()); + assertEquals(type, convertedEntity.getType()); + assertEquals("{}", convertedEntity.getMatchRule()); + assertEquals(2, convertedEntity.getImportance()); + assertEquals(1, convertedEntity.getEcmConfigs().size()); + assertEquals(List.of(autolink), convertedEntity.getEcmConfigs()); + }); + } + + @Test + void givenDtoAndEntity_whenUpdate_thenEntityHasDtoProperties() { + Context context = getSampleEntity(); + ContextDto contextDto = getSampleDto(); + + Type type = getType(); + when(typeService.getType("Document")).thenReturn(type); + + Autolink autolink = getAutolinkConfig(); + when(ecmConfigRepository.findByObjectName("Autolink")).thenReturn(Optional.of(autolink)); + + mapper.updateEntityFromDto(contextDto, context); + + assertAll(() -> { + assertEquals("Context Dto", context.getObjectName()); + assertEquals(type, context.getType()); + assertEquals("{}", context.getMatchRule()); + assertEquals(2, context.getImportance()); + assertEquals(1, context.getEcmConfigs().size()); + assertEquals(List.of(autolink), context.getEcmConfigs()); + }); + } + + @Test + void givenDtoAndEmptyEntity_whenUpdate_thenEntityHasDtoProperties() { + Context context = new Context(); + ContextDto contextDto = getSampleDto(); + + Type type = getType(); + when(typeService.getType("Document")).thenReturn(type); + + Autolink autolink = getAutolinkConfig(); + when(ecmConfigRepository.findByObjectName("Autolink")).thenReturn(Optional.of(autolink)); + + mapper.updateEntityFromDto(contextDto, context); + + assertAll(() -> { + assertEquals("Context Dto", context.getObjectName()); + assertEquals(type, context.getType()); + assertEquals("{}", context.getMatchRule()); + assertEquals(2, context.getImportance()); + assertEquals(1, context.getEcmConfigs().size()); + assertEquals(List.of(autolink), context.getEcmConfigs()); + }); + } + + @Test + void givenNullDto_whenUpdate_thenDoNothing() { + Context context = getSampleEntity(); + mapper.updateEntityFromDto(null, context); + + Type type = getType(); + when(typeService.getType("Document")).thenReturn(type); + + assertAll(() -> { + assertEquals("Context entity", context.getObjectName()); + assertEquals(type, context.getType()); + assertEquals("{ \"objectName\": \"Test\"}", context.getMatchRule()); + assertEquals(1, context.getImportance()); + assertEquals(2, context.getEcmConfigs().size()); + }); + } + + private Context getSampleEntity() { + Context context = new Context(); + context.setObjectName("Context entity"); + context.setType(getType()); + context.setMatchRule("{ \"objectName\": \"Test\"}"); + context.setImportance(1); + + List configs = new ArrayList<>(); + configs.add(getAutonameConfig()); + configs.add(getAutolinkConfig()); + + context.setEcmConfigs(configs); + + return context; + } + + private ContextDto getSampleDto() { + ContextDto contextDto = new ContextDto(); + contextDto.setName("Context Dto"); + contextDto.setType("Document"); + contextDto.setImportance(2); + + List configNames = new ArrayList<>(); + configNames.add("Autolink"); + + contextDto.setConfigNames(configNames); + + return contextDto; + } + + private Autolink getAutolinkConfig() { + Autolink autolink = new Autolink(); + autolink.setObjectName("Autolink"); + + return autolink; + } + + private Autoname getAutonameConfig() { + Autoname autoname = new Autoname(); + autoname.setObjectName("Autoname"); + + return autoname; + } + + private Type getType() { + Type type = new Type(); + type.setObjectName("Document"); + type.setEntityClass(Document.class); + + return type; + } +} \ No newline at end of file diff --git a/src/test/java/com/avispa/ecm/model/configuration/load/mapper/UpsertMapperTest.java b/src/test/java/com/avispa/ecm/model/configuration/load/mapper/UpsertMapperTest.java new file mode 100644 index 0000000..85a5b9b --- /dev/null +++ b/src/test/java/com/avispa/ecm/model/configuration/load/mapper/UpsertMapperTest.java @@ -0,0 +1,136 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.load.mapper; + +import com.avispa.ecm.model.configuration.EcmConfigRepository; +import com.avispa.ecm.model.configuration.load.dto.UpsertDto; +import com.avispa.ecm.model.configuration.propertypage.PropertyPage; +import com.avispa.ecm.model.configuration.upsert.Upsert; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.when; + +/** + * @author Rafał Hiszpański + */ +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {UpsertMapperImpl.class}) +class UpsertMapperTest { + + @Autowired + private UpsertMapper mapper; + + @MockBean + private EcmConfigRepository propertyPageRepository; + + @Test + void givenDto_whenConvert_thenCorrectEntity() { + UpsertDto upsertDto = getSampleDto(); + + PropertyPage propertyPage = getPropertyPage("Property page for Dto"); + when(propertyPageRepository.findByObjectName("Property page for Dto")).thenReturn(Optional.of(propertyPage)); + + Upsert convertedEntity = mapper.convertToEntity(upsertDto); + + assertAll(() -> { + assertEquals("Upsert Dto", convertedEntity.getObjectName()); + assertNotNull(convertedEntity.getPropertyPage()); + assertEquals("Property page for Dto", convertedEntity.getPropertyPage().getObjectName()); + }); + } + + @Test + void givenDtoAndEntity_whenUpdate_thenEntityHasDtoProperties() { + Upsert upsert = getSampleEntity(); + UpsertDto upsertDto = getSampleDto(); + + PropertyPage propertyPage = getPropertyPage("Property page for Dto"); + when(propertyPageRepository.findByObjectName("Property page for Dto")).thenReturn(Optional.of(propertyPage)); + + mapper.updateEntityFromDto(upsertDto, upsert); + + assertAll(() -> { + assertEquals("Upsert Dto", upsert.getObjectName()); + assertNotNull(upsert.getPropertyPage()); + assertEquals("Property page for Dto", upsert.getPropertyPage().getObjectName()); + }); + } + + @Test + void givenDtoAndEmptyEntity_whenUpdate_thenEntityHasDtoProperties() { + Upsert upsert = new Upsert(); + UpsertDto upsertDto = getSampleDto(); + + PropertyPage propertyPage = getPropertyPage("Property page for Dto"); + when(propertyPageRepository.findByObjectName("Property page for Dto")).thenReturn(Optional.of(propertyPage)); + + mapper.updateEntityFromDto(upsertDto, upsert); + + assertAll(() -> { + assertEquals("Upsert Dto", upsert.getObjectName()); + assertNotNull(upsert.getPropertyPage()); + assertEquals("Property page for Dto", upsert.getPropertyPage().getObjectName()); + }); + } + + @Test + void givenNullDto_whenUpdate_thenDoNothing() { + Upsert upsert = getSampleEntity(); + mapper.updateEntityFromDto(null, upsert); + + assertAll(() -> { + assertEquals("Upsert entity", upsert.getObjectName()); + assertNotNull(upsert.getPropertyPage()); + assertEquals("Property page", upsert.getPropertyPage().getObjectName()); + }); + } + + private Upsert getSampleEntity() { + Upsert upsert = new Upsert(); + upsert.setObjectName("Upsert entity"); + upsert.setPropertyPage(getPropertyPage("Property page")); + + return upsert; + } + + private UpsertDto getSampleDto() { + UpsertDto upsertDto = new UpsertDto(); + upsertDto.setName("Upsert Dto"); + upsertDto.setPropertyPage("Property page for Dto"); + + return upsertDto; + } + + private PropertyPage getPropertyPage(String objectName) { + PropertyPage propertyPage = new PropertyPage(); + propertyPage.setObjectName(objectName); + + return propertyPage; + } +} \ No newline at end of file diff --git a/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/DictionaryControlLoaderTest.java b/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/DictionaryControlLoaderTest.java new file mode 100644 index 0000000..796b0d7 --- /dev/null +++ b/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/DictionaryControlLoaderTest.java @@ -0,0 +1,151 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.propertypage.content.mapper; + +import com.avispa.ecm.model.configuration.dictionary.Dictionary; +import com.avispa.ecm.model.configuration.dictionary.DictionaryNotFoundException; +import com.avispa.ecm.model.configuration.dictionary.DictionaryService; +import com.avispa.ecm.model.configuration.dictionary.DictionaryValue; +import com.avispa.ecm.model.configuration.propertypage.content.control.ComboRadio; +import com.avispa.ecm.model.type.Type; +import com.avispa.ecm.model.type.TypeService; +import com.avispa.ecm.util.TestDocument; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.context.annotation.Import; + +import java.util.Map; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Rafał Hiszpański + */ +@DataJpaTest +@Import({DictionaryControlLoader.class, DictionaryService.class, TypeService.class}) +class DictionaryControlLoaderTest { + @Autowired + private TestEntityManager entityManager; + + @Autowired + private DictionaryControlLoader controlLoader; + + @BeforeEach + void init() { + entityManager.persist(getType()); + } + + @AfterEach + void cleanup() { + entityManager.clear(); + } + + @Test + void givenControlWithTypeName_whenLoadDictionary_thenTypeObjectsAreLoaded() { + ComboRadio comboRadio = new ComboRadio(); + comboRadio.setProperty("testDate"); + comboRadio.setTypeName("Test document"); + + UUID id = persistTestDocument("Test document"); + persistTestDocument(""); // should be ignored in test + + controlLoader.loadDictionary(comboRadio, TestDocument.class); + + assertEquals(Map.of(id.toString(), "Test document"), comboRadio.getOptions()); + } + + @Test + void givenControlWithDictionary_whenLoadDictionary_thenDictionaryIsLoaded() { + ComboRadio comboRadio = new ComboRadio(); + comboRadio.setProperty("testInt"); + comboRadio.setDictionary("Test Dictionary"); + + persistTestDictionary(); + + controlLoader.loadDictionary(comboRadio, TestDocument.class); + + assertEquals(Map.of("Key 1", "Label 1"), comboRadio.getOptions()); + } + + @Test + void givenControl_whenLoadDictionary_thenDictionaryIsLoadedFromAnnotation() { + ComboRadio comboRadio = new ComboRadio(); + comboRadio.setProperty("testString"); + + persistTestDictionary(); + + controlLoader.loadDictionary(comboRadio, TestDocument.class); + + assertEquals(Map.of("Key 1", "Label 1"), comboRadio.getOptions()); + } + + @Test + void givenControl_whenLoadUnknownDictionary_thenThrowException() { + ComboRadio comboRadio = new ComboRadio(); + comboRadio.setProperty("testString"); + + assertThrows(DictionaryNotFoundException.class, () -> controlLoader.loadDictionary(comboRadio, TestDocument.class)); + } + + @Test + void givenControlWithoutAnyDictionaryDate_whenLoadDictionary_thenThrowException() { + ComboRadio comboRadio = new ComboRadio(); + comboRadio.setProperty("testInt"); + + assertThrows(DictionaryNotFoundException.class, () -> controlLoader.loadDictionary(comboRadio, TestDocument.class)); + } + + private Type getType() { + Type type = new Type(); + type.setObjectName("Test document"); + type.setEntityClass(TestDocument.class); + + return type; + } + + private UUID persistTestDocument(String documentName) { + TestDocument testDocument = new TestDocument(); + testDocument.setObjectName(documentName); + return entityManager.persist(testDocument).getId(); + } + + private void persistTestDictionary() { + Dictionary dictionary = new Dictionary(); + dictionary.setObjectName("Test Dictionary"); + + DictionaryValue dv1 = new DictionaryValue(); + dv1.setKey("Key 1"); + dv1.setLabel("Label 1"); + + DictionaryValue dv2 = new DictionaryValue(); // should be ignored + dv2.setKey("Key 2"); + dv2.setLabel(""); + + dictionary.addValue(dv1); + dictionary.addValue(dv2); + + entityManager.persist(dictionary); + } +} \ No newline at end of file diff --git a/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapperTest.java b/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapperIntegrationTest.java similarity index 95% rename from src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapperTest.java rename to src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapperIntegrationTest.java index 4ede609..14eca91 100644 --- a/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapperTest.java +++ b/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/PropertyPageMapperIntegrationTest.java @@ -20,6 +20,7 @@ import com.avispa.ecm.model.configuration.EcmConfigRepository; import com.avispa.ecm.model.configuration.dictionary.Dictionary; +import com.avispa.ecm.model.configuration.dictionary.DictionaryNotFoundException; import com.avispa.ecm.model.configuration.dictionary.DictionaryService; import com.avispa.ecm.model.configuration.dictionary.DictionaryValue; import com.avispa.ecm.model.configuration.display.DisplayService; @@ -77,8 +78,15 @@ @Slf4j @DataJpaTest @AutoConfigureJson -@Import({PropertyPageMapper.class, ExpressionResolver.class, DictionaryService.class, DisplayService.class}) -class PropertyPageMapperTest { +@Import({ + PropertyPageMapper.class, + ExpressionResolver.class, + DictionaryService.class, + DisplayService.class, + SimpleControlMapper.class, + TableMapper.class, + DictionaryControlLoader.class}) +class PropertyPageMapperIntegrationTest { private Document document; @MockBean @@ -97,7 +105,7 @@ void init() { // first dictionary { Dictionary testDict = new Dictionary(); - testDict.setObjectName("TestDict"); + testDict.setObjectName("Test Dictionary"); DictionaryValue dv1 = new DictionaryValue(); dv1.setKey("1"); @@ -115,13 +123,13 @@ void init() { testDict.addValue(dv2); testDict.addValue(dv3); - when(dictionaryRepository.findByObjectName("TestDict")).thenReturn(Optional.of(testDict)); + when(dictionaryRepository.findByObjectName("Test Dictionary")).thenReturn(Optional.of(testDict)); } // second dictionary { Dictionary testDict = new Dictionary(); - testDict.setObjectName("TestDict2"); + testDict.setObjectName("Test Dictionary 2"); DictionaryValue dv1 = new DictionaryValue(); dv1.setKey("a"); @@ -134,7 +142,7 @@ void init() { testDict.addValue(dv1); testDict.addValue(dv2); - when(dictionaryRepository.findByObjectName("TestDict2")).thenReturn(Optional.of(testDict)); + when(dictionaryRepository.findByObjectName("Test Dictionary 2")).thenReturn(Optional.of(testDict)); } Type type = new Type(); @@ -417,7 +425,7 @@ void dictionaryNotSpecified() { PropertyPage propertyPage = createPropertyPage("content/dictionaryNotSpecified.json"); // when - assertThrows(IllegalStateException.class, () -> propertyPageMapper.convertToContent(propertyPage, document, true)); + assertThrows(DictionaryNotFoundException.class, () -> propertyPageMapper.convertToContent(propertyPage, document, true)); } @Test diff --git a/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/SimpleControlMapperTest.java b/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/SimpleControlMapperTest.java new file mode 100644 index 0000000..89ad8c0 --- /dev/null +++ b/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/SimpleControlMapperTest.java @@ -0,0 +1,148 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.propertypage.content.mapper; + +import com.avispa.ecm.model.configuration.display.DisplayService; +import com.avispa.ecm.model.configuration.propertypage.content.control.ComboRadio; +import com.avispa.ecm.model.configuration.propertypage.content.control.Label; +import com.avispa.ecm.model.configuration.propertypage.content.control.Text; +import com.avispa.ecm.util.NestedObject; +import com.avispa.ecm.util.TestDocument; +import com.avispa.ecm.util.expression.ExpressionResolver; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Map; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * @author Rafał Hiszpański + */ +class SimpleControlMapperTest { + private static ExpressionResolver expressionResolver; + private static DictionaryControlLoader dictionaryControlLoader; + + private static SimpleControlMapper simpleControlMapper; + + @BeforeAll + static void init() { + expressionResolver = mock(ExpressionResolver.class); + dictionaryControlLoader = mock(DictionaryControlLoader.class); + simpleControlMapper = new SimpleControlMapper(dictionaryControlLoader, new ObjectMapper(), expressionResolver, new DisplayService()); + } + + @Test + @SneakyThrows + void givenLabelWithCorrectExpression_whenProcess_thenExpressionWasResolved() { + Label label = new Label(); + label.setExpression("$value('testString')"); + + TestDocument testDocument = new TestDocument(); + + simpleControlMapper.processControl(label, testDocument); + + verify(expressionResolver).resolve(testDocument, "$value('testString')"); + } + + @Test + void givenPropertyWithoutLabel_whenProcess_thenLabelTakenFromAnnotation() { + Text text = new Text(); + text.setProperty("testInt"); + + TestDocument testDocument = new TestDocument(); + testDocument.setObjectName("Test document"); + testDocument.setTestInt(12); + + simpleControlMapper.processControl(text, testDocument); + + assertEquals("Some test integer", text.getLabel()); + assertEquals("12", text.getValue()); + } + + @Test + void givenUnknownProperty_whenProcess_thenValueIsEmptyString() { + Text text = new Text(); + text.setLabel("Label"); + text.setProperty("nonExisting"); + + simpleControlMapper.processControl(text, new TestDocument()); + + assertEquals("", text.getValue()); + } + + @Test + void givenComboWithoutType_whenProcess_thenDictionaryLoadAttempt() { + ComboRadio comboRadio = new ComboRadio(); + comboRadio.setLabel("Label"); + comboRadio.setProperty("testString"); + + simpleControlMapper.processControl(comboRadio, new TestDocument()); + + verify(dictionaryControlLoader).loadDictionary(comboRadio, TestDocument.class); + } + + @Test + @SneakyThrows + void givenComboWithTypeExpression_whenProcess_thenTypeDeductionAttempt() { + ComboRadio comboRadio = new ComboRadio(); + comboRadio.setLabel("Label"); + comboRadio.setProperty("testString"); + comboRadio.setTypeNameExpression("{\"testString\": \"Test\"}"); + + TestDocument testDocument = new TestDocument(); + simpleControlMapper.processControl(comboRadio, testDocument); + + verify(expressionResolver).resolve(testDocument, "{\"testString\": \"Test\"}"); + } + + @Test + void givenControlWithObjectAsProperty_whenProcess_thenReturnMap() { + Text text = new Text(); + text.setProperty("nestedObject"); + + TestDocument testDocument = new TestDocument(); + + UUID id = UUID.randomUUID(); + NestedObject nestedObject = new NestedObject(); + nestedObject.setId(id); + nestedObject.setObjectName("Nested"); + + testDocument.setNestedObject(nestedObject); + + simpleControlMapper.processControl(text, testDocument); + + assertEquals(Map.of("objectName", "Nested", "id", id.toString()), text.getValue()); + } + + @Test + void givenControlWithNullObjectAsProperty_whenProcess_thenReturnMap() { + Text text = new Text(); + text.setProperty("nestedObject"); + + simpleControlMapper.processControl(text, new TestDocument()); + + assertEquals("", text.getValue()); + } +} \ No newline at end of file diff --git a/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/TableMapperTest.java b/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/TableMapperTest.java new file mode 100644 index 0000000..9a4a88f --- /dev/null +++ b/src/test/java/com/avispa/ecm/model/configuration/propertypage/content/mapper/TableMapperTest.java @@ -0,0 +1,153 @@ +/* + * Avispa ECM - a small framework for implementing basic ECM solution + * Copyright (C) 2023 Rafał Hiszpański + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.avispa.ecm.model.configuration.propertypage.content.mapper; + +import com.avispa.ecm.model.configuration.propertypage.content.control.ComboRadio; +import com.avispa.ecm.model.configuration.propertypage.content.control.PropertyControl; +import com.avispa.ecm.model.configuration.propertypage.content.control.Table; +import com.avispa.ecm.model.configuration.propertypage.content.control.Text; +import com.avispa.ecm.model.document.Document; +import com.avispa.ecm.util.TestDocument; +import com.avispa.ecm.util.exception.EcmException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * @author Rafał Hiszpański + */ +class TableMapperTest { + private static DictionaryControlLoader dictionaryControlLoader; + private static TableMapper tableMapper; + + @BeforeAll + static void init() { + dictionaryControlLoader = mock(DictionaryControlLoader.class); + tableMapper = new TableMapper(dictionaryControlLoader, new ObjectMapper()); + } + + @ParameterizedTest + @ValueSource(strings = {"nonExisting", "nonTable"}) + void givenTableForNonExistingProperty_whenProcessControl_thenExceptionIsThrown(String propertyName) { + Table table = new Table(); + table.setProperty(propertyName); + + TestDocument testDocument = new TestDocument(); + assertThrows(EcmException.class, () -> tableMapper.processControl(table, testDocument)); + } + + @Test + void givenComboPropertyInTable_whenProcessControl_thenDictionaryLoadAttempt() { + Table table = new Table(); + table.setProperty("table"); + + List controls = new ArrayList<>(); + ComboRadio comboRadio = new ComboRadio(); + comboRadio.setProperty("objectName"); + controls.add(comboRadio); + table.setControls(controls); + + TestDocument testDocument = new TestDocument(); + Document document = new Document(); + document.setObjectName("Table document"); + testDocument.setTable(List.of(document)); + + tableMapper.processControl(table, testDocument); + + verify(dictionaryControlLoader).loadDictionary(any(ComboRadio.class), eq(Document.class)); + } + + @Test + void givenDocumentWithNullList_whenProcessControl_thenTableSizeIsZero() { + Table table = new Table(); + table.setProperty("table"); + + List controls = new ArrayList<>(); + Text text = new Text(); + text.setProperty("objectName"); + controls.add(text); + table.setControls(controls); + + tableMapper.processControl(table, new TestDocument()); + + assertEquals(0, table.getSize()); + } + + @Test + void givenPropertyInTable_whenProcessControl_thenTableIsCorrectlyProcessed() { + Table table = new Table(); + table.setProperty("table"); + + List controls = new ArrayList<>(); + Text text = new Text(); + text.setProperty("objectName"); + controls.add(text); + table.setControls(controls); + + TestDocument testDocument = new TestDocument(); + Document document = new Document(); + document.setObjectName("Table document"); + testDocument.setTable(List.of(document)); + + tableMapper.processControl(table, testDocument); + + assertAll(() -> { + assertEquals(1, table.getSize()); + assertEquals(2, table.getControls().size()); + + PropertyControl control = table.getControls().get(0); + assertTrue(control.isRequired()); + assertEquals(List.of("Table document"), control.getValue()); + }); + } + + @Test + void givenNonExistingPropertyInTable_whenProcessControl_thenEmptyValueIsPopulated() { + Table table = new Table(); + table.setProperty("table"); + + List controls = new ArrayList<>(); + Text text = new Text(); + text.setProperty("nonExisting"); + controls.add(text); + table.setControls(controls); + + TestDocument testDocument = new TestDocument(); + testDocument.setTable(List.of(new Document())); + + tableMapper.processControl(table, testDocument); + + PropertyControl control = table.getControls().get(0); + assertEquals(List.of(""), control.getValue()); + } +} \ No newline at end of file diff --git a/src/test/java/com/avispa/ecm/util/NestedObject.java b/src/test/java/com/avispa/ecm/util/NestedObject.java index 992ec1d..eaf00df 100644 --- a/src/test/java/com/avispa/ecm/util/NestedObject.java +++ b/src/test/java/com/avispa/ecm/util/NestedObject.java @@ -20,6 +20,7 @@ import com.avispa.ecm.model.EcmObject; import com.avispa.ecm.model.configuration.dictionary.annotation.Dictionary; +import com.avispa.ecm.model.configuration.display.annotation.DisplayName; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -38,6 +39,7 @@ public NestedObject(String objectName, String nestedField) { this.setObjectName(objectName); this.nestedField = nestedField; } - @Dictionary(name = "TestDict") + @Dictionary(name = "Test Dictionary") + @DisplayName("Nested field") private String nestedField; } diff --git a/src/test/java/com/avispa/ecm/util/TestDocument.java b/src/test/java/com/avispa/ecm/util/TestDocument.java index 64e751f..edfd533 100644 --- a/src/test/java/com/avispa/ecm/util/TestDocument.java +++ b/src/test/java/com/avispa/ecm/util/TestDocument.java @@ -40,7 +40,7 @@ @Setter @Entity public class TestDocument extends Document { - @Dictionary(name = "TestDict") + @Dictionary(name = "Test Dictionary") private String testString; private LocalDateTime testDateTime; private LocalDate testDate; diff --git a/src/test/java/com/avispa/ecm/util/condition/ConditionParserTest.java b/src/test/java/com/avispa/ecm/util/condition/ConditionParserTest.java index aad29ab..f657364 100644 --- a/src/test/java/com/avispa/ecm/util/condition/ConditionParserTest.java +++ b/src/test/java/com/avispa/ecm/util/condition/ConditionParserTest.java @@ -25,9 +25,10 @@ import com.avispa.ecm.util.json.JsonValidator; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.json.JsonTest; -import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -56,8 +57,13 @@ void givenInvalidRule_whenConversion_thenThrowException() { conditionParser.parse("{\"testString\": {\"unknown\": \"TEST\"}}")); } - @Test - void givenSimpleEquals_whenConversion_thenEqualsIntermediateResult() { + @ParameterizedTest + @CsvSource({ + "testString,{\"testString\": \"TEST\"}", + "testString,{\"testString\": { \"$eq\": \"TEST\"}}", + "testString,{\"nestedObject.nestedField\": \"TEST\"}", + }) + void givenEquals_whenConversion_thenEqualsIntermediateResult() { Conditions conditions = new Conditions(); conditions.addElement(Condition.equal("testString", ConditionValue.text("TEST"))); @@ -75,15 +81,6 @@ void givenCombinedSimpleEquals_whenConversion_thenEqualsIntermediateResult() { conditionParser.parse("{\"testString\": \"TEST\", \"testInt\": 12}")); } - @Test - void givenStringEquals_whenConversion_thenEqualsIntermediateResult() { - Conditions conditions = new Conditions(); - conditions.addElement(Condition.equal("testString", ConditionValue.text("TEST"))); - - assertEquals(conditions, - conditionParser.parse("{\"testString\": { \"$eq\": \"TEST\"}}")); - } - @Test void givenBooleanEquals_whenConversion_thenEqualsIntermediateResult() { Conditions conditions = new Conditions(); @@ -197,13 +194,4 @@ void givenNestedGroups_whenConversion_thenEqualsIntermediateResult() { assertEquals(conditions, conditionParser.parse("{\"$or\": [{\"testString\": { \"$ne\": \"TEST2\"}}, {\"$and\": [{\"testInt\": { \"$gt\": 11}}, {\"testInt\": { \"$lt\": 15}}]}]}")); } - - @Test - void givenNestedProperty_whenConversion_thenEqualsIntermediateResult() { - Conditions conditions = new Conditions(); - conditions.addElement(Condition.equal("nestedObject.nestedField", ConditionValue.text("TEST"))); - - assertEquals(conditions, - conditionParser.parse("{\"nestedObject.nestedField\": \"TEST\"}")); - } } \ No newline at end of file diff --git a/src/test/java/com/avispa/ecm/util/json/JsonValidatorTest.java b/src/test/java/com/avispa/ecm/util/json/JsonValidatorTest.java index 976a3d9..a81c764 100644 --- a/src/test/java/com/avispa/ecm/util/json/JsonValidatorTest.java +++ b/src/test/java/com/avispa/ecm/util/json/JsonValidatorTest.java @@ -88,7 +88,7 @@ private boolean validate(String jsonFilePath) { } @Test - @Disabled + @Disabled("Not an actual test") void testWalker() throws Exception { var svc = new SchemaValidatorsConfig(); svc.addKeywordWalkListener("$ref", new JsonSchemaWalkListener() { @@ -132,6 +132,8 @@ private String fieldName(String schemaPath) { var schema = factory.getSchema(resourceSchema.getURI(), svc); schema.walk(null, false); System.out.println(schema.getSchemaNode().toPrettyString()); + + assertTrue(true); } } \ No newline at end of file diff --git a/src/test/resources/content/dictionaryFromProperty.json b/src/test/resources/content/dictionaryFromProperty.json index c952f3b..5eea8b6 100644 --- a/src/test/resources/content/dictionaryFromProperty.json +++ b/src/test/resources/content/dictionaryFromProperty.json @@ -5,7 +5,7 @@ "type": "combo", "label": "Combo test", "property": "testString", - "dictionary": "TestDict", + "dictionary": "Test Dictionary", "required": true } ] diff --git a/src/test/resources/content/dictionaryOverride.json b/src/test/resources/content/dictionaryOverride.json index 3a33e62..e0b6b47 100644 --- a/src/test/resources/content/dictionaryOverride.json +++ b/src/test/resources/content/dictionaryOverride.json @@ -5,7 +5,7 @@ "type": "combo", "label": "Combo test", "property": "testString", - "dictionary": "TestDict2", + "dictionary": "Test Dictionary 2", "required": true } ] diff --git a/src/test/resources/content/radio.json b/src/test/resources/content/radio.json index bb38a3a..e6a0723 100644 --- a/src/test/resources/content/radio.json +++ b/src/test/resources/content/radio.json @@ -5,7 +5,7 @@ "type": "radio", "label": "Radio test", "property": "testString", - "dictionary": "TestDict", + "dictionary": "Test Dictionary", "required": true } ]