Unverified Commit e80d124b authored by Stefan Brunecker's avatar Stefan Brunecker Committed by GitHub
Browse files

Merge pull request #13 from EmbeddedMontiArc/feature/add-missing-unit-tests

feature/add-missing-unit-tests
parents c6b9eabe db7a00a2
package de.monticore.lang.monticar.emam2wasm.cpp;
import static de.monticore.lang.monticar.contract.Precondition.requiresNotNull;
import de.monticore.symboltable.Symbol;
import org.springframework.stereotype.Component;
......@@ -10,7 +12,7 @@ public class CppMainNameProvider implements CppNameProvider {
@Override
public String getName(Symbol model) {
return model.getName();
return requiresNotNull(model).getName();
}
@Override
......
package de.monticore.lang.monticar.emam2wasm.wasm;
import static de.monticore.lang.monticar.contract.Precondition.requiresNotNull;
import java.nio.file.Path;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Component;
......@@ -11,7 +13,7 @@ public class WasmJsNameProvider implements WasmNameProvider {
@Override
public String getName(Path cppFile) {
return FilenameUtils.getBaseName(cppFile.toString());
return FilenameUtils.getBaseName(requiresNotNull(cppFile).toString());
}
@Override
......
......@@ -3,25 +3,49 @@ package de.monticore.lang.monticar.generator;
import static de.monticore.lang.monticar.contract.Precondition.requiresNotNull;
import static de.monticore.lang.monticar.contract.StringPrecondition.requiresNotBlank;
import com.google.common.annotations.VisibleForTesting;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.PortSymbol;
import de.monticore.lang.monticar.common2._ast.ASTCommonDimensionElement;
import de.monticore.lang.monticar.common2._ast.ASTCommonMatrixType;
import de.monticore.lang.monticar.ts.MCTypeSymbol;
import de.monticore.lang.monticar.ts.references.MCASTTypeSymbolReference;
import de.monticore.lang.monticar.ts.references.MCTypeReference;
import de.monticore.lang.monticar.types2._ast.ASTElementType;
import de.monticore.lang.monticar.types2._ast.ASTType;
import de.monticore.symboltable.Symbol;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.springframework.util.StringUtils;
/**
* Class for methods commonly used by generator classes.
*/
public class GeneratorUtil {
private static final String GETTER_PREFIX = "get";
private static final String SETTER_PREFIX = "set";
private static final String BOOLEAN_TYPE = "B";
private static final String NATURAL_NUMBER_TYPE = "N";
private static final String INTEGER_NUMBER_TYPE = "Z";
private static final String RATIONAL_NUMBER_TYPE = "Q";
private static final String COMPLEX_NUMBER_TYPE = "C";
/**
* Takes a collection of {@link PortSymbol}s and filters out ports that
* belong to an array except for one. The order of the ports in the supplied
* collection remains otherwise unchanged.<p>
* It is guaranteed that the first port of an array as returned by the
* collections iterator is put into the returned collection. All subsequent
* ports belonging to this array will be discarded.<p>
* Two ports are determined to belong to the same port array if their names
* match disregarding the trailing square brackets.
*
* @param ports a collection of ports
* @return collection that contains only one port for each port array and is
* otherwise unchanged from the supplied collection
*/
public static Collection<PortSymbol> filterMultipleArrayPorts(Collection<PortSymbol> ports) {
List<PortSymbol> filteredPorts = new ArrayList<>();
List<String> processedArrays = new ArrayList<>();
......@@ -38,23 +62,123 @@ public class GeneratorUtil {
return filteredPorts;
}
/**
* Returns the method name to be used when generating a setter method for the
* supplied port.
*
* @param port {@code PortSymbol}
* @return method name for the supplied port
*/
public static String getSetterMethodName(PortSymbol port) {
return getSetterMethodName(requiresNotNull(port).getNameWithoutArrayBracketPart());
}
/**
* Returns the method name to be used when generating a setter method for a
* {@link PortSymbol} with the supplied name.
*
* @param portName the name of a {@code PortSymbol}
* @return method name for the supplied port name
*/
public static String getSetterMethodName(String portName) {
return SETTER_PREFIX + StringUtils.capitalize(requiresNotBlank(portName));
}
/**
* Returns the method name to be used when generating a getter method for the
* supplied port.
*
* @param port {@code PortSymbol}
* @return method name for the supplied port
*/
public static String getGetterMethodName(PortSymbol port) {
return getGetterMethodName(requiresNotNull(port).getNameWithoutArrayBracketPart());
}
/**
* Returns the method name to be used when generating a getter method for a
* {@link PortSymbol} with the supplied name.
*
* @param portName the name of a {@code PortSymbol}
* @return method name for the supplied port name
*/
public static String getGetterMethodName(String portName) {
return GETTER_PREFIX + StringUtils.capitalize(requiresNotBlank(portName));
}
@VisibleForTesting
/**
* Returns the component name for the supplied {@code Symbol}. This name
* always starts with an capital letter.
*
* @param model {@code Symbol}
* @return component name for the supplied symbol
*/
public static String getComponentName(Symbol model) {
return StringUtils.capitalize(requiresNotNull(model).getName());
}
/**
* Tries to determine the supplied {@code PortSymbol}'s type. The type
* includes the number set, any defined range and corresponding units.
*
* @param port {@code PortSymbol}
* @return the port's type
* @throws RuntimeException if it failed to determine the port's type
*/
public static String getType(PortSymbol port) {
MCASTTypeSymbolReference typeReference = (MCASTTypeSymbolReference) port.getTypeReference();
ASTType astType = typeReference.getAstType();
if (astType instanceof ASTCommonMatrixType) {
return matrixType((ASTCommonMatrixType) astType);
} else if (astType instanceof ASTElementType) {
ASTElementType type = (ASTElementType) astType;
Optional<String> elementType = type.getTElementType();
return elementType.orElse(typeReference.getName());
} else {
throw new RuntimeException("Unexpected ASTType: " + astType);
}
}
private static String matrixType(ASTCommonMatrixType type) {
ASTElementType elementType = type.getElementType();
Optional<String> tElementTypeOpt = elementType.getTElementType();
if (tElementTypeOpt.isPresent()) {
return tElementTypeOpt.get();
} else {
if (elementType.isIsBoolean()) {
return BOOLEAN_TYPE;
} else if (elementType.isIsNatural()) {
return NATURAL_NUMBER_TYPE;
} else if (elementType.isIsWholeNumberNumber()) {
return INTEGER_NUMBER_TYPE;
} else if (elementType.isIsRational()) {
return RATIONAL_NUMBER_TYPE;
} else if (elementType.isIsComplex()) {
return COMPLEX_NUMBER_TYPE;
} else {
throw new RuntimeException("Unable to determine type from " + type);
}
}
}
/**
* Returns a string array representing the dimension of the supplied port.
* The entries in this array are strings of integer numbers. The dimension
* is a combination of the port's potential matrix dimension and array size.
* In case the supplied port is defined as an array of matrices, a string
* array with the array and matrix dimension is returned. The size of the
* port array will be in position 0 of the returned array.
* In case the supplied port is either defined as a matrix or belongs to an
* array, the respective dimension is returned.
* Otherwise, a string array of size 0 is returned.<p>
* A collection of all ports of the component that the supplied port belongs
* to is needed to determine a potential array size.
*
* @param ports all ports directly belonging to the component of the
* supplied port
* @param port PortSymbol to determine the dimension for
* @return dimension of the port or an empty array
*/
public static String[] getDimension(Collection<PortSymbol> ports, PortSymbol port) {
int arrayDimension = port.isPartOfPortArray() ?
getArrayDimension(ports, port.getNameWithoutArrayBracketPart()) : 0;
......
package de.monticore.lang.monticar.generator.html;
import static de.monticore.lang.monticar.generator.GeneratorUtil.filterMultipleArrayPorts;
import static de.monticore.lang.monticar.generator.GeneratorUtil.getComponentName;
import static de.monticore.lang.monticar.generator.GeneratorUtil.getDimension;
import static de.monticore.lang.monticar.generator.GeneratorUtil.getType;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.PortSymbol;
import de.monticore.lang.monticar.common2._ast.ASTCommonMatrixType;
import de.monticore.lang.monticar.freemarker.TemplateProcessor;
import de.monticore.lang.monticar.generator.GeneratorUtil;
import de.monticore.lang.monticar.ts.references.MCASTTypeSymbolReference;
import de.monticore.lang.monticar.types2._ast.ASTElementType;
import de.monticore.lang.monticar.types2._ast.ASTType;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.util.Arrays;
......@@ -18,10 +16,8 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.util.StringUtils;
/**
* This generator generates html files that can be used in combination with a
......@@ -63,7 +59,7 @@ public class HtmlGenerator {
List<Port> outports = produceOutports(model.getOutgoingPorts());
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("modelName", getModelName(model));
dataModel.put("model_name", getComponentName(model));
dataModel.put("model", wasmNamingFunction.apply(model));
dataModel.put("model_wrapper", wrapperNamingFunction.apply(model));
dataModel.put("inports", inports);
......@@ -84,23 +80,11 @@ public class HtmlGenerator {
Function<PortSymbol, String> methodNameFunction) {
return filterMultipleArrayPorts(ports).stream().map(
p -> port(p.getNameWithoutArrayBracketPart(), methodNameFunction.apply(p),
getType(ports, p))).collect(Collectors.toList());
getPortDefinition(ports, p))).collect(Collectors.toList());
}
private String getType(Collection<PortSymbol> ports, PortSymbol port) {
MCASTTypeSymbolReference typeReference = (MCASTTypeSymbolReference) port.getTypeReference();
ASTType astType = typeReference.getAstType();
Optional<String> elementType;
if (astType instanceof ASTCommonMatrixType) {
ASTCommonMatrixType type = (ASTCommonMatrixType) astType;
elementType = type.getElementType().getTElementType();
} else if (astType instanceof ASTElementType) {
ASTElementType type = (ASTElementType) astType;
elementType = type.getTElementType();
} else {
throw new RuntimeException("Unexpected ASTType: " + astType);
}
String type = elementType.orElse(typeReference.getName());
private String getPortDefinition(Collection<PortSymbol> ports, PortSymbol port) {
String type = getType(port);
String[] dimension = getDimension(ports, port);
String dim = dimension.length > 0 ?
......@@ -109,10 +93,6 @@ public class HtmlGenerator {
return type + dim;
}
private String getModelName(ExpandedComponentInstanceSymbol model) {
return StringUtils.capitalize(model.getName());
}
private Port port(String name, String wrapperFunction, String type) {
Port port = new Port();
port.setName(name);
......
......@@ -66,13 +66,13 @@
src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/4.0.1/math.min.js"></script>
<script type="text/javascript" src="${model_wrapper}.js"></script>
<script type="text/javascript" src="${model}.js"></script>
<title>${modelName}</title>
<title>${model_name}</title>
</head>
<body>
<div class="container">
<div class="model">
<div class="header">
<h2>${modelName}</h2>
<h2>${model_name}</h2>
</div>
<div class="ports">
<div class="inports">
......
package de.monticore.lang.monticar.emam2wasm.cpp;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import de.monticore.lang.monticar.contract.Precondition.PreconditionViolationException;
import de.monticore.symboltable.Symbol;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
class CppMainNameProviderTest {
private static final Symbol NULL_SYMBOL = null;
private static final String SOME_SYMBOL_NAME = "someSymbolName";
private static final String EXPECTED_SYMBOL_NAME = SOME_SYMBOL_NAME;
private static final Path EXPECTED_FILE_PATH = Paths.get("someSymbolName.cpp");
private CppMainNameProvider nameProvider;
private Symbol symbol;
@BeforeEach
void setUp() {
nameProvider = new CppMainNameProvider();
symbol = mock(Symbol.class);
when(symbol.getName()).thenReturn(SOME_SYMBOL_NAME);
}
@Nested
class GetName {
@Nested
class ShouldThrowPreconditionViolationException {
@Test
void whenSymbolIsNull() {
assertThatExceptionOfType(PreconditionViolationException.class)
.isThrownBy(() -> nameProvider.getName(NULL_SYMBOL));
}
}
@Nested
class ShouldReturnSymbolName {
@Test
void whenSymbolIsNotNull() {
assertThat(nameProvider.getName(symbol)).isEqualTo(EXPECTED_SYMBOL_NAME);
}
}
}
@Nested
class GetFilePath {
@Nested
class ShouldThrowPreconditionViolationException {
@Test
void whenSymbolIsNull() {
assertThatExceptionOfType(PreconditionViolationException.class)
.isThrownBy(() -> nameProvider.getName(NULL_SYMBOL));
}
}
@Nested
class ShouldReturnFilePath {
@Test
void whenOnlyFileName() {
assertThat(nameProvider.getFilePath(symbol)).isEqualTo(
CppMainNameProviderTest.EXPECTED_FILE_PATH);
}
}
}
}
\ No newline at end of file
package de.monticore.lang.monticar.emam2wasm;
package de.monticore.lang.monticar.emam2wasm.cpp;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
......@@ -7,9 +7,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import de.monticore.lang.monticar.contract.Precondition.PreconditionViolationException;
import de.monticore.lang.monticar.emam2wasm.cpp.CppCompiler;
import de.monticore.lang.monticar.emam2wasm.cpp.CppNameProvider;
import de.monticore.lang.monticar.emam2wasm.cpp.CppStep;
import de.monticore.symboltable.Symbol;
import java.nio.file.Path;
import java.nio.file.Paths;
......
package de.monticore.lang.monticar.emam2wasm;
package de.monticore.lang.monticar.emam2wasm.model;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
......@@ -7,7 +7,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarcmath._parser.EmbeddedMontiArcMathParser;
import de.monticore.lang.monticar.emam2wasm.model.EmamModelNameProvider;
import de.monticore.lang.monticar.util.TextFile;
import java.io.IOException;
import java.io.Reader;
......
package de.monticore.lang.monticar.emam2wasm;
package de.monticore.lang.monticar.emam2wasm.model;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
......@@ -7,8 +7,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import de.monticore.lang.monticar.contract.Precondition.PreconditionViolationException;
import de.monticore.lang.monticar.emam2wasm.model.ModelNameProvider;
import de.monticore.lang.monticar.emam2wasm.model.ModelStep;
import de.monticore.lang.monticar.junit.TemporaryDirectoryExtension;
import java.nio.file.Path;
import java.nio.file.Paths;
......
package de.monticore.lang.monticar.emam2wasm.wasm;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import de.monticore.lang.monticar.contract.Precondition.PreconditionViolationException;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
class WasmJsNameProviderTest {
private static final Path NULL_PATH = null;
private static final Path SOME_CPP_FILE_PATH = Paths.get("some_file.cpp");
private static final Path SOME_CPP_RELATIVE_PATH = Paths.get("some/directory/some_file.cpp");
private static final Path SOME_CPP_ABSOLUTE_PATH = Paths.get("some/directory/some_file.cpp")
.toAbsolutePath();
private static final String EXPECTED_NAME = "some_file";
private static final Path EXPECTED_FILE_PATH = Paths.get("some_file.js");
private WasmJsNameProvider nameProvider;
@BeforeEach
void setUp() {
nameProvider = new WasmJsNameProvider();
}
@Nested
class GetName {
@Nested
class ShouldThrowPreconditionViolationException {
@Test
void whenPathIsNull() {
assertThatExceptionOfType(PreconditionViolationException.class)
.isThrownBy(() -> nameProvider.getName(NULL_PATH));
}
}
@Nested
class ShouldReturnBaseName {
@Test
void whenOnlyFileName() {
assertThat(nameProvider.getName(SOME_CPP_FILE_PATH)).isEqualTo(EXPECTED_NAME);
}
@Test
void whenRelativePath() {
assertThat(nameProvider.getName(SOME_CPP_RELATIVE_PATH)).isEqualTo(EXPECTED_NAME);
}
@Test
void whenAbsolutePath() {
assertThat(nameProvider.getName(SOME_CPP_ABSOLUTE_PATH)).isEqualTo(EXPECTED_NAME);
}
}
}
@Nested
class GetFilePath {
@Nested
class ShouldThrowPreconditionViolationException {
@Test
void whenPathIsNull() {
assertThatExceptionOfType(PreconditionViolationException.class)
.isThrownBy(() -> nameProvider.getName(NULL_PATH));
}
}
@Nested
class ShouldReturnFilePath {
@Test
void whenOnlyFileName() {
assertThat(nameProvider.getFilePath(SOME_CPP_FILE_PATH)).isEqualTo(EXPECTED_FILE_PATH);
}
@Test
void whenRelativePath() {
assertThat(nameProvider.getFilePath(SOME_CPP_RELATIVE_PATH)).isEqualTo(EXPECTED_FILE_PATH);
}
@Test
void whenAbsolutePath() {
assertThat(nameProvider.getFilePath(SOME_CPP_ABSOLUTE_PATH)).isEqualTo(EXPECTED_FILE_PATH);
}
}
}
}
\ No newline at end of file
package de.monticore.lang.monticar.generator;
import static de.monticore.lang.monticar.generator.GeneratorUtil.filterMultipleArrayPorts;
import static de.monticore.lang.monticar.generator.GeneratorUtil.getComponentName;
import static de.monticore.lang.monticar.generator.GeneratorUtil.getDimension;
import static de.monticore.lang.monticar.generator.GeneratorUtil.getGetterMethodName;
import static de.monticore.lang.monticar.generator.GeneratorUtil.getSetterMethodName;
import static de.monticore.lang.monticar.generator.GeneratorUtil.getType;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock;
......@@ -14,6 +16,7 @@ import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.PortSymb
import de.monticore.lang.monticar.contract.Precondition.PreconditionViolationException;
import de.monticore.lang.monticar.resolver.Resolver;
import de.monticore.lang.monticar.resolver.ResolverFactory;
import de.monticore.symboltable.Symbol;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
......@@ -21,7 +24,10 @@ import java.util.stream.Collectors;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
@SuppressWarnings("ConstantConditions")
class GeneratorUtilTest {
private static final Path RESOLVING_BASE_DIR = Paths.get("src/test/resources/generatorutil");
......@@ -49,6 +55,14 @@ class GeneratorUtilTest {
private static final String COLUMN_VECTOR = "ColumnVector";
private static final String MATRIX = "Matrix";
private static final String MATRIX_ARRAY = "MatrixArray[2]";
private static final Symbol NULL_SYMBOL = null;
private static final String ALL_LOWERCASE_NAME = "somename";
private static final String EXPECTED_ALL_LOWERCASE_COMPONENT_NAME = "Somename";
private static final String EXPECTED_FIRST_UPPERCASE_COMPONENT_NAME = "Somename";
private static final String EXPECTED_ALL_UPPERCASE_COMPONENT_NAME = "SOMENAME";
private static final String FIRST_UPPERCASE_NAME = "Somename";
private static final String ALL_UPPERCASE_NAME = "SOMENAME";
private static final String TYPES_MODEL = "models.types";