diff --git a/src/main/java/io/github/utplsql/api/CustomTypes.java b/src/main/java/io/github/utplsql/api/CustomTypes.java index 6dc6856..0dd7d1e 100644 --- a/src/main/java/io/github/utplsql/api/CustomTypes.java +++ b/src/main/java/io/github/utplsql/api/CustomTypes.java @@ -5,7 +5,10 @@ */ public final class CustomTypes { - // Object names must be upper case. + /* Object names must be upper case. */ + + public static final String UT_VARCHAR2_LIST = "UT_VARCHAR2_LIST"; + public static final String UT_REPORTERS = "UT_REPORTERS"; public static final String UT_DOCUMENTATION_REPORTER = "UT_DOCUMENTATION_REPORTER"; public static final String UT_COVERAGE_HTML_REPORTER = "UT_COVERAGE_HTML_REPORTER"; @@ -14,7 +17,12 @@ public final class CustomTypes { public static final String UT_COVERALLS_REPORTER = "UT_COVERALLS_REPORTER"; public static final String UT_COVERAGE_SONAR_REPORTER = "UT_COVERAGE_SONAR_REPORTER"; public static final String UT_SONAR_TEST_REPORTER = "UT_SONAR_TEST_REPORTER"; - public static final String UT_VARCHAR2_LIST = "UT_VARCHAR2_LIST"; + + public static final String UT_FILE_MAPPING = "UT_FILE_MAPPING"; + public static final String UT_FILE_MAPPINGS = "UT_FILE_MAPPINGS"; + + public static final String UT_KEY_VALUE_PAIR = "UT_KEY_VALUE_PAIR"; + public static final String UT_KEY_VALUE_PAIRS = "UT_KEY_VALUE_PAIRS"; private CustomTypes() {} diff --git a/src/main/java/io/github/utplsql/api/FileMapper.java b/src/main/java/io/github/utplsql/api/FileMapper.java new file mode 100644 index 0000000..d5c1c16 --- /dev/null +++ b/src/main/java/io/github/utplsql/api/FileMapper.java @@ -0,0 +1,72 @@ +package io.github.utplsql.api; + + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.OracleTypes; + +import java.sql.Array; +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public final class FileMapper { + + private FileMapper() {} + + /** + * Call the database api to build the custom file mappings. + */ + public static Array buildFileMappingArray( + Connection conn, List filePaths, FileMapperOptions mapperOptions) throws SQLException { + OracleConnection oraConn = conn.unwrap(OracleConnection.class); + + Map typeMap = conn.getTypeMap(); + typeMap.put(CustomTypes.UT_FILE_MAPPING, FileMapping.class); + typeMap.put(CustomTypes.UT_KEY_VALUE_PAIR, KeyValuePair.class); + conn.setTypeMap(typeMap); + + CallableStatement callableStatement = conn.prepareCall( + "BEGIN " + + "? := ut_file_mapper.build_file_mappings(" + + "a_object_owner => ?, " + + "a_file_paths => ?, " + + "a_file_to_object_type_mapping => ?, " + + "a_regex_pattern => ?, " + + "a_object_owner_subexpression => ?, " + + "a_object_name_subexpression => ?, " + + "a_object_type_subexpression => ?); " + + "END;"); + + int paramIdx = 0; + callableStatement.registerOutParameter(++paramIdx, OracleTypes.ARRAY, CustomTypes.UT_FILE_MAPPINGS); + + callableStatement.setString(++paramIdx, mapperOptions.getObjectOwner()); + callableStatement.setArray( + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_VARCHAR2_LIST, filePaths.toArray())); + callableStatement.setArray( + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_KEY_VALUE_PAIRS, mapperOptions.getTypeMappings().toArray())); + callableStatement.setString(++paramIdx, mapperOptions.getRegexPattern()); + callableStatement.setInt(++paramIdx, mapperOptions.getOwnerSubExpression()); + callableStatement.setInt(++paramIdx, mapperOptions.getNameSubExpression()); + callableStatement.setInt(++paramIdx, mapperOptions.getTypeSubExpression()); + + callableStatement.execute(); + return callableStatement.getArray(1); + } + + public static List buildFileMappingList( + Connection conn, List filePaths, FileMapperOptions mapperOptions) throws SQLException { + java.sql.Array fileMappings = buildFileMappingArray(conn, filePaths, mapperOptions); + + List mappingList = new ArrayList<>(); + for (Object obj : (Object[]) fileMappings.getArray()) { + mappingList.add((FileMapping) obj); + } + + return mappingList; + } + +} diff --git a/src/main/java/io/github/utplsql/api/FileMapperOptions.java b/src/main/java/io/github/utplsql/api/FileMapperOptions.java new file mode 100644 index 0000000..cee3ecf --- /dev/null +++ b/src/main/java/io/github/utplsql/api/FileMapperOptions.java @@ -0,0 +1,67 @@ +package io.github.utplsql.api; + +import java.util.ArrayList; +import java.util.List; + +public class FileMapperOptions { + + private String objectOwner; + private List typeMappings; + private String regexPattern; + private int ownerSubExpression; + private int typeSubExpression; + private int nameSubExpression; + + public FileMapperOptions() { + this.typeMappings = new ArrayList<>(); + } + + public String getObjectOwner() { + return objectOwner; + } + + public void setObjectOwner(String owner) { + this.objectOwner = owner; + } + + public List getTypeMappings() { + return typeMappings; + } + + public void setTypeMappings(List typeMappings) { + this.typeMappings = typeMappings; + } + + public String getRegexPattern() { + return regexPattern; + } + + public void setRegexPattern(String regexPattern) { + this.regexPattern = regexPattern; + } + + public int getOwnerSubExpression() { + return ownerSubExpression; + } + + public void setOwnerSubExpression(int ownerSubExpression) { + this.ownerSubExpression = ownerSubExpression; + } + + public int getTypeSubExpression() { + return typeSubExpression; + } + + public void setTypeSubExpression(int typeSubExpression) { + this.typeSubExpression = typeSubExpression; + } + + public int getNameSubExpression() { + return nameSubExpression; + } + + public void setNameSubExpression(int nameSubExpression) { + this.nameSubExpression = nameSubExpression; + } + +} diff --git a/src/main/java/io/github/utplsql/api/FileMapping.java b/src/main/java/io/github/utplsql/api/FileMapping.java new file mode 100644 index 0000000..9586a18 --- /dev/null +++ b/src/main/java/io/github/utplsql/api/FileMapping.java @@ -0,0 +1,78 @@ +package io.github.utplsql.api; + +import java.sql.SQLData; +import java.sql.SQLException; +import java.sql.SQLInput; +import java.sql.SQLOutput; + +/** + * Created by Vinicius on 17/07/2017. + */ +public class FileMapping implements SQLData { + + private String fileName; + private String objectOwner; + private String objectName; + private String objectType; + + public FileMapping() {} + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getObjectOwner() { + return objectOwner; + } + + public void setObjectOwner(String objectOwner) { + this.objectOwner = objectOwner; + } + + public String getObjectName() { + return objectName; + } + + public void setObjectName(String objectName) { + this.objectName = objectName; + } + + public String getObjectType() { + return objectType; + } + + public void setObjectType(String objectType) { + this.objectType = objectType; + } + + @Override + public String getSQLTypeName() throws SQLException { + return CustomTypes.UT_FILE_MAPPING; + } + + @Override + public void readSQL(SQLInput stream, String typeName) throws SQLException { + setFileName(stream.readString()); + setObjectOwner(stream.readString()); + setObjectName(stream.readString()); + setObjectType(stream.readString()); + } + + @Override + public void writeSQL(SQLOutput stream) throws SQLException { + stream.writeString(getFileName()); + stream.writeString(getObjectOwner()); + stream.writeString(getObjectName()); + stream.writeString(getObjectType()); + } + + @Override + public String toString() { + return String.format("%s/%s.%s", getObjectType(), getObjectOwner(), getObjectName()); + } + +} diff --git a/src/main/java/io/github/utplsql/api/KeyValuePair.java b/src/main/java/io/github/utplsql/api/KeyValuePair.java new file mode 100644 index 0000000..991bc2a --- /dev/null +++ b/src/main/java/io/github/utplsql/api/KeyValuePair.java @@ -0,0 +1,59 @@ +package io.github.utplsql.api; + +import java.sql.SQLData; +import java.sql.SQLException; +import java.sql.SQLInput; +import java.sql.SQLOutput; + +/** + * Created by Vinicius on 22/07/2017. + */ +public class KeyValuePair implements SQLData { + + private String key; + private String value; + + public KeyValuePair(String key, String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public String getSQLTypeName() throws SQLException { + return CustomTypes.UT_KEY_VALUE_PAIR; + } + + @Override + public void readSQL(SQLInput stream, String typeName) throws SQLException { + setKey(stream.readString()); + setValue(stream.readString()); + } + + @Override + public void writeSQL(SQLOutput stream) throws SQLException { + stream.writeString(getKey()); + stream.writeString(getValue()); + } + + @Override + public String toString() { + return String.format("%s => %s", getKey(), getValue()); + } + +} diff --git a/src/main/java/io/github/utplsql/api/TestRunner.java b/src/main/java/io/github/utplsql/api/TestRunner.java index d980cf1..7183a77 100644 --- a/src/main/java/io/github/utplsql/api/TestRunner.java +++ b/src/main/java/io/github/utplsql/api/TestRunner.java @@ -5,7 +5,10 @@ import io.github.utplsql.api.reporter.Reporter; import oracle.jdbc.OracleConnection; -import java.sql.*; +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Types; import java.util.ArrayList; import java.util.List; @@ -22,6 +25,8 @@ public class TestRunner { private List testFiles = new ArrayList<>(); private List includeObjects = new ArrayList<>(); private List excludeObjects = new ArrayList<>(); + private FileMapperOptions sourceMappingOptions; + private FileMapperOptions testMappingOptions; private boolean failOnErrors = false; public TestRunner addPath(String path) { @@ -74,6 +79,16 @@ public TestRunner excludeObject(String obj) { return this; } + public TestRunner sourceMappingOptions(FileMapperOptions mapperOptions) { + this.sourceMappingOptions = mapperOptions; + return this; + } + + public TestRunner testMappingOptions(FileMapperOptions mapperOptions) { + this.testMappingOptions = mapperOptions; + return this; + } + public TestRunner failOnErrors(boolean failOnErrors) { this.failOnErrors = failOnErrors; return this; @@ -95,64 +110,94 @@ public void run(Connection conn) throws SomeTestsFailedException, SQLException { String colorConsoleStr = Boolean.toString(this.colorConsole); String failOnErrors = Boolean.toString(this.failOnErrors); + String sourceFilesParam = "a_source_files"; + String testFilesParam = "a_test_files"; + + if (this.sourceMappingOptions != null || this.testMappingOptions != null) { + sourceFilesParam = "a_source_file_mappings"; + testFilesParam = "a_test_file_mappings"; + } + OracleConnection oraConn = conn.unwrap(OracleConnection.class); CallableStatement callableStatement = null; try { callableStatement = conn.prepareCall( "BEGIN " + - "ut_runner.run(" + - "a_paths => ?, " + - "a_reporters => ?, " + - "a_color_console => " + colorConsoleStr + ", " + - "a_coverage_schemes => ?, " + - "a_source_files => ?, " + - "a_test_files => ?, " + - "a_include_objects => ?, " + - "a_exclude_objects => ?, " + - "a_fail_on_errors => " + failOnErrors + "); " + - "END;"); + "ut_runner.run(" + + "a_paths => ?, " + + "a_reporters => ?, " + + "a_color_console => " + colorConsoleStr + ", " + + "a_coverage_schemes => ?, " + + sourceFilesParam + " => ?, " + + testFilesParam + " => ?, " + + "a_include_objects => ?, " + + "a_exclude_objects => ?, " + + "a_fail_on_errors => " + failOnErrors + "); " + + "END;"); int paramIdx = 0; callableStatement.setArray( - ++paramIdx, oraConn.createARRAY(CustomTypes.UT_VARCHAR2_LIST, this.pathList.toArray())); + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_VARCHAR2_LIST, this.pathList.toArray())); callableStatement.setArray( - ++paramIdx, oraConn.createARRAY(CustomTypes.UT_REPORTERS, this.reporterList.toArray())); + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_REPORTERS, this.reporterList.toArray())); if (this.coverageSchemes.isEmpty()) { callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_VARCHAR2_LIST); } else { callableStatement.setArray( - ++paramIdx, oraConn.createARRAY(CustomTypes.UT_VARCHAR2_LIST, this.coverageSchemes.toArray())); - } - - if (this.sourceFiles.isEmpty()) { - callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_VARCHAR2_LIST); - } else { - callableStatement.setArray( - ++paramIdx, oraConn.createARRAY(CustomTypes.UT_VARCHAR2_LIST, this.sourceFiles.toArray())); + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_VARCHAR2_LIST, this.coverageSchemes.toArray())); } - if (this.testFiles.isEmpty()) { - callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_VARCHAR2_LIST); + if (this.sourceMappingOptions != null || this.testMappingOptions != null) { + if (this.sourceMappingOptions != null) { + List sourceMappings = FileMapper.buildFileMappingList( + conn, this.sourceFiles, this.sourceMappingOptions); + + callableStatement.setArray( + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_FILE_MAPPINGS, sourceMappings.toArray())); + } else { + callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_FILE_MAPPINGS); + } + + if (this.testMappingOptions != null) { + List sourceMappings = FileMapper.buildFileMappingList( + conn, this.testFiles, this.testMappingOptions); + + callableStatement.setArray( + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_FILE_MAPPINGS, sourceMappings.toArray())); + } else { + callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_FILE_MAPPINGS); + } } else { - callableStatement.setArray( - ++paramIdx, oraConn.createARRAY(CustomTypes.UT_VARCHAR2_LIST, this.testFiles.toArray())); + if (this.sourceFiles.isEmpty()) { + callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_VARCHAR2_LIST); + } else { + callableStatement.setArray( + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_VARCHAR2_LIST, this.sourceFiles.toArray())); + } + + if (this.testFiles.isEmpty()) { + callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_VARCHAR2_LIST); + } else { + callableStatement.setArray( + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_VARCHAR2_LIST, this.testFiles.toArray())); + } } if (this.includeObjects.isEmpty()) { callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_VARCHAR2_LIST); } else { callableStatement.setArray( - ++paramIdx, oraConn.createARRAY(CustomTypes.UT_VARCHAR2_LIST, this.includeObjects.toArray())); + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_VARCHAR2_LIST, this.includeObjects.toArray())); } if (this.excludeObjects.isEmpty()) { callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_VARCHAR2_LIST); } else { callableStatement.setArray( - ++paramIdx, oraConn.createARRAY(CustomTypes.UT_VARCHAR2_LIST, this.excludeObjects.toArray())); + ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_VARCHAR2_LIST, this.excludeObjects.toArray())); } callableStatement.execute(); diff --git a/src/test/java/io/github/utplsql/api/FileMapperTest.java b/src/test/java/io/github/utplsql/api/FileMapperTest.java new file mode 100644 index 0000000..d96631e --- /dev/null +++ b/src/test/java/io/github/utplsql/api/FileMapperTest.java @@ -0,0 +1,50 @@ +package io.github.utplsql.api; + +import io.github.utplsql.api.rules.DatabaseRule; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class FileMapperTest { + + @Rule + public final DatabaseRule db = new DatabaseRule(); + + @Test + public void testFileMapper() throws SQLException { + List typeMappings = new ArrayList<>(); + typeMappings.add(new KeyValuePair("procedures", "PROCEDURE")); + typeMappings.add(new KeyValuePair("functions", "FUNCTION")); + + List filePaths = java.util.Arrays.asList( + "sources/app/procedures/award_bonus.sql", + "sources/app/functions/betwnstr.sql"); + + FileMapperOptions mapperOptions = new FileMapperOptions(); + mapperOptions.setObjectOwner("APP"); + mapperOptions.setTypeMappings(typeMappings); + mapperOptions.setRegexPattern("\\w+[\\\\\\/](\\w+)[\\\\\\/](\\w+)[\\\\\\/](\\w+)[.](\\w{3})"); + mapperOptions.setOwnerSubExpression(1); + mapperOptions.setTypeSubExpression(2); + mapperOptions.setNameSubExpression(3); + + List fileMappings = FileMapper.buildFileMappingList(db.newConnection(), filePaths, mapperOptions); + + if (fileMappings.size() != 2) + Assert.fail("Wrong mapping list size."); + + assertMapping(fileMappings.get(0), "APP", "AWARD_BONUS", "PROCEDURE"); + assertMapping(fileMappings.get(1), "APP", "BETWNSTR", "FUNCTION"); + } + + private void assertMapping(FileMapping fileMapping, String owner, String name, String type) { + Assert.assertEquals(owner, fileMapping.getObjectOwner()); + Assert.assertEquals(name, fileMapping.getObjectName()); + Assert.assertEquals(type, fileMapping.getObjectType()); + } + +}