getReporterOptionsList() {
+ return getRunAction().getReporterOptionsList();
+ }
+
+ @Override
+ public void initLogger() {
+ getRunAction().init();
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/RunTestRunnerTask.java b/src/main/java/org/utplsql/cli/RunTestRunnerTask.java
new file mode 100644
index 0000000..fc72c3d
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/RunTestRunnerTask.java
@@ -0,0 +1,71 @@
+package org.utplsql.cli;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.utplsql.api.DBHelper;
+import org.utplsql.api.TestRunner;
+import org.utplsql.api.exception.OracleCreateStatmenetStuckException;
+import org.utplsql.api.exception.SomeTestsFailedException;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+
+/**
+ * Runs the utPLSQL Test-Runner
+ *
+ * Takes care of its connection.
+ * In case of an OracleCreateStatementStuckException it will abort the connection, otherwise close it.
+ *
+ * @author pesse
+ */
+public class RunTestRunnerTask implements Callable {
+
+ private static final Logger logger = LoggerFactory.getLogger(RunTestRunnerTask.class);
+ private DataSource dataSource;
+ private TestRunner testRunner;
+ private boolean enableDmbsOutput;
+
+ RunTestRunnerTask(DataSource dataSource, TestRunner testRunner, boolean enableDmbsOutput) {
+ this.dataSource = dataSource;
+ this.testRunner = testRunner;
+ this.enableDmbsOutput = enableDmbsOutput;
+ }
+
+ @Override
+ public Boolean call() throws Exception {
+ Connection conn = null;
+ try {
+ conn = dataSource.getConnection();
+ if (enableDmbsOutput) DBHelper.enableDBMSOutput(conn);
+ logger.info("Running tests now.");
+ logger.info("--------------------------------------");
+ testRunner.run(conn);
+ } catch (SomeTestsFailedException e) {
+ throw e;
+ } catch (OracleCreateStatmenetStuckException e) {
+ try {
+ conn.abort(Executors.newSingleThreadExecutor());
+ conn = null;
+ } catch (SQLException e1) {
+ logger.error(e1.getMessage(), e1);
+ }
+ throw e;
+ } catch (SQLException e) {
+ System.out.println(e.getMessage());
+ throw e;
+ } finally {
+ if (conn != null) {
+ try {
+ if (enableDmbsOutput) DBHelper.disableDBMSOutput(conn);
+ conn.close();
+ } catch (SQLException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/UtplsqlPicocliCommand.java b/src/main/java/org/utplsql/cli/UtplsqlPicocliCommand.java
new file mode 100644
index 0000000..ca1b647
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/UtplsqlPicocliCommand.java
@@ -0,0 +1,21 @@
+package org.utplsql.cli;
+
+import picocli.CommandLine;
+
+@CommandLine.Command(
+ name = "utplsql",
+ description = "utPLSQL cli",
+ subcommands = {
+ RunPicocliCommand.class,
+ VersionInfoCommand.class,
+ ReportersCommand.class,
+ CommandLine.HelpCommand.class
+ })
+public class UtplsqlPicocliCommand {
+
+ public static final String COMMANDLINE_PARAM_DESCRIPTION = "/@//[:]/ OR /@ OR /@::";
+
+ @CommandLine.Option(names = "-h", usageHelp = true, description = "display this help and exit")
+ boolean help;
+
+}
diff --git a/src/main/java/org/utplsql/cli/VersionInfoCommand.java b/src/main/java/org/utplsql/cli/VersionInfoCommand.java
new file mode 100644
index 0000000..821d0ba
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/VersionInfoCommand.java
@@ -0,0 +1,54 @@
+package org.utplsql.cli;
+
+
+import org.utplsql.api.JavaApiVersionInfo;
+import org.utplsql.api.Version;
+import org.utplsql.api.db.DefaultDatabaseInformation;
+import org.utplsql.api.exception.UtPLSQLNotInstalledException;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.Parameters;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+@Command(name = "info", description = "prints version information of cli, java-api and - if connection is given - database utPLSQL framework")
+public class VersionInfoCommand implements ICommand {
+
+ @Parameters(description = UtplsqlPicocliCommand.COMMANDLINE_PARAM_DESCRIPTION, arity = "0..1")
+ private String connectionString;
+
+ @Option(names = "-h", usageHelp = true, description = "display this help and exit")
+ boolean help;
+
+ public int run() {
+ LoggerConfiguration.configure(LoggerConfiguration.ConfigLevel.NONE);
+
+ System.out.println(CliVersionInfo.getInfo());
+ System.out.println(JavaApiVersionInfo.getInfo());
+
+ try {
+ writeUtPlsqlVersion(connectionString);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return 1;
+ }
+
+ return 0;
+ }
+
+ private void writeUtPlsqlVersion(String connectString) throws SQLException {
+ if (connectString != null) {
+
+ DataSource dataSource = DataSourceProvider.getDataSource(connectString, 1);
+
+ try (Connection con = dataSource.getConnection()) {
+ Version v = new DefaultDatabaseInformation().getUtPlsqlFrameworkVersion(con);
+ System.out.println("utPLSQL " + v.getNormalizedString());
+ } catch (UtPLSQLNotInstalledException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/config/ConnectionConfig.java b/src/main/java/org/utplsql/cli/config/ConnectionConfig.java
new file mode 100644
index 0000000..ef0231e
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/config/ConnectionConfig.java
@@ -0,0 +1,18 @@
+package org.utplsql.cli.config;
+
+import java.beans.ConstructorProperties;
+
+public class ConnectionConfig {
+
+ private final String connectString;
+
+ @ConstructorProperties({"connectString"})
+ public ConnectionConfig(String connectString) {
+ this.connectString = connectString;
+ }
+
+ public String getConnectString() {
+ return connectString;
+ }
+
+}
diff --git a/src/main/java/org/utplsql/cli/config/FileMapperConfig.java b/src/main/java/org/utplsql/cli/config/FileMapperConfig.java
new file mode 100644
index 0000000..f5d4db2
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/config/FileMapperConfig.java
@@ -0,0 +1,54 @@
+package org.utplsql.cli.config;
+
+import java.beans.ConstructorProperties;
+import java.util.Map;
+
+public class FileMapperConfig {
+
+ private final String path;
+ private final String owner;
+ private final String regexExpression;
+ private final Map typeMapping;
+ private final Integer ownerSubexpression;
+ private final Integer nameSubexpression;
+ private final Integer typeSubexpression;
+
+ @ConstructorProperties({"path", "owner", "regexExpression", "typeMapping", "ownerSubexpression", "nameSubexpression", "typeSubexpression"})
+ public FileMapperConfig(String path, String owner, String regexExpression, Map typeMapping, Integer ownerSubexpression, Integer nameSubexpression, Integer typeSubexpression) {
+ this.path = path;
+ this.owner = owner;
+ this.regexExpression = regexExpression;
+ this.typeMapping = typeMapping;
+ this.ownerSubexpression = ownerSubexpression;
+ this.nameSubexpression = nameSubexpression;
+ this.typeSubexpression = typeSubexpression;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public String getRegexExpression() {
+ return regexExpression;
+ }
+
+ public Map getTypeMapping() {
+ return typeMapping;
+ }
+
+ public Integer getOwnerSubexpression() {
+ return ownerSubexpression;
+ }
+
+ public Integer getNameSubexpression() {
+ return nameSubexpression;
+ }
+
+ public Integer getTypeSubexpression() {
+ return typeSubexpression;
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/config/ReporterConfig.java b/src/main/java/org/utplsql/cli/config/ReporterConfig.java
new file mode 100644
index 0000000..e3e74ba
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/config/ReporterConfig.java
@@ -0,0 +1,35 @@
+package org.utplsql.cli.config;
+
+import org.utplsql.api.reporter.CoreReporters;
+
+import java.beans.ConstructorProperties;
+
+public class ReporterConfig {
+
+ private final String name;
+ private final String output;
+ private boolean forceToScreen = false;
+
+ @ConstructorProperties({"name", "output", "forceToScreen"})
+ public ReporterConfig(String name, String output, Boolean forceToScreen) {
+ if ( name != null ) {
+ this.name = name;
+ } else {
+ this.name = CoreReporters.UT_DOCUMENTATION_REPORTER.name();
+ }
+ this.output = output;
+ if (forceToScreen != null) this.forceToScreen = forceToScreen;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getOutput() {
+ return output;
+ }
+
+ public boolean isForceToScreen() {
+ return forceToScreen;
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/config/RunCommandConfig.java b/src/main/java/org/utplsql/cli/config/RunCommandConfig.java
new file mode 100644
index 0000000..218466b
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/config/RunCommandConfig.java
@@ -0,0 +1,231 @@
+package org.utplsql.cli.config;
+
+
+import org.utplsql.cli.LoggerConfiguration.ConfigLevel;
+
+import java.beans.ConstructorProperties;
+
+public class RunCommandConfig extends ConnectionConfig {
+
+ private final String[] suitePaths;
+ private final ReporterConfig[] reporters;
+ private boolean outputAnsiColor = false;
+ private final Integer failureExitCode;
+ private boolean skipCompatibilityCheck = false;
+ private final String[] includePackages;
+ private final String[] excludePackages;
+ private final FileMapperConfig sourceMapping;
+ private final FileMapperConfig testMapping;
+ private final ConfigLevel logConfigLevel;
+ private final Integer timeoutInMinutes;
+ private boolean dbmsOutput = false;
+ private boolean randomTestOrder = false;
+ private final Integer randomTestOrderSeed;
+ private final String[] tags;
+ private final String[] coverageSchemes;
+ private final Integer oraStuckTimeout;
+
+ @ConstructorProperties({"connectString", "suitePaths", "reporters", "outputAnsiColor", "failureExitCode", "skipCompatibilityCheck", "includePackages", "excludePackages", "sourceMapping", "testMapping", "logConfigLevel", "timeoutInMinutes", "dbmsOutput", "randomTestOrder", "randomTestOrderSeed", "tags", "coverageSchemes", "oraStuckTimeout"})
+ public RunCommandConfig(String connectString, String[] suitePaths, ReporterConfig[] reporters, boolean outputAnsiColor, Integer failureExitCode, boolean skipCompatibilityCheck, String[] includePackages, String[] excludePackages, FileMapperConfig sourceMapping, FileMapperConfig testMapping, ConfigLevel logConfigLevel, Integer timeoutInMinutes, boolean dbmsOutput, boolean randomTestOrder, Integer randomTestOrderSeed, String[] tags, String[] coverageSchemes, Integer oraStuckTimeout) {
+ super(connectString);
+ this.suitePaths = suitePaths;
+ this.reporters = reporters;
+ this.outputAnsiColor = outputAnsiColor;
+ this.failureExitCode = failureExitCode;
+ this.skipCompatibilityCheck = skipCompatibilityCheck;
+ this.includePackages = includePackages;
+ this.excludePackages = excludePackages;
+ this.sourceMapping = sourceMapping;
+ this.testMapping = testMapping;
+ this.logConfigLevel = logConfigLevel;
+ this.timeoutInMinutes = timeoutInMinutes;
+ this.dbmsOutput = dbmsOutput;
+ this.randomTestOrder = randomTestOrder;
+ this.randomTestOrderSeed = randomTestOrderSeed;
+ this.tags = tags;
+ this.coverageSchemes = coverageSchemes;
+ this.oraStuckTimeout = oraStuckTimeout;
+ }
+
+ public String[] getSuitePaths() {
+ return suitePaths;
+ }
+
+ public String[] getTags() {
+ return tags;
+ }
+
+ public ReporterConfig[] getReporters() {
+ return reporters;
+ }
+
+ public boolean isOutputAnsiColor() {
+ return outputAnsiColor;
+ }
+
+ public Integer getFailureExitCode() {
+ return failureExitCode;
+ }
+
+ public boolean isSkipCompatibilityCheck() {
+ return skipCompatibilityCheck;
+ }
+
+ public String[] getIncludePackages() {
+ return includePackages;
+ }
+
+ public String[] getExcludePackages() {
+ return excludePackages;
+ }
+
+ public FileMapperConfig getSourceMapping() {
+ return sourceMapping;
+ }
+
+ public FileMapperConfig getTestMapping() {
+ return testMapping;
+ }
+
+ public ConfigLevel getLogConfigLevel() {
+ return logConfigLevel;
+ }
+
+ public Integer getTimeoutInMinutes() {
+ return timeoutInMinutes;
+ }
+
+ public boolean isDbmsOutput() {
+ return dbmsOutput;
+ }
+
+ public boolean isRandomTestOrder() {
+ return randomTestOrder;
+ }
+
+ public Integer getRandomTestOrderSeed() {
+ return randomTestOrderSeed;
+ }
+
+ public String[] getCoverageSchemes() {
+ return coverageSchemes;
+ }
+
+ public Integer getOraStuckTimeout() { return oraStuckTimeout; }
+
+ public static class Builder {
+
+ private String connectString;
+ private String[] suitePaths = new String[0];
+ private ReporterConfig[] reporters;
+ private boolean outputAnsiColor;
+ private Integer failureExitCode;
+ private boolean skipCompatibilityCheck;
+ private String[] includePackages = new String[0];
+ private String[] excludePackages = new String[0];
+ private FileMapperConfig sourceMapping;
+ private FileMapperConfig testMapping;
+ private ConfigLevel logConfigLevel;
+ private Integer timeoutInMinutes;
+ private boolean dbmsOutput;
+ private boolean randomTestOrder;
+ private Integer randomTestOrderSeed;
+ private String[] tags = new String[0];
+ private String[] coverageSchemes = new String[0];
+ private Integer oraStuckTimeout;
+
+ public Builder connectString(String connectString) {
+ this.connectString = connectString;
+ return this;
+ }
+
+ public Builder suitePaths(String[] suitePaths) {
+ this.suitePaths = suitePaths;
+ return this;
+ }
+
+ public Builder reporters(ReporterConfig[] reporters) {
+ this.reporters = reporters;
+ return this;
+ }
+
+ public Builder outputAnsiColor(boolean outputAnsiColor) {
+ this.outputAnsiColor = outputAnsiColor;
+ return this;
+ }
+
+ public Builder failureExitCode(Integer failureExitCode) {
+ this.failureExitCode = failureExitCode;
+ return this;
+ }
+
+ public Builder skipCompatibilityCheck(boolean skipCompatibilityCheck) {
+ this.skipCompatibilityCheck = skipCompatibilityCheck;
+ return this;
+ }
+
+ public Builder includePackages(String[] includePackages) {
+ this.includePackages = includePackages;
+ return this;
+ }
+
+ public Builder excludePackages(String[] excludePackages) {
+ this.excludePackages = excludePackages;
+ return this;
+ }
+
+ public Builder sourceMapping(FileMapperConfig sourceMapping) {
+ this.sourceMapping = sourceMapping;
+ return this;
+ }
+
+ public Builder testMapping(FileMapperConfig testMapping) {
+ this.testMapping = testMapping;
+ return this;
+ }
+
+ public Builder logConfigLevel(ConfigLevel logConfigLevel) {
+ this.logConfigLevel = logConfigLevel;
+ return this;
+ }
+
+ public Builder timeoutInMinutes(Integer timeoutInMinutes) {
+ this.timeoutInMinutes = timeoutInMinutes;
+ return this;
+ }
+
+ public Builder dbmsOutput(boolean dbmsOutput) {
+ this.dbmsOutput = dbmsOutput;
+ return this;
+ }
+
+ public Builder randomTestOrder(boolean randomTestOrder) {
+ this.randomTestOrder = randomTestOrder;
+ return this;
+ }
+
+ public Builder randomTestOrderSeed(Integer randomTestOrderSeed) {
+ this.randomTestOrderSeed = randomTestOrderSeed;
+ return this;
+ }
+
+ public Builder tags(String[] tags) {
+ this.tags = tags;
+ return this;
+ }
+
+ public Builder coverageSchemes(String[] coverageSchemes) {
+ this.coverageSchemes = coverageSchemes;
+ return this;
+ }
+
+ public Builder oraStuckTimeout(Integer oraStuckTimeout) {
+ this.oraStuckTimeout = oraStuckTimeout;
+ return this;
+ }
+
+ public RunCommandConfig create() {
+ return new RunCommandConfig(connectString, suitePaths, reporters, outputAnsiColor, failureExitCode, skipCompatibilityCheck, includePackages, excludePackages, sourceMapping, testMapping, logConfigLevel, timeoutInMinutes, dbmsOutput, randomTestOrder, randomTestOrderSeed, tags, coverageSchemes, oraStuckTimeout);
+ }
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/datasource/InitializableOracleDataSource.java b/src/main/java/org/utplsql/cli/datasource/InitializableOracleDataSource.java
new file mode 100644
index 0000000..db32b1a
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/datasource/InitializableOracleDataSource.java
@@ -0,0 +1,32 @@
+package org.utplsql.cli.datasource;
+
+import oracle.jdbc.pool.OracleDataSource;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public class InitializableOracleDataSource extends OracleDataSource {
+
+ private String initSql;
+
+ public InitializableOracleDataSource() throws SQLException {
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+ Connection con = super.getConnection();
+
+ if ( initSql != null && !initSql.isEmpty() ) {
+ try (CallableStatement stmt = con.prepareCall(initSql)) {
+ stmt.execute();
+ }
+ }
+
+ return con;
+ }
+
+ public void setConnectionInitSql( String sql ) {
+ this.initSql = sql;
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java b/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java
new file mode 100644
index 0000000..8f99cf3
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java
@@ -0,0 +1,126 @@
+package org.utplsql.cli.datasource;
+
+import oracle.jdbc.pool.OracleDataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.utplsql.api.EnvironmentVariableUtil;
+import org.utplsql.cli.ConnectionConfig;
+import org.utplsql.cli.exception.DatabaseConnectionFailed;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class TestedDataSourceProvider {
+
+ interface ConnectStringPossibility {
+ String getConnectString(ConnectionConfig config);
+
+ String getMaskedConnectString(ConnectionConfig config);
+ }
+
+ private static final Logger logger = LoggerFactory.getLogger(TestedDataSourceProvider.class);
+ private final ConnectionConfig config;
+ private final List possibilities = new ArrayList<>();
+ private final int maxConnections;
+
+ public TestedDataSourceProvider(ConnectionConfig config, int maxConnections) {
+ this.config = config;
+ this.maxConnections = maxConnections;
+
+ possibilities.add(new ThickConnectStringPossibility());
+ possibilities.add(new ThinConnectStringPossibility());
+ }
+
+ public DataSource getDataSource() throws SQLException {
+
+ InitializableOracleDataSource ds = new InitializableOracleDataSource();
+
+ setInitSqlFrom_NLS_LANG(ds);
+ setThickOrThinJdbcUrl(ds);
+
+ return ds;
+ }
+
+ private void setThickOrThinJdbcUrl(OracleDataSource ds) throws SQLException {
+ List errors = new ArrayList<>();
+ Throwable lastException = null;
+
+ ds.setUser(config.getUser());
+ ds.setPassword(config.getPassword());
+
+ for (ConnectStringPossibility possibility : possibilities) {
+ logger.debug("Try connecting {}", possibility.getMaskedConnectString(config));
+ ds.setURL(possibility.getConnectString(config));
+ try (Connection ignored = ds.getConnection()) {
+ logger.info("Use connection string {}", possibility.getMaskedConnectString(config));
+ return;
+ } catch (Error | Exception e) {
+ errors.add(possibility.getMaskedConnectString(config) + ": " + e.getMessage());
+ lastException = e;
+ }
+ }
+
+ errors.forEach(System.out::println);
+ throw new DatabaseConnectionFailed(lastException);
+ }
+
+ private void setInitSqlFrom_NLS_LANG(InitializableOracleDataSource ds) {
+ String nls_lang = EnvironmentVariableUtil.getEnvValue("NLS_LANG");
+
+ if (nls_lang != null) {
+ Pattern pattern = Pattern.compile("^([a-zA-Z ]+)?_?([a-zA-Z ]+)?\\.?([a-zA-Z0-9]+)?$");
+ Matcher matcher = pattern.matcher(nls_lang);
+
+ List sqlCommands = new ArrayList<>(2);
+ if (matcher.matches()) {
+ if (matcher.group(1) != null) {
+ sqlCommands.add(String.format("ALTER SESSION SET NLS_LANGUAGE='%s'", matcher.group(1)));
+ }
+ if (matcher.group(2) != null) {
+ sqlCommands.add(String.format("ALTER SESSION SET NLS_TERRITORY='%s'", matcher.group(2)));
+ }
+
+ if (sqlCommands.size() > 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("BEGIN\n");
+ for (String command : sqlCommands) {
+ sb.append(String.format("EXECUTE IMMEDIATE q'[%s]';\n", command));
+ }
+ sb.append("END;");
+
+ logger.debug("NLS settings: {}", sb.toString());
+ ds.setConnectionInitSql(sb.toString());
+ }
+ }
+ }
+ }
+
+ private static class ThickConnectStringPossibility implements ConnectStringPossibility {
+ @Override
+ public String getConnectString(ConnectionConfig config) {
+ return "jdbc:oracle:oci8:@" + config.getConnect();
+ }
+
+ @Override
+ public String getMaskedConnectString(ConnectionConfig config) {
+ return "jdbc:oracle:oci8:****/****@" + config.getConnect();
+ }
+ }
+
+ private static class ThinConnectStringPossibility implements ConnectStringPossibility {
+ @Override
+ public String getConnectString(ConnectionConfig config) {
+ return "jdbc:oracle:thin:@" + config.getConnect();
+ }
+
+ @Override
+ public String getMaskedConnectString(ConnectionConfig config) {
+ return "jdbc:oracle:thin:****/****@" + config.getConnect();
+ }
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/exception/DatabaseConnectionFailed.java b/src/main/java/org/utplsql/cli/exception/DatabaseConnectionFailed.java
index 01b03db..fe4bf96 100644
--- a/src/main/java/org/utplsql/cli/exception/DatabaseConnectionFailed.java
+++ b/src/main/java/org/utplsql/cli/exception/DatabaseConnectionFailed.java
@@ -4,7 +4,7 @@
public class DatabaseConnectionFailed extends SQLException {
- public DatabaseConnectionFailed(SQLException cause ) {
- super( "Could not establish connection to database. Reason: " + cause.getMessage(), cause);
+ public DatabaseConnectionFailed(Throwable cause) {
+ super("Could not establish connection to database. Reason: " + cause.getMessage(), cause);
}
}
diff --git a/src/main/java/org/utplsql/cli/exception/ReporterTimeoutException.java b/src/main/java/org/utplsql/cli/exception/ReporterTimeoutException.java
new file mode 100644
index 0000000..5bfdbf9
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/exception/ReporterTimeoutException.java
@@ -0,0 +1,15 @@
+package org.utplsql.cli.exception;
+
+public class ReporterTimeoutException extends Exception {
+
+ private final int timeOutInMinutes;
+
+ public ReporterTimeoutException(int timeoutInMinutes) {
+ super("Timeout while waiting for reporters to finish for " + timeoutInMinutes + " minutes");
+ this.timeOutInMinutes = timeoutInMinutes;
+ }
+
+ public int getTimeOutInMinutes() {
+ return timeOutInMinutes;
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/log/StringBlockFormatter.java b/src/main/java/org/utplsql/cli/log/StringBlockFormatter.java
new file mode 100644
index 0000000..370092c
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/log/StringBlockFormatter.java
@@ -0,0 +1,85 @@
+package org.utplsql.cli.log;
+
+public class StringBlockFormatter {
+
+ private String headline;
+ private final StringBuilder content = new StringBuilder();
+
+ public StringBlockFormatter() {
+ }
+
+ public StringBlockFormatter(String headline) {
+ setHeadline(headline);
+ }
+
+ public void setHeadline(String headline) {
+ this.headline = headline;
+ }
+
+ public String getHeadline() {
+ return headline;
+ }
+
+ public void append(CharSequence seq) {
+ content.append(seq);
+ }
+
+ public void appendLine(CharSequence seq) {
+ content.append(seq).append("\n");
+ }
+
+ private int getMaxLength(String[] lines) {
+ int len = 0;
+ for (String line : lines) {
+ if (line.length() > len) {
+ len = line.length();
+ }
+ }
+
+ if (headline.length() > (len + 6)) {
+ len = headline.length();
+ }
+
+ return len;
+ }
+
+ public static String getEncapsulatedLine(String line, int maxLength) {
+ return String.format("# %-" + maxLength + "s #", line);
+ }
+
+ public static String getEncapsulatedHeadline(String headline, int maxLength) {
+ String content = new String(new char[maxLength + 8]).replace("\0", "#");
+ if (headline == null || headline.isEmpty()) {
+ return content;
+ }
+
+ headline = " " + headline + " ";
+ int start = (int) Math.floor(
+ (float) content.length() / 2f
+ - (float) headline.length() / 2f
+ );
+ int end = start + headline.length();
+
+ return content.substring(0, start)
+ + headline
+ + content.substring(end);
+ }
+
+ public String toString() {
+
+ String[] lines = content.toString().split("\n");
+ int maxLen = getMaxLength(lines);
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(getEncapsulatedHeadline(headline, maxLen)).append("\n");
+ sb.append(getEncapsulatedLine("", maxLen)).append("\n");
+ for (String line : lines) {
+ sb.append(getEncapsulatedLine(line, maxLen)).append("\n");
+ }
+ sb.append(getEncapsulatedLine("", maxLen)).append("\n");
+ sb.append(getEncapsulatedHeadline("", maxLen));
+
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/reporters/LocalAssetsCoverageHTMLReporter.java b/src/main/java/org/utplsql/cli/reporters/LocalAssetsCoverageHTMLReporter.java
new file mode 100644
index 0000000..602ee7c
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/reporters/LocalAssetsCoverageHTMLReporter.java
@@ -0,0 +1,74 @@
+package org.utplsql.cli.reporters;
+
+import org.utplsql.api.compatibility.CompatibilityProxy;
+import org.utplsql.api.reporter.CoverageHTMLReporter;
+import org.utplsql.api.reporter.Reporter;
+import org.utplsql.api.reporter.ReporterFactory;
+import org.utplsql.cli.ReporterOptions;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * Simple replacement of the CoverageHTMLReporter which writes the necessary assets to a folder
+ * named after the Output File's name.
+ *
+ * @author pesse
+ */
+public class LocalAssetsCoverageHTMLReporter extends CoverageHTMLReporter implements ReporterOptionsAware {
+
+ private ReporterOptions options;
+
+ public LocalAssetsCoverageHTMLReporter(String selfType, Object[] attributes) {
+ super(selfType, attributes);
+ }
+
+ @Override
+ public Reporter init(Connection con, CompatibilityProxy compatibilityProxy, ReporterFactory reporterFactory) throws SQLException {
+ super.init(con, compatibilityProxy, reporterFactory);
+
+ if (hasOutputToFile()) {
+ writeReportAssetsTo(getPhysicalAssetPath());
+ }
+
+ return this;
+ }
+
+ private String getNameOfOutputFile() {
+ Path outputPath = Paths.get(options.getOutputFileName());
+ return outputPath.getName(outputPath.getNameCount() - 1).toString();
+ }
+
+ private Path getPhysicalAssetPath() {
+ Path outputPath = Paths.get(options.getOutputFileName());
+ if (outputPath.getNameCount() > 1) {
+ return outputPath.getParent().resolve(getAssetsPath());
+ } else {
+ return Paths.get(getAssetsPath());
+ }
+ }
+
+ private void setAssetsPathFromOptions() {
+ if (hasOutputToFile()) {
+ setAssetsPath(getNameOfOutputFile() + "_assets/");
+ }
+ }
+
+ private boolean hasOutputToFile() {
+ return (options != null && options.outputToFile());
+ }
+
+ @Override
+ public void setReporterOptions(ReporterOptions options) {
+ this.options = options;
+ setAssetsPathFromOptions();
+ }
+
+ @Override
+ protected void setAttributes(Object[] attributes) {
+ super.setAttributes(attributes);
+ setAssetsPathFromOptions();
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/reporters/ReporterOptionsAware.java b/src/main/java/org/utplsql/cli/reporters/ReporterOptionsAware.java
new file mode 100644
index 0000000..5236715
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/reporters/ReporterOptionsAware.java
@@ -0,0 +1,12 @@
+package org.utplsql.cli.reporters;
+
+import org.utplsql.cli.ReporterOptions;
+
+/**
+ * Reporters implementing this interface will get their specific ReporterOptions before initialization
+ *
+ * @author pesse
+ */
+public interface ReporterOptionsAware {
+ void setReporterOptions(ReporterOptions options);
+}
diff --git a/src/main/resources/utplsql-cli.version b/src/main/resources/utplsql-cli.version
new file mode 100644
index 0000000..3fb16e7
--- /dev/null
+++ b/src/main/resources/utplsql-cli.version
@@ -0,0 +1 @@
+${project.version}.${travisBuildNumber}
\ No newline at end of file
diff --git a/src/test/java/org/utplsql/cli/AbstractFileOutputTest.java b/src/test/java/org/utplsql/cli/AbstractFileOutputTest.java
new file mode 100644
index 0000000..7cafd58
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/AbstractFileOutputTest.java
@@ -0,0 +1,42 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+
+public abstract class AbstractFileOutputTest {
+
+ private Set tempPaths;
+
+ protected void addTempPath(Path path) {
+ tempPaths.add(path);
+ }
+
+ protected boolean tempPathExists( Path path ) { return tempPaths.contains(path); }
+
+ @BeforeEach
+ public void setupTest() {
+ tempPaths = new HashSet<>();
+ }
+
+ @AfterEach
+ public void deleteTempFiles() {
+ tempPaths.forEach(p -> deleteDir(p.toFile()));
+ }
+
+ void deleteDir(File file) {
+ if (file.exists()) {
+ File[] contents = file.listFiles();
+ if (contents != null) {
+ for (File f : contents) {
+ deleteDir(f);
+ }
+ }
+ file.delete();
+ }
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/CliHelpTest.java b/src/test/java/org/utplsql/cli/CliHelpTest.java
new file mode 100644
index 0000000..baaf25f
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/CliHelpTest.java
@@ -0,0 +1,63 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+import org.utplsql.cli.util.SystemCapturer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CliHelpTest {
+
+ private SystemCapturer capturer;
+
+ @Test
+ void show_basic_help_on_help_command() {
+ capturer = new SystemCapturer.SystemOutCapturer();
+ capturer.start();
+ TestHelper.runApp("help");
+ String output = capturer.stop();
+
+ assertTrue(output.contains("Usage:"));
+ }
+
+ @Test
+ void show_help_for_run_command() {
+ capturer = new SystemCapturer.SystemOutCapturer();
+ capturer.start();
+ TestHelper.runApp("run", "-h");
+ String output = capturer.stop();
+
+ assertTrue(output.contains("Usage:"));
+ }
+
+ @Test
+ void show_help_for_reporters_command() {
+ capturer = new SystemCapturer.SystemOutCapturer();
+ capturer.start();
+ TestHelper.runApp("reporters", "-h");
+ String output = capturer.stop();
+
+ assertTrue(output.contains("Usage:"));
+ }
+
+ @Test
+ void show_help_for_info_command() {
+ capturer = new SystemCapturer.SystemOutCapturer();
+ capturer.start();
+ TestHelper.runApp("reporters", "-h");
+ String output = capturer.stop();
+
+ assertTrue(output.contains("Usage:"));
+ }
+
+ @Test
+ void write_help_to_error_out_on_unknown_command() {
+ capturer = new SystemCapturer.SystemErrCapturer();
+ capturer.start();
+ int exitCode = TestHelper.runApp("wtfhappens");
+ String output = capturer.stop();
+
+ assertTrue(output.contains("Usage:"));
+ assertEquals(1, exitCode);
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/CliVersionInfoTest.java b/src/test/java/org/utplsql/cli/CliVersionInfoTest.java
new file mode 100644
index 0000000..28db14c
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/CliVersionInfoTest.java
@@ -0,0 +1,13 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CliVersionInfoTest {
+
+ @Test
+ void getCliVersionInfo() {
+ assertTrue(CliVersionInfo.getVersion().startsWith("3.1"));
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/ConnectionConfigTest.java b/src/test/java/org/utplsql/cli/ConnectionConfigTest.java
new file mode 100644
index 0000000..ee1e0b9
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/ConnectionConfigTest.java
@@ -0,0 +1,57 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class ConnectionConfigTest {
+
+ @Test
+ void parse() {
+ ConnectionConfig info = new ConnectionConfig("test/pw@my.local.host/service");
+
+ assertEquals("test", info.getUser());
+ assertEquals("pw", info.getPassword());
+ assertEquals("my.local.host/service", info.getConnect());
+ assertFalse(info.isSysDba());
+ }
+
+ @Test
+ void parseSysDba() {
+ ConnectionConfig info = new ConnectionConfig("sys as sysdba/pw@my.local.host/service");
+
+ assertEquals("sys as sysdba", info.getUser());
+ assertEquals("pw", info.getPassword());
+ assertEquals("my.local.host/service", info.getConnect());
+ assertTrue(info.isSysDba());
+ }
+ @Test
+ void parseSysOper() {
+ ConnectionConfig info = new ConnectionConfig("myOperUser as sysoper/passw0rd@my.local.host/service");
+
+ assertEquals("myOperUser as sysoper", info.getUser());
+ assertEquals("passw0rd", info.getPassword());
+ assertEquals("my.local.host/service", info.getConnect());
+ assertTrue(info.isSysDba());
+ }
+
+ @Test
+ void parseSpecialCharsPW() {
+ ConnectionConfig info = new ConnectionConfig("test/\"p@ssw0rd=\"@my.local.host/service");
+
+ assertEquals("test", info.getUser());
+ assertEquals("p@ssw0rd=", info.getPassword());
+ assertEquals("my.local.host/service", info.getConnect());
+ assertFalse(info.isSysDba());
+ }
+
+ @Test
+ void parseSpecialCharsUser() {
+ ConnectionConfig info = new ConnectionConfig("\"User/Mine@=\"/pw@my.local.host/service");
+
+ assertEquals("User/Mine@=", info.getUser());
+ assertEquals("pw", info.getPassword());
+ assertEquals("my.local.host/service", info.getConnect());
+ assertFalse(info.isSysDba());
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/ConnectionInfoTest.java b/src/test/java/org/utplsql/cli/ConnectionInfoTest.java
deleted file mode 100644
index 2fdc9c4..0000000
--- a/src/test/java/org/utplsql/cli/ConnectionInfoTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package org.utplsql.cli;
-
-/**
- * Created by Vinicius on 21/04/2017.
- */
-public class ConnectionInfoTest {
-
- /**
- * Regex pattern to match following connection strings:
- * user/pass@host:port/db
- * user/pass@host/db
- * user/pass@db
- */
-
-// @Test
-// public void valid_Full() {
-// try {
-// ConnectionInfo ci = new ConnectionInfo()
-// .parseConnectionString("my_user/p@ss!@some.server.123-abc.com:3000/db_1.acme.com");
-// Assert.assertEquals("my_user", ci.getUser());
-// Assert.assertEquals("p@ss!", ci.getPassword());
-// Assert.assertEquals("some.server.123-abc.com", ci.getHost());
-// Assert.assertEquals(3000, ci.getPort());
-// Assert.assertEquals("db_1.acme.com", ci.getDatabase());
-// Assert.assertEquals("my_user@some.server.123-abc.com:3000/db_1.acme.com", ci.toString());
-// Assert.assertEquals("jdbc:oracle:thin:@//some.server.123-abc.com:3000/db_1.acme.com", ci.getConnectionUrl());
-// } catch (Exception e) {
-// Assert.fail(e.getMessage());
-// }
-// }
-//
-// @Test
-// public void valid_WithoutPort() {
-// try {
-// ConnectionInfo ci = new ConnectionInfo()
-// .parseConnectionString("my_user/p@ss!@some.server.123-abc.com/db_1.acme.com");
-// Assert.assertEquals("my_user", ci.getUser());
-// Assert.assertEquals("p@ss!", ci.getPassword());
-// Assert.assertEquals("some.server.123-abc.com", ci.getHost());
-// Assert.assertEquals(1521, ci.getPort());
-// Assert.assertEquals("db_1.acme.com", ci.getDatabase());
-// Assert.assertEquals("my_user@some.server.123-abc.com:1521/db_1.acme.com", ci.toString());
-// Assert.assertEquals("jdbc:oracle:thin:@//some.server.123-abc.com:1521/db_1.acme.com", ci.getConnectionUrl());
-// } catch (Exception e) {
-// Assert.fail(e.getMessage());
-// }
-// }
-//
-// @Test
-// public void valid_WithoutHostAndPort() {
-// try {
-// ConnectionInfo ci = new ConnectionInfo()
-// .parseConnectionString("my_user/p@ss!@127.0.0.1/db_1.acme.com");
-// Assert.assertEquals("my_user", ci.getUser());
-// Assert.assertEquals("p@ss!", ci.getPassword());
-// Assert.assertEquals("127.0.0.1", ci.getHost());
-// Assert.assertEquals(1521, ci.getPort());
-// Assert.assertEquals("db_1.acme.com", ci.getDatabase());
-// Assert.assertEquals("my_user@127.0.0.1:1521/db_1.acme.com", ci.toString());
-// Assert.assertEquals("jdbc:oracle:thin:@//127.0.0.1:1521/db_1.acme.com", ci.getConnectionUrl());
-// } catch (Exception e) {
-// Assert.fail(e.getMessage());
-// }
-// }
-//
-// @Test
-// public void invalid_WithoutDatabase_1() {
-// try {
-// new ConnectionInfo().parseConnectionString("user/pass@");
-// Assert.fail();
-// } catch (ParameterException ignored) {}
-// }
-//
-// @Test
-// public void invalid_WithoutDatabase_2() {
-// try {
-// new ConnectionInfo().parseConnectionString("user/pass");
-// Assert.fail();
-// } catch (ParameterException ignored) {}
-// }
-//
-// @Test
-// public void invalid_WithoutDatabase_3() {
-// try {
-// new ConnectionInfo().parseConnectionString("user/pass@localhost:1521");
-// Assert.fail();
-// } catch (ParameterException ignored) {}
-// }
-//
-// @Test
-// public void invalid_WithoutHost() {
-// try {
-// new ConnectionInfo().parseConnectionString("user/pass@/db");
-// Assert.fail();
-// } catch (ParameterException ignored) {}
-// }
-//
-// @Test
-// public void invalid_WithoutPassword() {
-// try {
-// new ConnectionInfo().parseConnectionString("user/@db");
-// Assert.fail();
-// } catch (ParameterException ignored) {}
-// }
-//
-// @Test
-// public void invalid_WithoutUsername() {
-// try {
-// new ConnectionInfo().parseConnectionString("/pass@db");
-// Assert.fail();
-// } catch (ParameterException ignored) {}
-// }
-//
-// @Test
-// public void invalid_WithoutUserPassDb_1() {
-// try {
-// new ConnectionInfo().parseConnectionString("/@db");
-// Assert.fail();
-// } catch (ParameterException ignored) {}
-// }
-//
-// @Test
-// public void invalid_WithoutUserPass() {
-// try {
-// new ConnectionInfo().parseConnectionString("@db");
-// Assert.fail();
-// } catch (ParameterException ignored) {}
-// }
-
-}
diff --git a/src/test/java/org/utplsql/cli/DataSourceProviderIT.java b/src/test/java/org/utplsql/cli/DataSourceProviderIT.java
new file mode 100644
index 0000000..1caaf26
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/DataSourceProviderIT.java
@@ -0,0 +1,84 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+import org.utplsql.cli.datasource.TestedDataSourceProvider;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class DataSourceProviderIT {
+
+ @Test
+ void connectToDatabase() throws SQLException {
+ DataSource dataSource = getDataSource();
+
+ assertNotNull(dataSource);
+ }
+
+ //@Test
+ void connectAsSysdba() throws SQLException {
+ ConnectionConfig config = new ConnectionConfig("sys as sysdba/oracle@localhost:1522/ORCLPDB1");
+ DataSource dataSource = new TestedDataSourceProvider(config, 2).getDataSource();
+
+ assertNotNull(dataSource);
+ }
+
+ @Test
+ void initNlsLang() throws SQLException {
+ System.setProperty("NLS_LANG", "BRAZILIAN PORTUGUESE_BRAZIL.WE8ISO8859P1");
+ DataSource dataSource = getDataSource();
+
+ assertNotNull(dataSource);
+ checkNlsSessionParameter(dataSource, "NLS_LANGUAGE", "BRAZILIAN PORTUGUESE");
+ checkNlsSessionParameter(dataSource, "NLS_TERRITORY", "BRAZIL");
+ }
+
+ @Test
+ void initPartialNlsLangTerritory() throws SQLException {
+ System.setProperty("NLS_LANG", "_SOMALIA");
+ DataSource dataSource = getDataSource();
+
+ assertNotNull(dataSource);
+ checkNlsSessionParameter(dataSource, "NLS_TERRITORY", "SOMALIA");
+ }
+
+ @Test
+ void initPartialNlsLangLanguage() throws SQLException {
+ System.setProperty("NLS_LANG", "HINDI");
+ DataSource dataSource = getDataSource();
+
+ assertNotNull(dataSource);
+ checkNlsSessionParameter(dataSource, "NLS_LANGUAGE", "HINDI");
+ }
+
+ @Test
+ void initNlsLangEmpty() throws SQLException {
+ System.setProperty("NLS_LANG", "");
+ DataSource dataSource = getDataSource();
+
+ assertNotNull(dataSource);
+ }
+
+ private DataSource getDataSource() throws SQLException {
+ ConnectionConfig config = new ConnectionConfig(TestHelper.getConnectionString());
+ return new TestedDataSourceProvider(config, 2).getDataSource();
+ }
+
+ private void checkNlsSessionParameter( DataSource dataSource, String parameterName, String expectedValue ) throws SQLException {
+ try ( Connection con = dataSource.getConnection() ) {
+ try (PreparedStatement stmt = con.prepareStatement("select value from nls_session_parameters where parameter = ?")) {
+ stmt.setString(1, parameterName);
+ ResultSet rs = stmt.executeQuery();
+ if ( rs.next() )
+ assertEquals(expectedValue, rs.getString(1));
+ else
+ fail("Could not get NLS Session parameter value for '" + parameterName + "'");
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/FileWalkerTest.java b/src/test/java/org/utplsql/cli/FileWalkerTest.java
index b8e2738..6ec2e1b 100644
--- a/src/test/java/org/utplsql/cli/FileWalkerTest.java
+++ b/src/test/java/org/utplsql/cli/FileWalkerTest.java
@@ -1,24 +1,25 @@
package org.utplsql.cli;
-import org.junit.Assert;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.Collections;
import java.util.List;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
/**
* Created by Vinicius on 18/06/2017.
*/
-public class FileWalkerTest {
+class FileWalkerTest {
private final File BASE_DIR = new File(new File("").getAbsolutePath(), "assets/demo_project");
@Test
- public void fileWalker_Relative() {
+ void fileWalker_Relative() {
List fileList = new FileWalker().getFileList(BASE_DIR, "source");
Collections.sort(fileList);
- Assert.assertArrayEquals(new Object[] {
+ assertArrayEquals(new Object[] {
"source/packages/package.pkb".replace('/', File.separatorChar),
"source/packages/package.pks".replace('/', File.separatorChar),
"source/script.sql".replace('/', File.separatorChar),
@@ -27,10 +28,10 @@ public void fileWalker_Relative() {
}
@Test
- public void fileWalker_Absolute() {
+ void fileWalker_Absolute() {
List fileList = new FileWalker().getFileList(BASE_DIR, "source", false);
Collections.sort(fileList);
- Assert.assertArrayEquals(new Object[] {
+ assertArrayEquals(new Object[] {
BASE_DIR.getAbsolutePath() + "/source/packages/package.pkb".replace('/', File.separatorChar),
BASE_DIR.getAbsolutePath() + "/source/packages/package.pks".replace('/', File.separatorChar),
BASE_DIR.getAbsolutePath() + "/source/script.sql".replace('/', File.separatorChar),
diff --git a/src/test/java/org/utplsql/cli/HelpCommandTest.java b/src/test/java/org/utplsql/cli/HelpCommandTest.java
new file mode 100644
index 0000000..fd19bd9
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/HelpCommandTest.java
@@ -0,0 +1,60 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.utplsql.cli.util.SystemCapturer;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class HelpCommandTest {
+
+
+ private SystemCapturer capturer;
+
+ @BeforeEach
+ void setupCaptureSystemOut() {
+ capturer = new SystemCapturer.SystemOutCapturer();
+ }
+
+ @Test
+ void callHelp() {
+
+ capturer.start();
+ int result = TestHelper.runApp("-h");
+ String output = capturer.stop();
+
+ assertEquals(0, result);
+ assertTrue(output.contains("Usage:"));
+ }
+
+ @Test
+ void callRunHelp() {
+
+ capturer.start();
+ int result = TestHelper.runApp("run", "-h");
+ String output = capturer.stop();
+
+ assertEquals(0, result);
+ assertTrue(output.contains("Usage:"));
+ }
+
+ @Test
+ void callWithNoArgs() {
+
+ capturer.start();
+ int result = TestHelper.runApp();
+ String output = capturer.stop();
+
+ assertEquals(1, result);
+ assertTrue(output.contains("Usage:"));
+ }
+
+ @AfterEach
+ void cleanupCaptureSystemOut() throws IOException {
+ capturer.stop();
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/PathMapperTest.java b/src/test/java/org/utplsql/cli/PathMapperTest.java
new file mode 100644
index 0000000..17798ca
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/PathMapperTest.java
@@ -0,0 +1,26 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+import org.utplsql.api.TestRunner;
+
+import java.util.ArrayList;
+
+public class PathMapperTest {
+
+ @Test
+ void checkPathMapperOutput() {
+ IRunCommand runCmd = TestHelper.createRunCommand(TestHelper.getConnectionString(),
+ "-f=ut_sonar_test_reporter",
+ "-o=sonar_result.xml",
+ "-s",
+ "-d",
+ "-source_path=src/test/resources/plsql/source",
+ "-owner=app",
+ "-regex_expression=\"*\"",
+ "-type_mapping=\"sql=PACKAGE BODY\"",
+ "-test_path=src/test/resources/plsql/test"
+ );
+
+ TestRunner testRunner = runCmd.newTestRunner(new ArrayList<>());;
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/PicocliRunCommandTest.java b/src/test/java/org/utplsql/cli/PicocliRunCommandTest.java
new file mode 100644
index 0000000..475ca82
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/PicocliRunCommandTest.java
@@ -0,0 +1,252 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+import org.utplsql.cli.config.FileMapperConfig;
+import org.utplsql.cli.config.ReporterConfig;
+import org.utplsql.cli.config.RunCommandConfig;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+public class PicocliRunCommandTest {
+
+ private RunCommandConfig parseForConfig( String... args ) throws Exception {
+ return TestHelper.parseRunConfig(args);
+ }
+
+ @Test
+ void runCommandAllArguments() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-p=app.betwnstr,app.basic",
+ "--tags=tag1,tag.2",
+ "-d",
+ "-c",
+ "-q",
+ "--failure-exit-code=10",
+ "-scc",
+ "-t=60",
+ "-exclude=app.exclude1,app.exclude2",
+ "-include=app.include1,app.include2",
+ "-D",
+ "-r",
+ "-seed=123",
+ "-f=ut_sonar_test_reporter",
+ "-o=sonar_result.xml",
+ "-s",
+ "-source_path=src/test/resources/plsql/source",
+ "-owner=app",
+ "-regex_expression=\"*\"",
+ "-type_mapping=\"sql=PACKAGE BODY\"",
+ "-owner_subexpression=0",
+ "-type_subexpression=0",
+ "-name_subexpression=0",
+ "-test_path=src/test/resources/plsql/test",
+ "-owner=test_app",
+ "-regex_expression=\"test_regex\"",
+ "-type_mapping=\"tsql=PACKAGE BODY\"",
+ "-owner_subexpression=1",
+ "-type_subexpression=2",
+ "-name_subexpression=3",
+ "--coverage-schemes=schema1,other_schema");
+
+ assertNotNull(config.getConnectString());
+ assertThat( config.getSuitePaths(), is(new String[]{"app.betwnstr", "app.basic"}));
+ assertThat( config.getTags(), is(new String[]{"tag1", "tag.2"}));
+ assertTrue( config.isOutputAnsiColor() );
+ assertEquals( LoggerConfiguration.ConfigLevel.NONE, config.getLogConfigLevel());
+ assertEquals( 10, config.getFailureExitCode());
+ assertTrue( config.isSkipCompatibilityCheck() );
+ assertEquals( 60, config.getTimeoutInMinutes());
+ assertThat( config.getExcludePackages(), is(new String[]{"app.exclude1", "app.exclude2"}));
+ assertThat( config.getIncludePackages(), is(new String[]{"app.include1", "app.include2"}));
+ assertTrue( config.isDbmsOutput() );
+ assertTrue( config.isRandomTestOrder() );
+ assertEquals( 123, config.getRandomTestOrderSeed() );
+ assertNotNull( config.getReporters() );
+ assertEquals( 1, config.getReporters().length );
+ assertThat( config.getCoverageSchemes(), is(new String[]{"schema1", "other_schema"}) );
+
+ // Source FileMapping
+ assertNotNull(config.getSourceMapping());
+ assertNotNull(config.getTestMapping());
+ }
+
+ @Test
+ void commaSeparatedPath() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-p=app.betwnstr,app.basic");
+
+ assertThat( config.getSuitePaths(), is(new String[]{"app.betwnstr", "app.basic"}));
+ }
+
+ @Test
+ void multiplePaths() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-p=app.betwnstr",
+ "-p=app.basic");
+
+ assertThat( config.getSuitePaths(), is(new String[]{"app.betwnstr", "app.basic"}));
+ }
+
+ @Test
+ void combinedOptions() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-cdq");
+
+ assertTrue( config.isOutputAnsiColor() );
+ assertEquals( LoggerConfiguration.ConfigLevel.NONE, config.getLogConfigLevel());
+ }
+
+ @Test
+ void debugLevelOptionsDebug() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-d");
+
+ assertEquals( LoggerConfiguration.ConfigLevel.DEBUG, config.getLogConfigLevel());
+ }
+
+ @Test
+ void debugLevelOptionsBasic() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString());
+
+ assertEquals( LoggerConfiguration.ConfigLevel.BASIC, config.getLogConfigLevel());
+ }
+
+ @Test
+ void debugLevelOptionsNone() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-q");
+
+ assertEquals( LoggerConfiguration.ConfigLevel.NONE, config.getLogConfigLevel());
+ }
+
+ @Test
+ void singleReporter() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-f=ut_documentation_reporter");
+
+ assertNotNull( config.getReporters() );
+
+ ReporterConfig reporterConfig = config.getReporters()[0];
+ assertEquals("ut_documentation_reporter", reporterConfig.getName());
+ assertNull(reporterConfig.getOutput());
+ assertFalse(reporterConfig.isForceToScreen());
+ }
+
+ @Test
+ void multipleReporters() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-f=ut_documentation_reporter",
+ "-o=output1.txt",
+ "-f=ut_coverage_html",
+ "-o=output2.html",
+ "-s");
+
+ assertNotNull( config.getReporters() );
+
+ ReporterConfig reporterConfig = config.getReporters()[0];
+ assertEquals("ut_documentation_reporter", reporterConfig.getName());
+ assertEquals("output1.txt", reporterConfig.getOutput());
+ assertFalse(reporterConfig.isForceToScreen());
+
+ reporterConfig = config.getReporters()[1];
+ assertEquals("ut_coverage_html", reporterConfig.getName());
+ assertEquals("output2.html", reporterConfig.getOutput());
+ assertTrue(reporterConfig.isForceToScreen());
+ }
+
+ @Test
+ void outputWithDefaultReporter() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-o=output1.txt");
+
+ assertNotNull( config.getReporters() );
+
+ ReporterConfig reporterConfig = config.getReporters()[0];
+ assertEquals("ut_documentation_reporter", reporterConfig.getName().toLowerCase());
+ assertEquals("output1.txt", reporterConfig.getOutput());
+ assertFalse(reporterConfig.isForceToScreen());
+ }
+
+ @Test
+ void sourceFileMapping() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-source_path=src/test/resources/plsql/source",
+ "-owner=app",
+ "-regex_expression=\"[a-Z+]\"",
+ "-type_mapping=\"sql=PACKAGE BODY/pks=PACKAGE\"",
+ "-owner_subexpression=0",
+ "-type_subexpression=1",
+ "-name_subexpression=3");
+
+ FileMapperConfig sourceMapperConfig = config.getSourceMapping();
+ assertEquals( "src/test/resources/plsql/source", sourceMapperConfig.getPath());
+ assertEquals( "app", sourceMapperConfig.getOwner());
+ assertEquals( "[a-Z+]", sourceMapperConfig.getRegexExpression());
+ assertThat( sourceMapperConfig.getTypeMapping(), hasEntry("PACKAGE BODY", "sql"));
+ assertThat( sourceMapperConfig.getTypeMapping(), hasEntry("PACKAGE", "pks"));
+ assertEquals( 0, sourceMapperConfig.getOwnerSubexpression());
+ assertEquals( 1, sourceMapperConfig.getTypeSubexpression());
+ assertEquals( 3, sourceMapperConfig.getNameSubexpression());
+ }
+
+ @Test
+ void testFileMapping() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-test_path=src/test/resources/plsql/test",
+ "-owner=test_app",
+ "-regex_expression=\"test_regex\"",
+ "-type_mapping=\"tsql=PACKAGE BODY/tsql=FUNCTION\"",
+ "-owner_subexpression=4",
+ "-type_subexpression=5",
+ "-name_subexpression=6");
+
+ FileMapperConfig testMapperConfig = config.getTestMapping();
+ assertEquals( "src/test/resources/plsql/test", testMapperConfig.getPath());
+ assertEquals( "test_app", testMapperConfig.getOwner());
+ assertEquals( "test_regex", testMapperConfig.getRegexExpression());
+ assertThat( testMapperConfig.getTypeMapping(), hasEntry("PACKAGE BODY", "tsql"));
+ assertThat( testMapperConfig.getTypeMapping(), hasEntry("FUNCTION", "tsql"));
+ assertEquals( 4, testMapperConfig.getOwnerSubexpression());
+ assertEquals( 5, testMapperConfig.getTypeSubexpression());
+ assertEquals( 6, testMapperConfig.getNameSubexpression());
+ }
+
+ @Test
+ void testFileMappingWithoutDetails() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "-test_path=src/test/resources/plsql/test");
+
+ FileMapperConfig testMapperConfig = config.getTestMapping();
+ assertEquals( "src/test/resources/plsql/test", testMapperConfig.getPath());
+ assertNull( testMapperConfig.getOwner());
+ assertNull( testMapperConfig.getRegexExpression());
+ assertThat( testMapperConfig.getTypeMapping(), anEmptyMap());
+ assertNull( testMapperConfig.getOwnerSubexpression());
+ assertNull( testMapperConfig.getTypeSubexpression());
+ assertNull( testMapperConfig.getNameSubexpression());
+ }
+
+ @Test
+ void negatedTag() throws Exception {
+ RunCommandConfig config = parseForConfig("run",
+ TestHelper.getConnectionString(),
+ "--tags=\"-dontwantit\"");
+
+ assertThat(config.getTags(), hasItemInArray("-dontwantit") );
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/ReportersCommandIT.java b/src/test/java/org/utplsql/cli/ReportersCommandIT.java
new file mode 100644
index 0000000..1bf443f
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/ReportersCommandIT.java
@@ -0,0 +1,16 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ReportersCommandIT {
+
+ @Test
+ void callReportersWorks() {
+
+ int result = TestHelper.runApp("reporters", TestHelper.getConnectionString());
+
+ assertEquals(0, result);
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/RunCommandArgumentsTest.java b/src/test/java/org/utplsql/cli/RunCommandArgumentsTest.java
new file mode 100644
index 0000000..63be6e2
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/RunCommandArgumentsTest.java
@@ -0,0 +1,81 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.utplsql.api.TestRunner;
+
+import java.util.ArrayList;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+
+public class RunCommandArgumentsTest {
+
+ @Test
+ @DisplayName("All arguments are recognized")
+ public void allArgumentsAreRecognized() {
+ IRunCommand runCmd = TestHelper.createRunCommand(TestHelper.getConnectionString(),
+ "-p=app",
+ "-f=ut_sonar_test_reporter",
+ "-o=sonar_result.xml",
+ "-s",
+ "--tags=tag1,tag2",
+ "--coverage-schemes=schema1,some_other_schema",
+ "-d",
+ "-c",
+ "--failure-exit-code=10",
+ "-scc",
+ "-t=60",
+ "-exclude=app.betwnstr",
+ "-include=app.betwnstr",
+ "-source_path=src/test/resources/plsql/source",
+ "-owner=app",
+ "-regex_expression=\"*\"",
+ "-type_mapping=\"sql=PACKAGE BODY\"",
+ "-owner_subexpression=0",
+ "-type_subexpression=0",
+ "-name_subexpression=0",
+ "-test_path=src/test/resources/plsql/test",
+ "-owner=app",
+ "-regex_expression=\"*\"",
+ "-type_mapping=\"sql=PACKAGE BODY\"",
+ "-owner_subexpression=0",
+ "-type_subexpression=0",
+ "-name_subexpression=0",
+ "--ora-stuck-timeout=2"
+ );
+
+ TestRunner testRunner = runCmd.newTestRunner(new ArrayList<>());
+ }
+
+ @Test
+ void multiplePaths() {
+ IRunCommand runCmd = TestHelper.createRunCommand(TestHelper.getConnectionString(),
+ "-p=app.test_betwnstr,app.test_award_bonus"
+ );
+
+ TestRunner testRunner = runCmd.newTestRunner(new ArrayList<>());
+ assertThat( testRunner.getOptions().pathList, contains("app.test_betwnstr", "app.test_award_bonus") );
+
+ }
+
+ @Test
+ void provideTags() {
+ IRunCommand runCmd = TestHelper.createRunCommand(TestHelper.getConnectionString(),
+ "--tags=tag1,tag.2"
+ );
+
+ TestRunner testRunner = runCmd.newTestRunner(new ArrayList<>());
+ assertThat( testRunner.getOptions().tags, contains("tag1", "tag.2") );
+ }
+
+ @Test
+ void provideCoverageSchemes() {
+ IRunCommand runCmd = TestHelper.createRunCommand(TestHelper.getConnectionString(),
+ "--coverage-schemes=schema-1,some_other_schema"
+ );
+
+ TestRunner testRunner = runCmd.newTestRunner(new ArrayList<>());
+ assertThat( testRunner.getOptions().coverageSchemes, contains("schema-1", "some_other_schema") );
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/RunCommandConfigLevelTest.java b/src/test/java/org/utplsql/cli/RunCommandConfigLevelTest.java
new file mode 100644
index 0000000..b677ed2
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/RunCommandConfigLevelTest.java
@@ -0,0 +1,39 @@
+package org.utplsql.cli;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class RunCommandConfigLevelTest {
+
+ private Logger getRootLogger() {
+ return (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ }
+
+ @Test
+ void defaultIsInfo() {
+ TestHelper.createRunCommand(TestHelper.getConnectionString())
+ .initLogger();
+
+ assertEquals(Level.INFO, getRootLogger().getLevel());
+ }
+
+ @Test
+ void silentModeSetsLoggerToOff() {
+ TestHelper.createRunCommand(TestHelper.getConnectionString(), "-q")
+ .initLogger();
+
+ assertEquals(Level.OFF, getRootLogger().getLevel());
+ }
+
+ @Test
+ void debugModeSetsLoggerToDebug() {
+ TestHelper.createRunCommand(TestHelper.getConnectionString(), "-d")
+ .initLogger();
+
+ assertEquals(Level.DEBUG, getRootLogger().getLevel());
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/RunCommandConfigParamsArePassedToTestRunnerTest.java b/src/test/java/org/utplsql/cli/RunCommandConfigParamsArePassedToTestRunnerTest.java
new file mode 100644
index 0000000..95d146a
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/RunCommandConfigParamsArePassedToTestRunnerTest.java
@@ -0,0 +1,42 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+import org.utplsql.api.TestRunner;
+import org.utplsql.cli.config.RunCommandConfig;
+
+import java.util.ArrayList;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class RunCommandConfigParamsArePassedToTestRunnerTest {
+
+ @Test
+ void tags() {
+ RunCommandConfig config = new RunCommandConfig.Builder()
+ .tags(new String[]{"tag1", "tag2"})
+ .create();
+ TestRunner testRunner = new RunAction(config).newTestRunner(new ArrayList<>());
+ assertThat( testRunner.getOptions().tags, contains("tag1", "tag2") );
+ }
+
+ @Test
+ void coverageSchemes() {
+ RunCommandConfig config = new RunCommandConfig.Builder()
+ .coverageSchemes(new String[]{"schema1", "another_schema", "and-another-one"})
+ .create();
+ TestRunner testRunner = new RunAction(config).newTestRunner(new ArrayList<>());
+ assertThat( testRunner.getOptions().coverageSchemes, contains("schema1", "another_schema", "and-another-one") );
+ }
+
+ @Test
+ void oraStuckTimeout() {
+ RunCommandConfig config = new RunCommandConfig.Builder()
+ .oraStuckTimeout(2)
+ .create();
+ TestRunner testRunner = new RunAction(config).newTestRunner(new ArrayList<>());
+ assertThat( testRunner.getOptions().oraStuckTimeout, equalTo(2) );
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/RunCommandCoverageReporterIT.java b/src/test/java/org/utplsql/cli/RunCommandCoverageReporterIT.java
new file mode 100644
index 0000000..e95dce2
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/RunCommandCoverageReporterIT.java
@@ -0,0 +1,134 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * System tests for Code Coverage Reporter
+ *
+ * @author pesse
+ */
+class RunCommandCoverageReporterIT extends AbstractFileOutputTest {
+
+ private static final Pattern REGEX_COVERAGE_TITLE = Pattern.compile("([a-zA-Z ]+ )?([a-zA-Z0-9\\._]+)<\\/a>");
+
+
+ private String getTempCoverageFileName(int counter) {
+
+ return "tmpCoverage_" + System.currentTimeMillis() + "_" + counter + ".html";
+ }
+
+ /**
+ * Returns a random filename which does not yet exist on the local path
+ *
+ * @return
+ */
+ private Path getTempCoverageFilePath() {
+
+ int i = 1;
+ Path p = Paths.get(getTempCoverageFileName(i));
+
+ while ((Files.exists(p) || tempPathExists(p)) && i < 100)
+ p = Paths.get(getTempCoverageFileName(i++));
+
+ if (i >= 100)
+ throw new IllegalStateException("Could not get temporary file for coverage output");
+
+ addTempPath(p);
+ addTempPath(Paths.get(p.toString()+"_assets"));
+
+ return p;
+ }
+
+ /**
+ * Checks Coverage HTML Output if a given packageName is listed
+ *
+ * @param content
+ * @param packageName
+ * @return
+ */
+ private boolean hasCoverageListed(String content, String packageName) {
+ Matcher m = REGEX_COVERAGE_TITLE.matcher(content);
+
+ while (m.find()) {
+ if (packageName.equals(m.group(2)))
+ return true;
+ }
+
+ return false;
+ }
+
+ @Test
+ void run_CodeCoverageWithIncludeAndExclude() throws Exception {
+
+ Path coveragePath = getTempCoverageFilePath();
+
+ int result = TestHelper.runApp("run", TestHelper.getConnectionString(),
+ "-f=ut_coverage_html_reporter", "-o=" + coveragePath, "-s", "-exclude=app.award_bonus,app.betwnstr");
+
+
+ String content = new String(Files.readAllBytes(coveragePath));
+
+ assertTrue(hasCoverageListed(content, "app.remove_rooms_by_name"));
+ assertFalse(hasCoverageListed(content, "app.award_bonus"));
+ assertFalse(hasCoverageListed(content, "app.betwnstr"));
+
+ }
+
+ @Test
+ void coverageReporterWriteAssetsToOutput() throws Exception {
+ Path coveragePath = getTempCoverageFilePath();
+ Path coverageAssetsPath = Paths.get(coveragePath.toString() + "_assets");
+
+ TestHelper.runApp("run", TestHelper.getConnectionString(),
+ "-f=ut_coverage_html_reporter", "-o=" + coveragePath, "-s");
+
+ // Run twice to test overriding of assets
+ TestHelper.runApp("run", TestHelper.getConnectionString(),
+ "-f=ut_coverage_html_reporter", "-o=" + coveragePath, "-s");
+
+
+ // Check application file exists
+ File applicationJs = coverageAssetsPath.resolve(Paths.get("application.js")).toFile();
+ assertTrue(applicationJs.exists());
+
+ // Check correct script-part in HTML source exists
+ String content = new String(Files.readAllBytes(coveragePath));
+ assertTrue(content.contains("