diff --git a/sqldev/pom.xml b/sqldev/pom.xml
index f04528cb..86c63539 100644
--- a/sqldev/pom.xml
+++ b/sqldev/pom.xml
@@ -5,135 +5,140 @@
org.utplsql
org.utplsql.sqldev
- 1.1.2-SNAPSHOT
+ 1.2.0-SNAPSHOT
bundle
UTF-8
1.8
1.8
- 2.20.0
/Applications/SQLDeveloper19.4.0.app/Contents/Resources/sqldeveloper
utplsql_for_SQLDev_${project.version}
+
+
+ -noverify -Djava.util.logging.config.file=${project.basedir}/src/test/resources/logging.conf
-
+
+
+
+
oracle
idert
- 12.2.0
+ 13.0.0
system
${sqldev.basedir}/ide/lib/idert.jar
oracle
javatools-nodeps
- 12.2.0
+ 13.0.0
system
${sqldev.basedir}/modules/oracle.javatools/javatools-nodeps.jar
oracle
javatools
- 12.2.0
+ 13.0.0
system
${sqldev.basedir}/ide/lib/javatools.jar
oracle
oracle.ide.ceditor
- 12.2.0
+ 13.0.0
system
${sqldev.basedir}/ide/extensions/oracle.ide.ceditor.jar
oracle
oracle.ide
- 12.2.0
+ 13.0.0
system
${sqldev.basedir}/ide/extensions/oracle.ide.jar
oracle
uic
- 12.2.2
+ 13.0.0
system
${sqldev.basedir}/ide/lib/uic.jar
oracle
oracle.ide.navigator
- 12.2.0
+ 13.0.0
system
${sqldev.basedir}/ide/extensions/oracle.ide.navigator.jar
oracle
javax-ide
- 12.2.0
+ 13.0.0
system
${sqldev.basedir}/ide/lib/javax-ide.jar
oracle
oracle.dbtools-common
- 12.2.0
+ 19.4.0
system
${sqldev.basedir}/sqldeveloper/lib/dbtools-common.jar
oracle
oracle.sqldeveloper
- 12.2.0
+ 19.3.0
system
${sqldev.basedir}/sqldeveloper/extensions/oracle.sqldeveloper.jar
oracle
oracle.sqldeveloper.utils
- 12.2.0
+ 19.3.0
system
${sqldev.basedir}/sqldeveloper/extensions/oracle.sqldeveloper.utils.jar
oracle
oracle.sqldeveloper.worksheet
- 12.2.0
+ 19.3.0
system
${sqldev.basedir}/sqldeveloper/extensions/oracle.sqldeveloper.worksheet.jar
oracle
ojdbc8
- 12.2.0.1.0
+ 19.3.0
system
${sqldev.basedir}/jdbc/lib/ojdbc8.jar
oracle
dbapi
- 12.2.1
+ 19.3.0
system
${sqldev.basedir}/ide/lib/dbapi.jar
oracle
oracle.ide.db
- 12.2.1
+ 19.3.0
system
${sqldev.basedir}/ide/extensions/oracle.ide.db.jar
oracle
oracle.jdeveloper.db.connection
- 12.2.1
+ 19.3.0
system
${sqldev.basedir}/jdev/extensions/oracle.jdeveloper.db.connection.jar
oracle
oracle.jdeveloper.java.core.jar
- 12.2.1
+ 13.0.0
system
${sqldev.basedir}/jdev/extensions/oracle.jdeveloper.java.core.jar
@@ -141,14 +146,14 @@
oracle
jewt4.jar
- 12.2.1
+ 13.0.0
system
${sqldev.basedir}/modules/oracle.bali.jewt/jewt4.jar
oracle
share.jar
- 12.2.1
+ 13.0.0
system
${sqldev.basedir}/modules/oracle.bali.share/share.jar
@@ -162,22 +167,19 @@
-
- org.eclipse.xtend
- org.eclipse.xtend.lib
- ${xtend.version}
-
-
+
org.springframework
spring-jdbc
- 5.2.4.RELEASE
+ 5.2.6.RELEASE
+
org.springframework
spring-web
- 5.2.4.RELEASE
+ 5.2.6.RELEASE
+
org.oddgen
org.oddgen.sqldev
0.3.1
@@ -204,34 +206,6 @@
-
- org.eclipse.xtend
- xtend-maven-plugin
-
- ${xtend.version}
-
-
- main
-
- compile
-
-
- ${jdk.version}
- ${project.basedir}/src/main/xtend-gen
-
-
-
- test
-
- testCompile
-
-
- ${jdk.version.test}
- ${project.basedir}/src/test/xtend-gen
-
-
-
-
org.apache.maven.plugins
3.8.1
@@ -266,9 +240,7 @@
maven-surefire-plugin
2.22.2
-
- -noverify
- -Djava.util.logging.config.file=${project.basedir}/src/test/resources/logging.conf
+
**/*.java
@@ -296,7 +268,7 @@
org.apache.maven.plugins
maven-antrun-plugin
- 1.8
+ 3.0.0
prepare-package
@@ -424,13 +396,13 @@
org.utplsql.sqldev.resources
<_exportcontents>
- org.eclipse.xtext.xbase.lib,
org.aspectj.runtime.internal,
org.aspectj.lang,
org.aspectj.runtime,
org.aspectj.lang.reflect
+ oracle.javatools,
oracle.javatools-nodeps,
oracle.jdeveloper.db.connection,
oracle.idert,
@@ -450,7 +422,7 @@
maven-assembly-plugin
- 3.2.0
+ 3.3.0
${final.name}
false
@@ -472,7 +444,7 @@
net.nicoulaj.maven.plugins
checksum-maven-plugin
- 1.8
+ 1.9
calculate-checksums
@@ -483,10 +455,30 @@
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.5
+
+
+
+ prepare-agent
+
+
+
+ report
+ prepare-package
+
+ report
+
+
+
+
+
org.eclipse.m2e
lifecycle-mapping
1.0.0
@@ -497,7 +489,7 @@
org.apache.maven.plugins
maven-dependency-plugin
- [3.1.1,)
+ [3.1.2,)
copy-dependencies
@@ -515,7 +507,7 @@
build-helper-maven-plugin
- [3.0.0,)
+ [3.1.0,)
parse-version
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/coverage/CodeCoverageReporter.java b/sqldev/src/main/java/org/utplsql/sqldev/coverage/CodeCoverageReporter.java
new file mode 100644
index 00000000..c00a0473
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/coverage/CodeCoverageReporter.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.coverage;
+
+import java.awt.Desktop;
+import java.io.File;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.utplsql.sqldev.dal.UtplsqlDao;
+import org.utplsql.sqldev.exception.GenericDatabaseAccessException;
+import org.utplsql.sqldev.exception.GenericRuntimeException;
+import org.utplsql.sqldev.model.DatabaseTools;
+import org.utplsql.sqldev.model.FileTools;
+import org.utplsql.sqldev.ui.coverage.CodeCoverageReporterDialog;
+
+public class CodeCoverageReporter {
+ private static final Logger logger = Logger.getLogger(CodeCoverageReporter.class.getName());
+
+ private Connection conn;
+ private List pathList;
+ private List includeObjectList;
+ private CodeCoverageReporterDialog frame;
+ private String schemas;
+ private String includeObjects;
+ private String excludeObjects;
+
+ public CodeCoverageReporter(final List pathList, final List includeObjectList,
+ final String connectionName) {
+ this.pathList = pathList;
+ this.includeObjectList = includeObjectList;
+ setConnection(connectionName);
+ }
+
+ public CodeCoverageReporter(final List pathList, final List includeObjectList,
+ final Connection conn) {
+ this.pathList = pathList;
+ this.includeObjectList = includeObjectList;
+ this.conn = conn;
+ }
+
+ private void setConnection(final String connectionName) {
+ if (connectionName == null) {
+ final String msg = "Cannot initialize a CodeCoverageReporter without a ConnectionName";
+ logger.severe(() -> msg);
+ throw new NullPointerException();
+ } else {
+ // must be closed manually
+ conn = DatabaseTools.cloneConnection(connectionName);
+ }
+ }
+
+ private ArrayList toStringList(final String s) {
+ final ArrayList list = new ArrayList<>();
+ if (s != null && !s.isEmpty()) {
+ for (final String item : s.split(",")) {
+ if (!item.isEmpty()) {
+ list.add(item.trim());
+ }
+ }
+ }
+ return list;
+ }
+
+ private void run() {
+ logger.fine(() -> "Running code coverage reporter for " + pathList + "...");
+ try {
+ final UtplsqlDao dal = new UtplsqlDao(conn);
+ final String content = dal.htmlCodeCoverage(pathList, toStringList(schemas),
+ toStringList(includeObjects), toStringList(excludeObjects));
+ final File file = File.createTempFile("utplsql_", ".html");
+ logger.fine(() -> "Writing result to " + file + "...");
+ FileTools.writeFile(file.toPath(), Arrays.asList(content.split(System.lineSeparator())), StandardCharsets.UTF_8);
+ final URL url = file.toURI().toURL();
+ logger.fine(() -> "Opening " + url.toExternalForm() + " in browser...");
+ final Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
+ if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE) && url != null) {
+ desktop.browse(url.toURI());
+ logger.fine(() -> url.toExternalForm() + " opened in browser.");
+ } else {
+ logger.severe(
+ () -> "Could not launch " + file + "in browser. No default browser defined on this system.");
+ }
+ } catch (Exception e) {
+ final String msg = "Error while running code coverage for " + pathList + ".";
+ logger.severe(() -> msg);
+ throw new GenericRuntimeException(msg, e);
+ } finally {
+ try {
+ DatabaseTools.closeConnection(conn);
+ } catch (GenericDatabaseAccessException e) {
+ // ignore
+ }
+ if (frame != null) {
+ frame.exit();
+ }
+ }
+ }
+
+ public void setFrame(final CodeCoverageReporterDialog frame) {
+ this.frame = frame;
+ }
+
+ public CodeCoverageReporterDialog getFrame() {
+ return frame;
+ }
+
+ public Connection getConnection() {
+ return conn;
+ }
+
+ public List getPathList() {
+ return pathList;
+ }
+
+ public List getIncludeObjectList() {
+ if (includeObjectList == null) {
+ return new ArrayList<>();
+ } else {
+ return includeObjectList;
+ }
+ }
+
+ public void setSchemas(final String schemas) {
+ this.schemas = schemas;
+ }
+
+ public void setIncludeObjects(final String includeObjects) {
+ this.includeObjects = includeObjects;
+ }
+
+ public void setExcludeObjects(final String excludeObjects) {
+ this.excludeObjects = excludeObjects;
+ }
+
+ public Thread runAsync() {
+ final Thread thread = new Thread(() -> {
+ run();
+ });
+ thread.setName("code coverage reporter");
+ thread.start();
+ return thread;
+ }
+
+ public void showParameterWindow() {
+ CodeCoverageReporterDialog.createAndShow(this);
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/coverage/CodeCoverageReporter.xtend b/sqldev/src/main/java/org/utplsql/sqldev/coverage/CodeCoverageReporter.xtend
deleted file mode 100644
index 1b4acb50..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/coverage/CodeCoverageReporter.xtend
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.coverage
-
-import java.awt.Desktop
-import java.io.File
-import java.net.URL
-import java.nio.charset.StandardCharsets
-import java.nio.file.Files
-import java.nio.file.Paths
-import java.sql.Connection
-import java.util.ArrayList
-import java.util.List
-import java.util.logging.Logger
-import oracle.dbtools.raptor.utils.Connections
-import org.utplsql.sqldev.dal.UtplsqlDao
-import org.utplsql.sqldev.ui.coverage.CodeCoverageReporterDialog
-
-class CodeCoverageReporter {
- static val Logger logger = Logger.getLogger(CodeCoverageReporter.name);
-
- var Connection conn
- var List pathList
- var List includeObjectList
- var CodeCoverageReporterDialog frame
- var String schemas
- var String includeObjects
- var String excludeObjects
-
- new(List pathList, List includeObjectList, String connectionName) {
- this.pathList = pathList
- this.includeObjectList = includeObjectList
- setConnection(connectionName)
- }
-
- new(List pathList, List includeObjectList, Connection conn) {
- this.pathList = pathList
- this.includeObjectList = includeObjectList
- this.conn = conn
- }
-
- private def setConnection(String connectionName) {
- if (connectionName === null) {
- throw new RuntimeException("Cannot initialize a CodeCoverageReporter without a ConnectionName")
- } else {
- // must be closed manually
- this.conn = Connections.instance.cloneConnection(Connections.instance.getConnection(connectionName))
- }
- }
-
- private def toStringList(String s) {
- val list = new ArrayList
- if (s !== null && !s.empty) {
- for (item : s.split(",")) {
- if (!item.empty) {
- list.add(item.trim)
- }
- }
- }
- return list
- }
-
- private def void run() {
- try {
- logger.fine('''Running code coverage reporter for «pathList»...''')
- val dal = new UtplsqlDao(conn)
- val content = dal.htmlCodeCoverage(pathList, toStringList(schemas), toStringList(includeObjects), toStringList(excludeObjects))
- val file = File.createTempFile("utplsql_", ".html")
- logger.fine('''Writing result to «file.absolutePath»...''')
- Files.write(Paths.get(file.absolutePath), content.split(System.lineSeparator), StandardCharsets.UTF_8);
- val url = file.toURI().toURL().toExternalForm()
- logger.fine('''Opening «url» in browser...''')
- val Desktop desktop = if (Desktop.isDesktopSupported()) {Desktop.getDesktop()} else {null}
- if (desktop !== null && desktop.isSupported(Desktop.Action.BROWSE) && url !== null) {
- desktop.browse((new URL(url)).toURI)
- logger.fine(url + " opened in browser.");
- } else {
- logger.severe('''Could not launch «file» in browser. No default browser defined on this system.''')
- }
- } catch (Exception e) {
- logger.severe('''Error when running code coverage: «e?.message»''')
- }
- finally {
- conn.close
- if (frame !== null) {
- frame.exit
- }
- }
- }
-
- def setFrame(CodeCoverageReporterDialog frame) {
- this.frame = frame;
- }
-
- def getFrame() {
- return this.frame
- }
-
- def getConnection() {
- return conn
- }
-
- def getPathList() {
- return pathList
- }
-
- def getIncludeObjectList() {
- if (includeObjectList === null) {
- return new ArrayList
- } else {
- return includeObjectList
- }
- }
-
- def setSchemas(String schemas) {
- this.schemas = schemas
- }
-
- def setIncludeObjects(String includeObjects) {
- this.includeObjects = includeObjects
- }
-
- def setExcludeObjects(String excludeObjects) {
- this.excludeObjects = excludeObjects
- }
-
- def Thread runAsync() {
- val Runnable runnable = [|run]
- val thread = new Thread(runnable)
- thread.name = "code coverage reporter"
- thread.start
- return thread
- }
-
- def showParameterWindow() {
- CodeCoverageReporterDialog.createAndShow(this)
- }
-
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterDao.java b/sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterDao.java
new file mode 100644
index 00000000..87be783c
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterDao.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.dal;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.xml.parsers.DocumentBuilder;
+
+import org.springframework.jdbc.core.CallableStatementCallback;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.SingleConnectionDataSource;
+import org.utplsql.sqldev.exception.GenericRuntimeException;
+import org.utplsql.sqldev.model.StringTools;
+import org.utplsql.sqldev.model.XMLTools;
+import org.utplsql.sqldev.model.runner.Counter;
+import org.utplsql.sqldev.model.runner.Expectation;
+import org.utplsql.sqldev.model.runner.PostEvent;
+import org.utplsql.sqldev.model.runner.PostRunEvent;
+import org.utplsql.sqldev.model.runner.PostSuiteEvent;
+import org.utplsql.sqldev.model.runner.PostTestEvent;
+import org.utplsql.sqldev.model.runner.PreRunEvent;
+import org.utplsql.sqldev.model.runner.PreSuiteEvent;
+import org.utplsql.sqldev.model.runner.PreTestEvent;
+import org.utplsql.sqldev.model.runner.RealtimeReporterEvent;
+import org.utplsql.sqldev.model.runner.Suite;
+import org.utplsql.sqldev.model.runner.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import oracle.jdbc.OracleTypes;
+
+public class RealtimeReporterDao {
+ private static final Logger logger = Logger.getLogger(RealtimeReporterDao.class.getName());
+ private static final int FIRST_VERSION_WITH_REALTIME_REPORTER = 3001004;
+ private final XMLTools xmlTools = new XMLTools();
+ private Connection conn;
+ private JdbcTemplate jdbcTemplate;
+
+ public RealtimeReporterDao(final Connection conn) {
+ this.conn = conn;
+ jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, true));
+ jdbcTemplate.setFetchSize(1);
+ }
+
+ public boolean isSupported() {
+ return new UtplsqlDao(conn)
+ .normalizedUtPlsqlVersionNumber() >= RealtimeReporterDao.FIRST_VERSION_WITH_REALTIME_REPORTER;
+ }
+
+ public void produceReport(final String reporterId, final List pathList) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("DECLARE\n");
+ sb.append(" l_reporter ut_realtime_reporter := ut_realtime_reporter();\n");
+ sb.append("BEGIN\n");
+ sb.append(" l_reporter.set_reporter_id(?);\n");
+ sb.append(" l_reporter.output_buffer.init();\n");
+ sb.append(" sys.dbms_output.enable(NULL);\n");
+ sb.append(" ut_runner.run(\n");
+ sb.append(" a_paths => ut_varchar2_list(\n");
+ sb.append(StringTools.getCSV(pathList, 24));
+ sb.append(" ),\n");
+ sb.append(" a_reporters => ut_reporters(l_reporter)\n");
+ sb.append(" );\n");
+ sb.append(" sys.dbms_output.disable;\n");
+ sb.append("END;");
+ final String plsql = sb.toString();
+ final Object[] binds = { reporterId };
+ jdbcTemplate.update(plsql, binds);
+ }
+
+ public void consumeReport(final String reporterId, final RealtimeReporterEventConsumer consumer) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("DECLARE\n");
+ sb.append(" l_reporter ut_realtime_reporter := ut_realtime_reporter();\n");
+ sb.append("BEGIN\n");
+ sb.append(" l_reporter.set_reporter_id(?);\n");
+ sb.append(" ? := l_reporter.get_lines_cursor();\n");
+ sb.append("END;");
+ final String plsql = sb.toString();
+ jdbcTemplate.execute(plsql, new CallableStatementCallback() {
+ @Override
+ public Void doInCallableStatement(final CallableStatement cs) throws SQLException {
+ cs.setString(1, reporterId);
+ cs.registerOutParameter(2, OracleTypes.CURSOR);
+ cs.execute();
+ final ResultSet rs = ((ResultSet) cs.getObject(2));
+ while (rs.next()) {
+ final String itemType = rs.getString("item_type");
+ final Clob textClob = rs.getClob("text");
+ final String textString = textClob.getSubString(1, ((int) textClob.length()));
+ final RealtimeReporterEvent event = convert(itemType, textString);
+ if (event != null) {
+ consumer.process(event);
+ }
+ }
+ rs.close();
+ return null;
+ }
+ });
+ }
+
+ private RealtimeReporterEvent convert(final String itemType, final String text) {
+ logger.fine(() -> "\n---- " + itemType + " ----\n" + text);
+ try {
+ final DocumentBuilder docBuilder = xmlTools.createDocumentBuilder();
+ final Document doc = docBuilder.parse(new InputSource(new StringReader(text)));
+ RealtimeReporterEvent event = null;
+ if ("pre-run".equals(itemType)) {
+ event = convertToPreRunEvent(doc);
+ } else if ("post-run".equals(itemType)) {
+ event = convertToPostRunEvent(doc);
+ } else if ("pre-suite".equals(itemType)) {
+ event = convertToPreSuiteEvent(doc);
+ } else if ("post-suite".equals(itemType)) {
+ event = convertToPostSuiteEvent(doc);
+ } else if ("pre-test".equals(itemType)) {
+ event = convertToPreTestEvent(doc);
+ } else if ("post-test".equals(itemType)) {
+ event = convertToPostTestEvent(doc);
+ }
+ return event;
+ } catch (SAXException e) {
+ final String msg = "Parse error while processing " + itemType + " with content: " + text;
+ logger.severe(() -> msg);
+ throw new GenericRuntimeException(msg, e);
+ } catch (IOException e) {
+ final String msg = "I/O error while processing " + itemType + " with content: " + text;
+ logger.severe(() -> msg);
+ throw new GenericRuntimeException(msg, e);
+ }
+ }
+
+ private RealtimeReporterEvent convertToPreRunEvent(final Document doc) {
+ final PreRunEvent event = new PreRunEvent();
+ final Node totalNumberOfTestsNode = xmlTools.getNode(doc, "/event/totalNumberOfTests");
+ String totalNumberOfTestsTextContent = null;
+ if (totalNumberOfTestsNode != null) {
+ totalNumberOfTestsTextContent = totalNumberOfTestsNode.getTextContent();
+ }
+ event.setTotalNumberOfTests(Integer.valueOf(totalNumberOfTestsTextContent));
+ final NodeList nodes = xmlTools.getNodeList(doc, "/event/items/*");
+ for (int i = 0; i < nodes.getLength(); i++) {
+ final Node node = nodes.item(i);
+ final String nodeName = node.getNodeName();
+ if ("suite".equals(nodeName)) {
+ final Suite suite = new Suite();
+ event.getItems().add(suite);
+ populate(suite, node);
+ } else if ("test".equals(nodeName)) {
+ final Test test = new Test();
+ event.getItems().add(test);
+ populate(test, node);
+ }
+ }
+ return event;
+ }
+
+ private RealtimeReporterEvent convertToPostRunEvent(final Document doc) {
+ final PostRunEvent event = new PostRunEvent();
+ populate(event, xmlTools.getNode(doc, "/event/run"));
+ return event;
+ }
+
+ private RealtimeReporterEvent convertToPreSuiteEvent(final Document doc) {
+ final PreSuiteEvent event = new PreSuiteEvent();
+ final Node node = xmlTools.getNode(doc, "/event/suite");
+ if (node instanceof Element) {
+ event.setId(xmlTools.getAttributeValue(node, "id"));
+ }
+ return event;
+ }
+
+ private RealtimeReporterEvent convertToPostSuiteEvent(final Document doc) {
+ final PostSuiteEvent event = new PostSuiteEvent();
+ final Node node = xmlTools.getNode(doc, "/event/suite");
+ if (node instanceof Element) {
+ event.setId(xmlTools.getAttributeValue(node, "id"));
+ populate(event, node);
+ }
+ return event;
+ }
+
+ private RealtimeReporterEvent convertToPreTestEvent(final Document doc) {
+ final PreTestEvent event = new PreTestEvent();
+ final Node node = xmlTools.getNode(doc, "/event/test");
+ if (node instanceof Element) {
+ event.setId(xmlTools.getAttributeValue(node, "id"));
+ event.setTestNumber(Integer.valueOf(xmlTools.getElementValue(node, "testNumber")));
+ event.setTotalNumberOfTests(Integer.valueOf(xmlTools.getElementValue(node, "totalNumberOfTests")));
+ }
+ return event;
+ }
+
+ private RealtimeReporterEvent convertToPostTestEvent(final Document doc) {
+ final PostTestEvent event = new PostTestEvent();
+ final Node node = xmlTools.getNode(doc, "/event/test");
+ if (node instanceof Element) {
+ event.setId(xmlTools.getAttributeValue(node, "id"));
+ event.setTestNumber(Integer.valueOf(xmlTools.getElementValue(node, "testNumber")));
+ event.setTotalNumberOfTests(Integer.valueOf(xmlTools.getElementValue(node, "totalNumberOfTests")));
+ populate(event, node);
+ final NodeList failedExpectations = xmlTools.getNodeList(node, "failedExpectations/expectation");
+ for (int i = 0; i < failedExpectations.getLength(); i++) {
+ final Node expectationNode = failedExpectations.item(i);
+ final Expectation expectation = new Expectation();
+ event.getFailedExpectations().add(expectation);
+ populate(expectation, expectationNode);
+ }
+ }
+ return event;
+ }
+
+ private void populate(final Suite suite, final Node node) {
+ if (node instanceof Element) {
+ suite.setId(xmlTools.getAttributeValue(node, "id"));
+ suite.setName(xmlTools.getElementValue(node, "name"));
+ suite.setDescription(xmlTools.getElementValue(node, "description"));
+ final NodeList nodeList = xmlTools.getNodeList(node, "items/*");
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ final Node childNode = nodeList.item(i);
+ final String nodeName = childNode.getNodeName();
+ if ("suite".equals(nodeName)) {
+ final Suite childSuite = new Suite();
+ suite.getItems().add(childSuite);
+ populate(childSuite, childNode);
+ } else if ("test".equals(nodeName)) {
+ final Test childTest = new Test();
+ suite.getItems().add(childTest);
+ populate(childTest, childNode);
+ }
+ }
+ }
+ }
+
+ private void populate(final Test test, final Node node) {
+ if (node instanceof Element) {
+ test.setId(xmlTools.getAttributeValue(node, "id"));
+ test.setExecutableType(xmlTools.getElementValue(node, "executableType"));
+ test.setOwnerName(xmlTools.getElementValue(node, "ownerName"));
+ test.setObjectName(xmlTools.getElementValue(node, "objectName"));
+ test.setProcedureName(xmlTools.getElementValue(node, "procedureName"));
+ test.setDisabled("true".equals(xmlTools.getElementValue(node, "disabled")));
+ test.setName(xmlTools.getElementValue(node, "name"));
+ test.setDescription(xmlTools.getElementValue(node, "description"));
+ test.setTestNumber(Integer.valueOf(xmlTools.getElementValue(node, "testNumber")));
+ }
+ }
+
+ private void populate(final PostEvent event, final Node node) {
+ if (node instanceof Element) {
+ event.setStartTime(xmlTools.getElementValue(node, "startTime"));
+ event.setEndTime(xmlTools.getElementValue(node, "endTime"));
+ event.setExecutionTime(Double.valueOf(xmlTools.getElementValue(node, "executionTime")));
+ populate(event.getCounter(), node);
+ event.setErrorStack(xmlTools.getElementValue(node, "errorStack"));
+ event.setServerOutput(xmlTools.getElementValue(node, "serverOutput"));
+ event.setWarnings(xmlTools.getElementValue(node, "warnings"));
+ }
+ }
+
+ private void populate(final Counter counter, final Node node) {
+ if (node instanceof Element) {
+ final Node counterNode = xmlTools.getElementNode(node, "counter");
+ if (counterNode instanceof Element) {
+ counter.setDisabled(Integer.valueOf(xmlTools.getElementValue(counterNode, "disabled")));
+ counter.setSuccess(Integer.valueOf(xmlTools.getElementValue(counterNode, "success")));
+ counter.setFailure(Integer.valueOf(xmlTools.getElementValue(counterNode, "failure")));
+ counter.setError(Integer.valueOf(xmlTools.getElementValue(counterNode, "error")));
+ counter.setWarning(Integer.valueOf(xmlTools.getElementValue(counterNode, "warning")));
+ }
+ }
+ }
+
+ private void populate(final Expectation expectation, final Node node) {
+ if (node instanceof Element) {
+ expectation.setDescription(xmlTools.getElementValue(node, "description"));
+ expectation.setMessage(xmlTools.getElementValue(node, "message"));
+ expectation.setCaller(xmlTools.getElementValue(node, "caller"));
+ }
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterDao.xtend b/sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterDao.xtend
deleted file mode 100644
index 442027ac..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterDao.xtend
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.utplsql.sqldev.dal
-
-import java.io.StringReader
-import java.sql.CallableStatement
-import java.sql.Connection
-import java.sql.ResultSet
-import java.sql.SQLException
-import java.util.List
-import java.util.logging.Logger
-import javax.xml.parsers.DocumentBuilderFactory
-import oracle.jdbc.OracleTypes
-import org.springframework.dao.DataAccessException
-import org.springframework.jdbc.core.CallableStatementCallback
-import org.springframework.jdbc.core.JdbcTemplate
-import org.springframework.jdbc.datasource.SingleConnectionDataSource
-import org.utplsql.sqldev.model.XMLTools
-import org.utplsql.sqldev.model.runner.Counter
-import org.utplsql.sqldev.model.runner.Expectation
-import org.utplsql.sqldev.model.runner.PostEvent
-import org.utplsql.sqldev.model.runner.PostRunEvent
-import org.utplsql.sqldev.model.runner.PostSuiteEvent
-import org.utplsql.sqldev.model.runner.PostTestEvent
-import org.utplsql.sqldev.model.runner.PreRunEvent
-import org.utplsql.sqldev.model.runner.PreSuiteEvent
-import org.utplsql.sqldev.model.runner.PreTestEvent
-import org.utplsql.sqldev.model.runner.RealtimeReporterEvent
-import org.utplsql.sqldev.model.runner.Suite
-import org.utplsql.sqldev.model.runner.Test
-import org.w3c.dom.Document
-import org.w3c.dom.Element
-import org.w3c.dom.Node
-import org.xml.sax.InputSource
-
-class RealtimeReporterDao {
- static val Logger logger = Logger.getLogger(RealtimeReporterDao.name);
- static val FIRST_VERSION_WITH_REALTIME_REPORTER = 3001004
- val extension XMLTools xmlTools = new XMLTools
- var Connection conn
- var JdbcTemplate jdbcTemplate
-
- new(Connection connection) {
- conn = connection
- jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, true))
- jdbcTemplate.fetchSize = 1
- }
-
- def isSupported() {
- return new UtplsqlDao(conn).normalizedUtPlsqlVersionNumber >= FIRST_VERSION_WITH_REALTIME_REPORTER
- }
-
- def produceReport(String reporterId, List pathList) {
- var plsql = '''
- DECLARE
- l_reporter ut_realtime_reporter := ut_realtime_reporter();
- BEGIN
- l_reporter.set_reporter_id(?);
- l_reporter.output_buffer.init();
- sys.dbms_output.enable(NULL);
- ut_runner.run(
- a_paths => ut_varchar2_list(
- «FOR path : pathList SEPARATOR ","»
- '«path»'
- «ENDFOR»
- ),
- a_reporters => ut_reporters(l_reporter)
- );
- sys.dbms_output.disable;
- END;
- '''
- jdbcTemplate.update(plsql, #[reporterId])
- }
-
- def consumeReport(String reporterId, RealtimeReporterEventConsumer consumer) {
- val plsql = '''
- DECLARE
- l_reporter ut_realtime_reporter := ut_realtime_reporter();
- BEGIN
- l_reporter.set_reporter_id(?);
- ? := l_reporter.get_lines_cursor();
- END;
- '''
- jdbcTemplate.execute(plsql, new CallableStatementCallback() {
- override doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
- cs.setString(1, reporterId)
- cs.registerOutParameter(2, OracleTypes.CURSOR)
- cs.execute
- val rs = cs.getObject(2) as ResultSet
- while(rs.next) {
- val itemType = rs.getString("item_type")
- val textClob = rs.getClob("text")
- val textString = textClob.getSubString(1, textClob.length as int)
- val event = convert(itemType, textString)
- if (event !== null) {
- consumer.process(event)
- }
- }
- rs.close
- return null
- }
- })
- }
-
- private def RealtimeReporterEvent convert(String itemType, String text) {
- logger.fine('''
- ---- «itemType» ----
- «text»
- ''')
- val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
- val doc = docBuilder.parse(new InputSource(new StringReader(text)))
- var RealtimeReporterEvent event
- if (itemType == "pre-run") {
- event = doc.convertToPreRunEvent
- } else if (itemType == "post-run") {
- event = doc.convertToPostRunEvent
- } else if (itemType == "pre-suite") {
- event = doc.convertToPreSuiteEvent
- } else if (itemType == "post-suite") {
- event = doc.convertToPostSuiteEvent
- } else if (itemType == "pre-test") {
- event = doc.convertToPreTestEvent
- } else if (itemType == "post-test") {
- event = doc.convertToPostTestEvent
- }
- return event
- }
-
- private def RealtimeReporterEvent convertToPreRunEvent(Document doc) {
- val event = new PreRunEvent
- event.totalNumberOfTests = Integer.valueOf(doc.getNode("/event/totalNumberOfTests")?.textContent)
- val nodeList = doc.getNodeList("/event/items/*")
- for (i : 0 ..< nodeList.length) {
- val node = nodeList.item(i)
- if (node.nodeName == "suite") {
- val suite = new Suite
- event.items.add(suite)
- suite.populate(node)
- } else if (node.nodeName == "test") {
- val test = new Test
- event.items.add(test)
- test.populate(node)
- }
- }
- return event
- }
-
- private def RealtimeReporterEvent convertToPostRunEvent(Document doc) {
- val event = new PostRunEvent
- event.populate(doc.getNode("/event/run"))
- return event
- }
-
- private def RealtimeReporterEvent convertToPreSuiteEvent(Document doc) {
- val event = new PreSuiteEvent
- val node = doc.getNode("/event/suite")
- if (node instanceof Element) {
- event.id = node.attributes?.getNamedItem("id")?.nodeValue
- }
- return event
- }
-
- private def RealtimeReporterEvent convertToPostSuiteEvent(Document doc) {
- val event = new PostSuiteEvent
- val node = doc.getNode("/event/suite")
- if (node instanceof Element) {
- event.id = node.attributes?.getNamedItem("id")?.nodeValue
- event.populate(node)
- }
- return event
- }
-
- private def RealtimeReporterEvent convertToPreTestEvent(Document doc) {
- val event = new PreTestEvent
- val node = doc.getNode("/event/test")
- if (node instanceof Element) {
- event.id = node.attributes?.getNamedItem("id")?.nodeValue
- event.testNumber = Integer.valueOf(node.getElementsByTagName("testNumber")?.item(0)?.textContent)
- event.totalNumberOfTests = Integer.valueOf(node.getElementsByTagName("totalNumberOfTests")?.item(0)?.textContent)
- }
- return event
- }
-
- private def RealtimeReporterEvent convertToPostTestEvent(Document doc) {
- val event = new PostTestEvent
- val node = doc.getNode("/event/test")
- if (node instanceof Element) {
- event.id = node.attributes?.getNamedItem("id")?.nodeValue
- event.testNumber = Integer.valueOf(node.getElementsByTagName("testNumber")?.item(0)?.textContent)
- event.totalNumberOfTests = Integer.valueOf(node.getElementsByTagName("totalNumberOfTests")?.item(0)?.textContent)
- event.populate(node)
- val failedExpectations = node.getNodeList("failedExpectations/expectation")
- for (i : 0 ..< failedExpectations.length) {
- val expectationNode = failedExpectations.item(i)
- val expectation = new Expectation
- event.failedExpectations.add(expectation)
- expectation.populate(expectationNode)
- }
- }
- return event
- }
-
- private def void populate(Suite suite, Node node) {
- if (node instanceof Element) {
- suite.id = node.attributes?.getNamedItem("id")?.nodeValue
- suite.name = node.getElementsByTagName("name")?.item(0)?.textContent
- suite.description = node.getElementsByTagName("description")?.item(0)?.textContent
- val nodeList = node.getNodeList("items/*")
- for (i : 0 ..< nodeList.length) {
- val childNode = nodeList.item(i)
- if (childNode.nodeName == "suite") {
- val childSuite = new Suite
- suite.items.add(childSuite)
- childSuite.populate(childNode)
- } else if (childNode.nodeName == "test") {
- val childTest = new Test
- suite.items.add(childTest)
- childTest.populate(childNode)
- }
- }
- }
- }
-
- private def void populate(Test test, Node node) {
- if (node instanceof Element) {
- test.id = node.attributes?.getNamedItem("id")?.nodeValue
- test.executableType = node.getElementsByTagName("executableType")?.item(0)?.textContent
- test.ownerName = node.getElementsByTagName("ownerName")?.item(0)?.textContent
- test.objectName = node.getElementsByTagName("objectName")?.item(0)?.textContent
- test.procedureName = node.getElementsByTagName("procedureName")?.item(0)?.textContent
- test.disabled = node.getElementsByTagName("disabled")?.item(0)?.textContent == "true"
- test.name = node.getElementsByTagName("name")?.item(0)?.textContent
- test.description = node.getElementsByTagName("description")?.item(0)?.textContent
- test.testNumber = Integer.valueOf(node.getElementsByTagName("testNumber")?.item(0)?.textContent)
- }
- }
-
- private def void populate(PostEvent event, Node node) {
- if (node instanceof Element) {
- event.startTime = node.getElementsByTagName("startTime")?.item(0)?.textContent
- event.endTime = node.getElementsByTagName("endTime")?.item(0)?.textContent
- event.executionTime = Double.valueOf(node.getElementsByTagName("executionTime")?.item(0)?.textContent)
- event.counter.populate(node)
- event.errorStack = node.getElementsByTagName("errorStack")?.item(0)?.textContent
- event.serverOutput = node.getElementsByTagName("serverOutput")?.item(0)?.textContent
- event.warnings = node.getElementsByTagName("warnings")?.item(0)?.textContent
- }
- }
-
- private def void populate(Counter counter, Node node) {
- if (node instanceof Element) {
- val counterNode = node.getElementsByTagName("counter")?.item(0)
- if (counterNode instanceof Element) {
- counter.disabled = Integer.valueOf(counterNode.getElementsByTagName("disabled")?.item(0)?.textContent)
- counter.success = Integer.valueOf(counterNode.getElementsByTagName("success")?.item(0)?.textContent)
- counter.failure = Integer.valueOf(counterNode.getElementsByTagName("failure")?.item(0)?.textContent)
- counter.error = Integer.valueOf(counterNode.getElementsByTagName("error")?.item(0)?.textContent)
- counter.warning = Integer.valueOf(counterNode.getElementsByTagName("warning")?.item(0)?.textContent)
- }
- }
- }
-
- private def void populate(Expectation expectation, Node node) {
- if (node instanceof Element) {
- expectation.description = node.getElementsByTagName("description")?.item(0)?.textContent
- expectation.message = node.getElementsByTagName("message")?.item(0)?.textContent
- expectation.caller = node.getElementsByTagName("caller")?.item(0)?.textContent
- }
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/AbstractModel.xtend b/sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterEventConsumer.java
similarity index 75%
rename from sqldev/src/main/java/org/utplsql/sqldev/model/AbstractModel.xtend
rename to sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterEventConsumer.java
index f4356033..65427f35 100644
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/AbstractModel.xtend
+++ b/sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterEventConsumer.java
@@ -13,12 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.utplsql.sqldev.model
+package org.utplsql.sqldev.dal;
-import org.eclipse.xtext.xbase.lib.util.ToStringBuilder
+import org.utplsql.sqldev.model.runner.RealtimeReporterEvent;
-abstract class AbstractModel {
- override toString() {
- new ToStringBuilder(this).addAllFields.toString
- }
+public interface RealtimeReporterEventConsumer {
+ public abstract void process(final RealtimeReporterEvent event);
}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.java b/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.java
new file mode 100644
index 00000000..be4d6d09
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.java
@@ -0,0 +1,1064 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.dal;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.oddgen.sqldev.generators.model.Node;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.CallableStatementCallback;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.SingleConnectionDataSource;
+import org.utplsql.sqldev.model.StringTools;
+import org.utplsql.sqldev.model.ut.Annotation;
+import org.utplsql.sqldev.model.ut.OutputLines;
+
+public class UtplsqlDao {
+ public static final String UTPLSQL_PACKAGE_NAME = "UT";
+ public static final int NOT_INSTALLED = 0;
+ public static final int FIRST_VERSION_WITH_INTERNAL_ANNOTATION_API = 3000004;
+ public static final int FIRST_VERSION_WITH_ANNOTATION_API = 3001003;
+ public static final int FIRST_VERSION_WITHOUT_INTERNAL_API = 3001008;
+ public static final int FIRST_VERSION_WITH_HAS_SUITES_API = 3001008;
+ private JdbcTemplate jdbcTemplate;
+ // cache fields
+ private Boolean cachedDbaViewAccessible;
+ private String cachedUtplsqlSchema;
+ private String cachedUtPlsqlVersion;
+
+ public UtplsqlDao(final Connection conn) {
+ jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, true));
+ }
+
+ /**
+ * used for testing purposes only
+ */
+ public void setUtPlsqlVersion(final String utPlsqlVersion) {
+ this.cachedUtPlsqlVersion = utPlsqlVersion;
+ }
+
+ /**
+ * returns a normalized utPLSQL version in format 9.9.9
+ */
+ public String normalizedUtPlsqlVersion() {
+ final String version = this.getUtPlsqlVersion();
+ if (version != null) {
+ final Pattern p = Pattern.compile("(\\d+\\.\\d+\\.\\d+)");
+ final Matcher m = p.matcher(version);
+ if (m.find()) {
+ return m.group(0);
+ }
+ }
+ return "0.0.0";
+ }
+
+ /**
+ * get version as number, e.g. 3001004
+ */
+ public int normalizedUtPlsqlVersionNumber() {
+ final Pattern p = Pattern.compile("(\\d+)");
+ final String version = this.normalizedUtPlsqlVersion();
+ final Matcher m = p.matcher(version);
+ m.find();
+ final String major = m.group();
+ m.find();
+ final String minor = m.group();
+ m.find();
+ final String bugfix = m.group();
+ return Integer.valueOf(major) * 1000000 + Integer.valueOf(minor) * 1000 + Integer.valueOf(bugfix);
+ }
+
+ /**
+ * gets version of installed utPLSQL
+ */
+ public String getUtPlsqlVersion() {
+ if (cachedUtPlsqlVersion == null) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("BEGIN\n");
+ sb.append(" ? := ut.version;\n");
+ sb.append("END;");
+ final String sql = sb.toString();
+ try {
+ cachedUtPlsqlVersion = jdbcTemplate.execute(sql, new CallableStatementCallback() {
+ @Override
+ public String doInCallableStatement(final CallableStatement cs) throws SQLException {
+ cs.registerOutParameter(1, Types.VARCHAR);
+ cs.execute();
+ return cs.getString(1);
+ }
+ });
+ } catch (DataAccessException e) {
+ // ignore error
+ }
+ }
+ return cachedUtPlsqlVersion;
+ }
+
+ public boolean isDbaViewAccessible() {
+ if (cachedDbaViewAccessible == null) {
+ try {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SELECT 1 AS dummy\n");
+ sb.append(" FROM dba_objects\n");
+ sb.append(" WHERE 1=2\n");
+ sb.append("UNION ALL\n");
+ sb.append("SELECT 1\n");
+ sb.append(" FROM dba_synonyms\n");
+ sb.append(" WHERE 1=2\n");
+ sb.append("UNION ALL\n");
+ sb.append("SELECT 1\n");
+ sb.append(" FROM dba_dependencies\n");
+ sb.append(" WHERE 1=2\n");
+ final String sql = sb.toString();
+ jdbcTemplate.execute(sql);
+ cachedDbaViewAccessible = true;
+ } catch (DataAccessException e) {
+ cachedDbaViewAccessible = false;
+ }
+ }
+ return cachedDbaViewAccessible.booleanValue();
+ }
+
+ public String getDbaView(String viewName) {
+ StringBuilder sb = new StringBuilder();
+ if (isDbaViewAccessible()) {
+ sb.append("dba");
+ } else {
+ sb.append("all");
+ }
+ sb.append("_");
+ sb.append(viewName);
+ return sb.toString();
+ }
+
+ /**
+ * Gets the schema name of the utPLSQL installation.
+ *
+ * @return utPLSQL schema or null if no utPLSQL is not installed
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public String getUtplsqlSchema() {
+ if (cachedUtplsqlSchema == null) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SELECT table_owner\n");
+ sb.append(" FROM ");
+ sb.append(getDbaView("synonyms\n"));
+ sb.append(" WHERE owner = 'PUBLIC'\n");
+ sb.append(" AND synonym_name = '");
+ sb.append(UtplsqlDao.UTPLSQL_PACKAGE_NAME);
+ sb.append("'\n");
+ sb.append(" AND table_name = '");
+ sb.append(UtplsqlDao.UTPLSQL_PACKAGE_NAME);
+ sb.append("'");
+ final String sql = sb.toString();
+ try {
+ final String schema = jdbcTemplate.queryForObject(sql, String.class);
+ cachedUtplsqlSchema = schema;
+ } catch (EmptyResultDataAccessException e) {
+ cachedUtplsqlSchema = null;
+ }
+ }
+ return cachedUtplsqlSchema;
+ }
+
+ /**
+ * Checks if the package ut_annotation_manager is installed. This package has
+ * been introduced with utPLSQL 3.0.4. This version is a prerequisite to
+ * identify utPLSQL unit test procedures.
+ *
+ * @return true if ut_annotation_manager package has been found
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public boolean isUtAnnotationManagerInstalled() {
+ return normalizedUtPlsqlVersionNumber() >= UtplsqlDao.FIRST_VERSION_WITH_INTERNAL_ANNOTATION_API;
+ }
+
+ /**
+ * Checks if utPLSQL tests exist
+ *
+ * @param owner
+ * schema name, mandatory, case-insensitive
+ * @param objectName
+ * name of the package or package body, optional, case-insensitive
+ * @param subobjectName
+ * name of the procedure, optional, case-insensitive
+ * @return true if at least one test has been found
+ * @throws DataAccessException
+ * if a utPLSQL version less than 3.0.4 is installed or if there are
+ * other problems
+ */
+ public boolean containsUtplsqlTest(final String owner, final String objectName, final String subobjectName) {
+ try {
+ if (normalizedUtPlsqlVersionNumber() >= UtplsqlDao.FIRST_VERSION_WITH_HAS_SUITES_API && objectName != null
+ && subobjectName != null) {
+ // use faster check function available since v3.1.3 (reliable in v3.1.8)
+ final StringBuilder sb = new StringBuilder();
+ sb.append("DECLARE\n");
+ sb.append(" l_return VARCHAR2(1) := '0';\n");
+ sb.append("BEGIN\n");
+ sb.append(" IF ut_runner.is_test(?, ?, ?) THEN\n");
+ sb.append(" l_return := '1';\n");
+ sb.append(" END IF;\n");
+ sb.append(" ? := l_return;\n");
+ sb.append("END;");
+ final String sql = sb.toString();
+ return jdbcTemplate.execute(sql, new CallableStatementCallback() {
+ @Override
+ public Boolean doInCallableStatement(final CallableStatement cs) throws SQLException {
+ cs.setString(1, owner);
+ cs.setString(2, objectName);
+ cs.setString(3, subobjectName);
+ cs.registerOutParameter(4, Types.VARCHAR);
+ cs.execute();
+ final String ret = cs.getString(4);
+ return "1".equals(ret);
+ }
+ });
+ } else if (normalizedUtPlsqlVersionNumber() >= FIRST_VERSION_WITH_ANNOTATION_API) {
+ // using API available since 3.1.3, can handle nulls in objectName and subobjectName
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT count(*)\n");
+ sb.append(" FROM TABLE(ut_runner.get_suites_info(upper(?), upper(?)))\n");
+ sb.append(" WHERE item_type IN ('UT_TEST', 'UT_SUITE')\n");
+ sb.append(" AND (item_name = upper(?) or ? IS NULL)\n");
+ final String sql = sb.toString();
+ final Object[] binds = new Object[] {owner, objectName, subobjectName, subobjectName};
+ final Integer found = jdbcTemplate.queryForObject(sql, Integer.class, binds);
+ return found > 0;
+ } else {
+ // using internal API (deprecated, not accessible in latest version)
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT count(\n");
+ sb.append(" CASE\n");
+ sb.append(" WHEN a.name = 'test'\n");
+ sb.append(" AND (upper(a.subobject_name) = upper(?) OR ? IS NULL)\n");
+ sb.append(" THEN\n");
+ sb.append(" 1\n");
+ sb.append(" ELSE\n");
+ sb.append(" NULL\n");
+ sb.append(" END\n");
+ sb.append(" )\n");
+ sb.append(" FROM TABLE(");
+ sb.append(getUtplsqlSchema());
+ sb.append(".ut_annotation_manager.get_annotated_objects(upper(?), 'PACKAGE')) o\n");
+ sb.append(" CROSS JOIN TABLE(o.annotations) a\n");
+ sb.append(" WHERE (o.object_name = upper(?) OR ? IS NULL)\n");
+ sb.append(" AND a.name IN ('test', 'suite')\n");
+ sb.append("HAVING count(\n");
+ sb.append(" CASE\n");
+ sb.append(" WHEN a.name = 'suite' THEN\n");
+ sb.append(" 1\n");
+ sb.append(" ELSE\n");
+ sb.append(" NULL\n");
+ sb.append(" END\n");
+ sb.append(" ) > 0");
+ final String sql = sb.toString();
+ final Object[] binds = new Object[] {subobjectName, subobjectName, owner, objectName, objectName};
+ final Integer found = jdbcTemplate.queryForObject(sql, Integer.class, binds);
+ return found > 0;
+ }
+ } catch (EmptyResultDataAccessException e) {
+ return false;
+ }
+ }
+
+ public boolean containsUtplsqlTest(final String owner) {
+ if (normalizedUtPlsqlVersionNumber() >= org.utplsql.sqldev.dal.UtplsqlDao.FIRST_VERSION_WITH_HAS_SUITES_API) {
+ // use faster check function available since v3.1.3 (reliable in v3.1.8)
+ StringBuilder sb = new StringBuilder();
+ sb.append("DECLARE\n");
+ sb.append(" l_return VARCHAR2(1) := '0';\n");
+ sb.append("BEGIN\n");
+ sb.append(" IF ut_runner.has_suites(?) THEN\n");
+ sb.append(" l_return := '1';\n");
+ sb.append(" END IF;\n");
+ sb.append(" ? := l_return;\n");
+ sb.append("END;");
+ final String sql = sb.toString();
+ return jdbcTemplate.execute(sql, new CallableStatementCallback() {
+ @Override
+ public Boolean doInCallableStatement(final CallableStatement cs)
+ throws SQLException {
+ cs.setString(1, owner);
+ cs.registerOutParameter(2, Types.VARCHAR);
+ cs.execute();
+ final String ret = cs.getString(2);
+ return "1".equals(ret);
+ }
+ });
+ } else {
+ return containsUtplsqlTest(owner, null, null);
+ }
+ }
+
+ public boolean containsUtplsqlTest(final String owner, final String objectName) {
+ if (normalizedUtPlsqlVersionNumber() >= org.utplsql.sqldev.dal.UtplsqlDao.FIRST_VERSION_WITH_HAS_SUITES_API) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("DECLARE\n");
+ sb.append(" l_return VARCHAR2(1) := '0';\n");
+ sb.append("BEGIN\n");
+ sb.append(" IF ut_runner.is_suite(?, ?) THEN\n");
+ sb.append(" l_return := '1';\n");
+ sb.append(" END IF;\n");
+ sb.append(" ? := l_return;\n");
+ sb.append("END;");
+ final String sql = sb.toString();
+ return jdbcTemplate.execute(sql, new CallableStatementCallback() {
+ @Override
+ public Boolean doInCallableStatement(final CallableStatement cs)
+ throws SQLException {
+ cs.setString(1, owner);
+ cs.setString(2, objectName);
+ cs.registerOutParameter(3, Types.VARCHAR);
+ cs.execute();
+ final String ret = cs.getString(3);
+ return "1".equals(ret);
+ }
+ });
+ } else {
+ return containsUtplsqlTest(owner, objectName, null);
+ }
+ }
+
+ /**
+ * Gets a list of utPLSQL annotations for a given PL/SQL package specification
+ *
+ * @param owner
+ * schema name, mandatory, case-insensitive
+ * @param objectName
+ * name of the package or package body, optional, case-insensitive
+ * @return list of Annotation with name 'suite' or 'test'
+ * @throws DataAccessException
+ * if a utPLSQL version less than 3.0.4 is installed or if there are
+ * other problems
+ */
+ public List annotations(final String owner, final String objectName) {
+ StringBuilder sb = new StringBuilder();
+ if (normalizedUtPlsqlVersionNumber() >= FIRST_VERSION_WITH_ANNOTATION_API) {
+ sb.append("SELECT object_owner,\n");
+ sb.append(" object_name,\n");
+ sb.append(" lower(substr(item_type, 4)) AS name,\n");
+ sb.append(" item_name as subobject_name\n");
+ sb.append(" FROM TABLE(ut_runner.get_suites_info(upper(?), upper(?)))");
+ } else {
+ sb.append("SELECT o.object_owner,\n");
+ sb.append(" o.object_name,\n");
+ sb.append(" a.name,\n");
+ sb.append(" a.text,\n");
+ sb.append(" coalesce(upper(a.subobject_name), o.object_name) AS subobject_name\n");
+ sb.append(" FROM TABLE(");
+ sb.append(getUtplsqlSchema());
+ sb.append(".ut_annotation_manager.get_annotated_objects(upper(?), 'PACKAGE')) o\n");
+ sb.append(" CROSS JOIN TABLE(o.annotations) a\n");
+ sb.append(" WHERE o.object_name = upper(?)");
+ }
+ final String sql = sb.toString();
+ final BeanPropertyRowMapper rowMapper = new BeanPropertyRowMapper<>(Annotation.class);
+ final Object[] binds = new Object[] {owner, objectName};
+ return jdbcTemplate.query(sql, rowMapper, binds);
+ }
+
+ /**
+ * Gets a list of public units in the object type
+ *
+ * @param objectType
+ * expected object types are PACKAGE, TYPE, FUNCTION, PROCEDURE
+ * @param objectName
+ * name of the object
+ * @return list of the public units in the object type
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public List units(final String objectType, final String objectName) {
+ if ("PACKAGE".equals(objectType) || "TYPE".equals(objectType)) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT procedure_name\n");
+ sb.append(" FROM user_procedures\n");
+ sb.append(" WHERE object_type = ?\n");
+ sb.append(" AND object_name = ?\n");
+ sb.append(" AND procedure_name IS NOT NULL\n");
+ sb.append(" GROUP BY procedure_name\n");
+ sb.append(" ORDER BY min(subprogram_id)");
+ final String sql = sb.toString();
+ final Object[] binds = new Object[] {objectType, objectName};
+ return jdbcTemplate.queryForList(sql, String.class, binds);
+ } else {
+ return Arrays.asList(objectName);
+ }
+ }
+
+ /**
+ * Gets a list of oddgen's nodes as candidates to create utPLSQL test packages.
+ * Candidates are packages, types, functions and procedures in the current user.
+ *
+ * This functions must be called from an oddgen generator only, since the Node
+ * is not defined in the utPLSQL extension.
+ *
+ * @param objectType
+ * expected object types are PACKAGE, TYPE, FUNCTION, PROCEDURE
+ * @return list of the oddgen nodes for the requested object type
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public List testables(final String objectType) {
+ StringBuilder sb = new StringBuilder();
+ if ("PACKAGE".equals(objectType)) {
+ if (normalizedUtPlsqlVersionNumber() >= FIRST_VERSION_WITH_ANNOTATION_API) {
+ // using API available since 3.1.3
+ sb.append("SELECT DISTINCT\n");
+ sb.append(" object_type || '.' || object_name AS id,\n");
+ sb.append(" object_type AS parent_id,\n");
+ sb.append(" 1 AS leaf,\n");
+ sb.append(" 1 AS generatable,\n");
+ sb.append(" 1 AS multiselectable\n");
+ sb.append(" FROM user_procedures\n");
+ sb.append(" WHERE object_type = ?\n");
+ sb.append(" AND procedure_name IS NOT NULL\n");
+ sb.append(" AND object_name NOT IN (\n");
+ sb.append(" SELECT object_name\n");
+ sb.append(" FROM TABLE(ut_runner.get_suites_info(USER))\n");
+ sb.append(" WHERE item_type = 'UT_SUITE'\n");
+ sb.append(" )");
+ } else {
+ // using internal API (deprecated, not accessible in latest version)
+ sb.append("SELECT DISTINCT\n");
+ sb.append(" object_type || '.' || object_name AS id,\n");
+ sb.append(" object_type AS parent_id,\n");
+ sb.append(" 1 AS leaf,\n");
+ sb.append(" 1 AS generatable,\n");
+ sb.append(" 1 AS multiselectable\n");
+ sb.append(" FROM user_procedures\n");
+ sb.append(" WHERE object_type = ?\n");
+ sb.append(" AND procedure_name IS NOT NULL\n");
+ sb.append(" AND object_name NOT IN (\n");
+ sb.append(" SELECT object_name\n");
+ sb.append(" FROM TABLE(\n");
+ sb.append(getUtplsqlSchema());
+ sb.append(".ut_annotation_manager.get_annotated_objects(USER, 'PACKAGE'))\n");
+ sb.append(" )");
+ }
+ } else if ("TYPE".equals(objectType)) {
+ sb.append("SELECT DISTINCT\n");
+ sb.append(" object_type || '.' || object_name AS id,\n");
+ sb.append(" object_type AS parent_id,\n");
+ sb.append(" 1 AS leaf,\n");
+ sb.append(" 1 AS generatable,\n");
+ sb.append(" 1 AS multiselectable\n");
+ sb.append(" FROM user_procedures\n");
+ sb.append(" WHERE object_type = ?\n");
+ sb.append(" AND procedure_name IS NOT NULL");
+ } else {
+ sb.append("SELECT object_type || '.' || object_name AS id,\n");
+ sb.append(" object_type AS parent_id,\n");
+ sb.append(" 1 AS leaf,\n");
+ sb.append(" 1 AS generatable,\n");
+ sb.append(" 1 AS multiselectable\n");
+ sb.append(" FROM user_objects\n");
+ sb.append(" WHERE object_type = ?\n");
+ sb.append(" AND generated = 'N'");
+ }
+ final String sql = sb.toString();
+ final Object[] binds = new Object[] {objectType};
+ BeanPropertyRowMapper rowMapper = new BeanPropertyRowMapper<>(Node.class);
+ return jdbcTemplate.query(sql, rowMapper, binds);
+ }
+
+ /**
+ * Gets a list of oddgen's nodes as candidates to run utPLSQL tests.
+ *
+ * This functions must be called from an oddgen generator only, since the Node
+ * is not defined in the utPLSQL extension.
+ *
+ * @return list of oddgen nodes (complete hierarchy loaded eagerly)
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public List runnables() {
+ StringBuilder sb = new StringBuilder();
+ if (normalizedUtPlsqlVersionNumber() >= FIRST_VERSION_WITH_ANNOTATION_API) {
+ // using API available since 3.1.3
+ sb.append("WITH\n");
+ sb.append(" test AS (\n");
+ sb.append(" SELECT object_owner,\n");
+ sb.append(" object_name,\n");
+ sb.append(" path AS suitepath,\n");
+ sb.append(" count(\n");
+ sb.append(" CASE\n");
+ sb.append(" WHEN item_type = 'UT_TEST' THEN\n");
+ sb.append(" 1\n");
+ sb.append(" ELSE\n");
+ sb.append(" NULL\n");
+ sb.append(" END\n");
+ sb.append(" ) over (partition by object_owner, object_name) AS test_count,\n");
+ sb.append(" item_type,\n");
+ sb.append(" item_name,\n");
+ sb.append(" item_description\n");
+ sb.append(" FROM TABLE(ut_runner.get_suites_info(user))\n");
+ sb.append(" ),\n");
+ sb.append(" suite_tree AS (\n");
+ sb.append(" SELECT null AS parent_id,\n");
+ sb.append(" 'SUITE' AS id,\n");
+ sb.append(" 'All Suites' AS name,\n");
+ sb.append(" 'All utPLSQL test suites' AS description,\n");
+ sb.append(" 'PACKAGE_FOLDER_ICON' AS iconName,\n");
+ sb.append(" 'No' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM dual\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT DISTINCT\n");
+ sb.append(" 'SUITE' AS parent_id,\n");
+ sb.append(" object_owner || '.' || object_name AS id,\n");
+ sb.append(" object_name AS name,\n");
+ sb.append(" null AS description,\n");
+ sb.append(" 'PACKAGE_ICON' AS iconName,\n");
+ sb.append(" 'No' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM test\n");
+ sb.append(" WHERE item_type IN ('UT_TEST', 'UT_SUITE')\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT object_owner || '.' || object_name AS parent_id,\n");
+ sb.append(" object_owner || '.' || object_name || '.' || item_name AS id,\n");
+ sb.append(" item_name AS name,\n");
+ sb.append(" item_description AS description,\n");
+ sb.append(" 'PROCEDURE_ICON' AS iconName,\n");
+ sb.append(" 'Yes' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM test\n");
+ sb.append(" WHERE item_type = 'UT_TEST'\n");
+ sb.append(" ),\n");
+ sb.append(" suitepath_tree AS (\n");
+ sb.append(" SELECT NULL AS parent_id,\n");
+ sb.append(" 'SUITEPATH' AS id,\n");
+ sb.append(" 'All Suitepaths' AS name\n,");
+ sb.append(" 'All utPLSQL test suitepathes' AS description,\n");
+ sb.append(" 'FOLDER_ICON' AS iconName,\n");
+ sb.append(" 'No' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM dual\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT CASE\n");
+ sb.append(" WHEN regexp_replace(suitepath,'\\.?\\w+$','') IS NULL THEN\n");
+ sb.append(" 'SUITEPATH'\n");
+ sb.append(" ELSE\n");
+ sb.append(" object_owner || ':' || regexp_replace(suitepath,'\\.?\\w+$','')\n");
+ sb.append(" END AS parent_id,\n");
+ sb.append(" object_owner || ':' || suitepath AS id,\n");
+ sb.append(" item_name AS name,\n");
+ sb.append(" item_description AS description,\n");
+ sb.append(" CASE\n");
+ sb.append(" WHEN item_type = 'UT_SUITE' AND test_count > 0 THEN\n");
+ sb.append(" 'PACKAGE_ICON'\n");
+ sb.append(" WHEN item_type = 'UT_TEST' THEN\n");
+ sb.append(" 'PROCEDURE_ICON'\n");
+ sb.append(" ELSE\n");
+ sb.append(" 'FOLDER_ICON'\n");
+ sb.append(" END AS iconName,\n");
+ sb.append(" CASE item_type\n");
+ sb.append(" WHEN 'UT_TEST' THEN\n");
+ sb.append(" 'Yes'\n");
+ sb.append(" ELSE\n");
+ sb.append(" 'No'\n");
+ sb.append(" END AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM test\n");
+ sb.append(" ),\n");
+ sb.append(" tree AS (\n");
+ sb.append(" SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant\n");
+ sb.append(" FROM suite_tree\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant\n");
+ sb.append(" FROM suitepath_tree\n");
+ sb.append(" )\n");
+ sb.append("SELECT parent_id, id, initcap(name) AS name, description, iconName, leaf, generatable, multiselectable, relevant\n");
+ sb.append(" FROM tree");
+ } else {
+ // using internal API (deprecated, not accessible in latest version)
+ sb.append("WITH\n");
+ sb.append(" base AS (\n");
+ sb.append(" SELECT rownum AS an_id,\n");
+ sb.append(" o.object_owner,\n");
+ sb.append(" o.object_type,\n");
+ sb.append(" o.object_name,\n");
+ sb.append(" lower(a.name) AS name,\n");
+ sb.append(" a.text,\n");
+ sb.append(" a.subobject_name\n");
+ sb.append(" FROM table(");
+ sb.append(getUtplsqlSchema());
+ sb.append(".ut_annotation_manager.get_annotated_objects(user, 'PACKAGE')) o\n");
+ sb.append(" CROSS JOIN table(o.annotations) a\n");
+ sb.append(" WHERE lower(a.name) in ('suite', 'suitepath', 'endcontext', 'test')\n");
+ sb.append(" OR lower(a.name) = 'context' AND regexp_like(text, '(\\w+)(\\.\\w+)*')\n");
+ sb.append(" ),\n");
+ sb.append(" suite AS (\n");
+ sb.append(" SELECT object_owner, object_type, object_name, text AS suite_description\n");
+ sb.append(" FROM base\n");
+ sb.append(" WHERE name = 'suite'\n");
+ sb.append(" ),\n");
+ sb.append(" suitepath as (\n");
+ sb.append(" SELECT object_owner, object_type, object_name, lower(text) AS suitepath\n");
+ sb.append(" FROM base\n");
+ sb.append(" WHERE name = 'suitepath'");
+ sb.append(" ),\n");
+ sb.append(" context_base AS (\n");
+ sb.append(" SELECT an_id,\n");
+ sb.append(" lead(an_id) over (partition by object_owner, object_type, object_name order by an_id) AS an_id_end,\n");
+ sb.append(" object_owner,\n");
+ sb.append(" object_type,\n");
+ sb.append(" object_name,\n");
+ sb.append(" name,\n");
+ sb.append(" lead(name) over (partition by object_owner, object_type, object_name order by an_id) AS name_end,\n");
+ sb.append(" text AS context\n");
+ sb.append(" FROM base\n");
+ sb.append(" WHERE name IN ('context', 'endcontext')\n");
+ sb.append(" ),\n");
+ sb.append(" context AS (\n");
+ sb.append(" SELECT an_id, an_id_end, object_owner, object_type, object_name, context\n");
+ sb.append(" FROM context_base\n");
+ sb.append(" WHERE name = 'context'\n");
+ sb.append(" AND name_end = 'endcontext'\n");
+ sb.append(" ),\n");
+ sb.append(" test AS (\n");
+ sb.append(" SELECT b.an_id,\n");
+ sb.append(" b.object_owner,\n");
+ sb.append(" b.object_type,\n");
+ sb.append(" b.object_name,\n");
+ sb.append(" p.suitepath,\n");
+ sb.append(" c.context,\n");
+ sb.append(" b.subobject_name,\n");
+ sb.append(" b.text AS test_description\n");
+ sb.append(" FROM base b\n");
+ sb.append(" LEFT JOIN suitepath p\n");
+ sb.append(" ON p.object_owner = b.object_owner\n");
+ sb.append(" AND p.object_type = b.object_type\n");
+ sb.append(" AND p.object_name = b.object_name\n");
+ sb.append(" LEFT JOIN context c\n");
+ sb.append(" ON c.object_owner = b.object_owner\n");
+ sb.append(" AND c.object_type = b.object_type\n");
+ sb.append(" AND c.object_name = b.object_name\n");
+ sb.append(" AND b.an_id BETWEEN c.an_id AND c.an_id_end\n");
+ sb.append(" WHERE name = 'test'\n");
+ sb.append(" AND (b.object_owner, b.object_type, b.object_name) IN (\n");
+ sb.append(" SELECT object_owner, object_type, object_name\n");
+ sb.append(" FROM suite\n");
+ sb.append(" )\n");
+ sb.append(" ),\n");
+ sb.append(" suite_tree AS (\n");
+ sb.append(" SELECT null AS parent_id,\n");
+ sb.append(" 'SUITE' AS id,\n");
+ sb.append(" 'All Suites' AS name,\n");
+ sb.append(" 'All utPLSQL test suites' AS description,\n");
+ sb.append(" 'PACKAGE_FOLDER_ICON' AS iconName,\n");
+ sb.append(" 'No' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM dual\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT DISTINCT\n");
+ sb.append(" 'SUITE' AS parent_id,\n");
+ sb.append(" 'object_owner || '.' || object_name AS id,\n");
+ sb.append(" object_name AS name,\n");
+ sb.append(" NULL AS description,\n");
+ sb.append(" 'PACKAGE_ICON' AS iconName,\n");
+ sb.append(" 'No' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM test\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT object_owner || '.' || object_name AS parent_id,\n");
+ sb.append(" object_owner || '.' || object_name || '.' || upper(subobject_name) AS id,\n");
+ sb.append(" subobject_name AS name,\n");
+ sb.append(" NULL AS description,\n");
+ sb.append(" 'PROCEDURE_ICON' AS iconName,\n");
+ sb.append(" 'Yes' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM test\n");
+ sb.append(" ),\n");
+ sb.append(" suitepath_base AS (\n");
+ sb.append(" SELECT DISTINCT\n");
+ sb.append(" suitepath\n");
+ sb.append(" FROM suitepath\n");
+ sb.append(" ),\n");
+ sb.append(" gen AS (\n");
+ sb.append(" SELECT rownum AS pos\n");
+ sb.append(" FROM xmltable('1 to 100')\n");
+ sb.append(" ),\n");
+ sb.append(" suitepath_part AS (\n");
+ sb.append(" SELECT DISTINCT\n");
+ sb.append(" lower(substr(suitepath, 1, instr(suitepath || '.', '.', 1, g.pos) -1)) AS suitepath\n");
+ sb.append(" FROM suitepath_base b\n");
+ sb.append(" JOIN gen g\n");
+ sb.append(" ON g.pos <= regexp_count(suitepath, '\\w+')\n");
+ sb.append(" ),\n");
+ sb.append(" suitepath_tree AS (\n");
+ sb.append(" SELECT NULL AS parent_id,\n");
+ sb.append(" 'SUITEPATH' AS id,\n");
+ sb.append(" 'All Suitepaths' AS name,\n");
+ sb.append(" 'All utPLSQL test suitepathes' AS description,\n");
+ sb.append(" 'FOLDER_ICON' AS iconName,\n");
+ sb.append(" 'No' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM dual\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT CASE\n");
+ sb.append(" WHEN regexp_replace(suitepath,'\\.?\\w+$','') IS NULL THEN\n");
+ sb.append(" 'SUITEPATH'\n");
+ sb.append(" ELSE\n");
+ sb.append(" USER || ':' || regexp_replace(suitepath,'\\.?\\w+$','')");
+ sb.append(" END AS parent_id,\n");
+ sb.append(" USER || ':' || suitepath AS id,\n");
+ sb.append(" regexp_substr(suitepath, '\\.?(\\w+$)', 1, 1, NULL, 1) AS name,\n");
+ sb.append(" NULL AS description,\n");
+ sb.append(" 'FOLDER_ICON' AS iconName,\n");
+ sb.append(" 'No' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM suitepath_part\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT DISTINCT\n");
+ sb.append(" object_owner || ':' || suitepath AS parent_id,\n");
+ sb.append(" object_owner || ':' || suitepath || '.' || lower(object_name) AS id,\n");
+ sb.append(" object_name AS name,\n");
+ sb.append(" NULL AS description,\n");
+ sb.append(" 'PACKAGE_ICON' AS iconName,\n");
+ sb.append(" 'No' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM test\n");
+ sb.append(" WHERE suitepath IS NOT NULL\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT DISTINCT\n");
+ sb.append(" object_owner || ':' || suitepath || '.' || lower(object_name) AS parent_id,\n");
+ sb.append(" object_owner || ':' || suitepath || '.' || lower(object_name) || '.' || context AS id,\n");
+ sb.append(" context AS name,\n");
+ sb.append(" NULL AS description,\n");
+ sb.append(" 'FOLDER_ICON' AS iconName,\n");
+ sb.append(" 'No' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable,\n");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM test\n");
+ sb.append(" WHERE suitepath IS NOT NULL\n");
+ sb.append(" AND context IS NOT NULL\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT object_owner || ':' || suitepath || '.' || lower(object_name) || CASE WHEN context IS NOT NULL THEN '.' || context END AS parent_id,\n");
+ sb.append(" object_owner || ':' || suitepath || '.' || lower(object_name) || CASE WHEN context IS NOT NULL THEN '.' || context END || '.' || lower(subobject_name) AS id,\n");
+ sb.append(" subobject_name AS name,\n");
+ sb.append(" NULL AS description,\n");
+ sb.append(" 'PROCEDURE_ICON' AS iconName,\n");
+ sb.append(" 'Yes' AS leaf,\n");
+ sb.append(" 'Yes' AS generatable,\n");
+ sb.append(" 'Yes' AS multiselectable\n,");
+ sb.append(" 'Yes' AS relevant\n");
+ sb.append(" FROM test\n");
+ sb.append(" WHERE suitepath IS NOT NULL\n");
+ sb.append(" ),\n");
+ sb.append(" tree AS (\n");
+ sb.append(" SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant\n");
+ sb.append(" FROM suite_tree\n");
+ sb.append(" UNION ALL\n");
+ sb.append(" SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant\n");
+ sb.append(" FROM suitepath_tree\n");
+ sb.append(" )\n");
+ sb.append("SELECT parent_id, id, initcap(name) AS name, description, iconName, leaf, generatable, multiselectable, relevant\n");
+ sb.append(" FROM tree");
+ }
+ BeanPropertyRowMapper rowMapper = new BeanPropertyRowMapper<>(Node.class);
+ final String sql = sb.toString();
+ return jdbcTemplate.query(sql, rowMapper);
+ }
+
+ /**
+ * enable DBMS_OUTPUT
+ *
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public void enableDbmsOutput() {
+ // equivalent to "set serveroutput on size unlimited"
+ StringBuilder sb = new StringBuilder();
+ sb.append("BEGIN");
+ sb.append(" sys.dbms_output.enable(NULL);\n");
+ sb.append("END;");
+ jdbcTemplate.update(sb.toString());
+ }
+
+ /**
+ * disable DBMS_OUTPUT
+ *
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public void disableDbmsOutput() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("BEGIN\n");
+ sb.append(" sys.dbms_output.disable;\n");
+ sb.append("END;");
+ jdbcTemplate.update(sb.toString());
+ }
+
+ /**
+ * return the content of DBMS_OUTPUT as String
+ *
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public String getDbmsOutput() {
+ return getDbmsOutput(1000);
+ }
+
+ /**
+ * return the content of DBMS_OUTPUT as String
+ *
+ * @param bufferSize
+ * maximum number of rows to be read from the DBMS_OUTPUT buffer in
+ * one network round trip
+ * @return content of DBMS_OUTPUT as String
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public String getDbmsOutput(final int bufferSize) {
+ final StringBuilder resultSb = new StringBuilder();
+ StringBuilder sb = new StringBuilder();
+ sb.append("BEGIN");
+ sb.append(" sys.dbms_output.get_lines(?, ?);\n");
+ sb.append("END;");
+ final String sql = sb.toString();
+ OutputLines ret = null;
+ do {
+ ret = jdbcTemplate.execute(sql, new CallableStatementCallback() {
+ @Override
+ public OutputLines doInCallableStatement(final CallableStatement cs) throws SQLException {
+ cs.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
+ cs.registerOutParameter(2, Types.INTEGER);
+ cs.setInt(2, bufferSize);
+ cs.execute();
+ final OutputLines out = new OutputLines();
+ Object array = cs.getArray(1).getArray();
+ out.setLines((String[]) array);
+ out.setNumlines(cs.getInt(2));
+ return out;
+ }
+ });
+ for (int i = 0; i < ret.getNumlines(); i++) {
+ final String line = ret.getLines()[i];
+ if (line != null) {
+ resultSb.append(ret.getLines()[i]);
+ }
+ resultSb.append(System.lineSeparator());
+ }
+ } while (ret.getNumlines() > 0);
+ return resultSb.toString();
+ }
+
+ /**
+ * gets the HTML code coverage report as String
+ *
+ * @param pathList
+ * utPLSQL path list
+ * @param schemaList
+ * list of schemas under tests. Current schema, if empty
+ * @param includeObjectList
+ * list of objects to be included for coverage analysis. All, if
+ * empty
+ * @param excludeObjectList
+ * list of objects to be excluded from coverage analysis. None, if
+ * empty
+ * @return HTML code coverage report in HTML format
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public String htmlCodeCoverage(final List pathList, final List schemaList,
+ final List includeObjectList, final List excludeObjectList) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT column_value\n");
+ sb.append(" FROM table(\n");
+ sb.append(" ut.run(\n");
+ sb.append(" a_paths => ut_varchar2_list(\n");
+ sb.append(StringTools.getCSV(pathList, 16));
+ sb.append(" ),\n");
+ if (!schemaList.isEmpty()) {
+ sb.append(" a_coverage_schemes => ut_varchar2_list(\n");
+ sb.append(StringTools.getCSV(schemaList, 16));
+ sb.append(" ),\n");
+ }
+ if (!includeObjectList.isEmpty()) {
+ sb.append(" a_include_objects => ut_varchar2_list(\n");
+ sb.append(StringTools.getCSV(includeObjectList, 16));
+ sb.append(" ),\n");
+ }
+ if (!excludeObjectList.isEmpty()) {
+ sb.append(" a_exclude_objects => ut_varchar2_list(\n");
+ sb.append(StringTools.getCSV(excludeObjectList, 16));
+ sb.append(" ),\n");
+ }
+ sb.append(" a_reporter => ut_coverage_html_reporter()\n");
+ sb.append(" )\n");
+ sb.append(" )");
+ final String sql = sb.toString();
+ final List lines = jdbcTemplate.queryForList(sql, String.class);
+ final StringBuilder resultSb = new StringBuilder();
+ for (String line : lines) {
+ if (line != null) {
+ resultSb.append(line);
+ resultSb.append("\n");
+ }
+ }
+ return resultSb.toString();
+ }
+
+ /**
+ * gets dependencies of a given object.
+ *
+ * The result can be used as input for the includeObjectList in htmlCodeCoverage
+ * The scope is reduced to non-oracle maintained schemas.
+ *
+ * Oracle introduced the column ORACLE_MAINTAINED in 12.1. To simplify the query
+ * and compatibility the result of the following query is included
+ *
+ * SELECT '''' || listagg(username, ''', ''') || '''' AS oracle_maintained_users
+ * FROM dba_users WHERE oracle_maintained = 'Y' ORDER BY username;
+ *
+ * The result may include test packages
+ *
+ * @param name
+ * test package name
+ * @return list of dependencies in the current schema
+ */
+ public List includes(final String owner, final String name) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT referenced_owner || '.' || referenced_name AS dep_name\n");
+ sb.append(" FROM ");
+ sb.append(getDbaView("dependencies\n"));
+ sb.append(" WHERE owner = upper(?)\n");
+ sb.append(" AND name = upper(?)\n");
+ sb.append(" AND referenced_owner NOT IN (\n");
+ sb.append(" 'SYS', 'SYSTEM', 'XS$NULL', 'OJVMSYS', 'LBACSYS', 'OUTLN', 'SYS$UMF',\n");
+ sb.append(" 'DBSNMP', 'APPQOSSYS', 'DBSFWUSER', 'GGSYS', 'ANONYMOUS', 'CTXSYS',\n");
+ sb.append(" 'SI_INFORMTN_SCHEMA', 'DVF', 'DVSYS', 'GSMADMIN_INTERNAL', 'ORDPLUGINS',\n");
+ sb.append(" 'MDSYS', 'OLAPSYS', 'ORDDATA', 'XDB', 'WMSYS', 'ORDSYS', 'GSMCATUSER',\n");
+ sb.append(" 'MDDATA', 'REMOTE_SCHEDULER_AGENT', 'SYSBACKUP', 'GSMUSER', 'APEX_PUBLIC_USER',\n");
+ sb.append(" 'SYSRAC', 'AUDSYS', 'DIP', 'SYSKM', 'ORACLE_OCM', 'APEX_INSTANCE_ADMIN_USER',\n");
+ sb.append(" 'SYSDG', 'FLOWS_FILES', 'ORDS_METADATA', 'ORDS_PUBLIC_USER'\n");
+ sb.append(" )\n");
+ sb.append(" AND referenced_owner NOT LIKE 'APEX\\_______'");
+ sb.append(" AND referenced_type IN ('PACKAGE', 'TYPE', 'PROCEDURE', 'FUNCTION', 'TRIGGER')");
+ final String sql = sb.toString();
+ final Object[] binds = new Object[] {owner, name};
+ return jdbcTemplate.queryForList(sql, String.class, binds);
+ }
+
+ /**
+ * gets source of an object from the database via DBMS_METADATA
+ *
+ * @param owner
+ * owner of the object (schema)
+ * @param objectType
+ * expected object types are PACKAGE, PACKAGE BODY
+ * @param objectName
+ * name of the object
+ * @return the source code of the object
+ * @throws DataAccessException
+ * if there is a problem
+ */
+ public String getSource(final String owner, final String objectType, final String objectName) {
+ String fixedObjectType;
+ if ("PACKAGE".equals(objectType)) {
+ fixedObjectType = "PACKAGE_SPEC";
+ } else if ("PACKAGE BODY".equals(objectType)) {
+ fixedObjectType = "PACKAGE_BODY";
+ } else {
+ fixedObjectType = objectType;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("BEGIN\n");
+ sb.append(" ? := sys.dbms_metadata.get_ddl(\n");
+ sb.append(" schema => ?,\n");
+ sb.append(" object_type => ?,\n");
+ sb.append(" name => ?\n");
+ sb.append(" );\n");
+ sb.append("END;");
+ final String sql = sb.toString();
+ return jdbcTemplate.execute(sql, new CallableStatementCallback() {
+ @Override
+ public String doInCallableStatement(final CallableStatement cs) throws SQLException {
+ cs.registerOutParameter(1, Types.CLOB);
+ cs.setString(2, owner);
+ cs.setString(3, fixedObjectType);
+ cs.setString(4, objectName);
+ cs.execute();
+ return cs.getString(1);
+ }
+ });
+ }
+
+ /**
+ * gets the object type of a database object
+ *
+ * The object types "PACKAGE BODY", "TYPE BODY" have higher priority. "PACKAGE"
+ * OR "TYPE" will be returned only when no body exists.
+ *
+ * @param owner
+ * owner of the object (schema)
+ * @param objectName
+ * name of the object
+ * @return the object type, e.g. PACKAGE BODY, TYPE BODY, PROCEDURE, FUNCTION
+ */
+ public String getObjectType(final String owner, final String objectName) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT object_type\n");
+ sb.append(" FROM (\n");
+ sb.append(" SELECT object_type\n");
+ sb.append(" FROM ");
+ sb.append(getDbaView("objects\n"));
+ sb.append(" WHERE owner = ?\n");
+ sb.append(" AND object_name = ?\n");
+ sb.append(" ORDER BY decode(object_type, 'PACKAGE', 10, 'TYPE', 10, 'SYNONYM', 20, 1)\n");
+ sb.append(" )\n");
+ sb.append(" WHERE rownum = 1");
+ final String sql = sb.toString();
+ final Object[] binds = new Object[] {owner, objectName};
+ return jdbcTemplate.queryForObject(sql, binds, String.class);
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.xtend b/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.xtend
deleted file mode 100644
index 7070a25f..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.xtend
+++ /dev/null
@@ -1,1020 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.utplsql.sqldev.dal
-
-import java.sql.CallableStatement
-import java.sql.Connection
-import java.sql.SQLException
-import java.sql.Types
-import java.util.List
-import java.util.regex.Pattern
-import org.oddgen.sqldev.generators.model.Node
-import org.springframework.dao.DataAccessException
-import org.springframework.dao.EmptyResultDataAccessException
-import org.springframework.jdbc.core.BeanPropertyRowMapper
-import org.springframework.jdbc.core.CallableStatementCallback
-import org.springframework.jdbc.core.JdbcTemplate
-import org.springframework.jdbc.datasource.SingleConnectionDataSource
-import org.utplsql.sqldev.model.ut.Annotation
-import org.utplsql.sqldev.model.ut.OutputLines
-
-class UtplsqlDao {
- public static val UTPLSQL_PACKAGE_NAME = "UT"
- public static val NOT_INSTALLED = 0000000
- public static val FIRST_VERSION_WITH_INTERNAL_ANNOTATION_API = 3000004
- public static val FIRST_VERSION_WITH_ANNOTATION_API = 3001003
- public static val FIRST_VERSION_WITHOUT_INTERNAL_API = 3001008
- public static val FIRST_VERSION_WITH_HAS_SUITES_API = 3001008
- var Connection conn
- var JdbcTemplate jdbcTemplate
- // cache fields
- Boolean cachedDbaViewAccessible
- String cachedUtplsqlSchema
- String cachedUtPlsqlVersion
-
- new(Connection connection) {
- conn = connection
- jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, true))
- }
-
- /**
- * used for testing purposes only
- */
- def setUtPlsqlVersion(String utPlsqlVersion) {
- cachedUtPlsqlVersion = utPlsqlVersion
- }
-
- /**
- * returns a normalized utPLSQL version in format 9.9.9
- */
- def String normalizedUtPlsqlVersion() {
- val version = getUtPlsqlVersion()
- if (version !== null) {
- val p = Pattern.compile("(\\d+\\.\\d+\\.\\d+)")
- val m = p.matcher(version)
- if (m.find) {
- return m.group(0)
- }
- }
- return "0.0.0"
- }
-
- /**
- * get version as number, e.g. 3001004
- */
- def int normalizedUtPlsqlVersionNumber() {
- val p = Pattern.compile("(\\d+)")
- val version = normalizedUtPlsqlVersion()
- val m = p.matcher(version)
- m.find
- val major = m.group
- m.find
- val minor = m.group
- m.find
- val bugfix = m.group
- val versionNumber = Integer.valueOf(major)*1000000 + Integer.valueOf(minor)*1000 + Integer.valueOf(bugfix)
- return versionNumber
- }
-
- /**
- * gets version of installed utPLSQL
- */
- def String getUtPlsqlVersion() {
- if (cachedUtPlsqlVersion === null) {
- val sql = '''
- BEGIN
- ? := ut.version;
- END;
- '''
- try {
- cachedUtPlsqlVersion = jdbcTemplate.execute(sql, new CallableStatementCallback() {
- override String doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
- cs.registerOutParameter(1, Types.VARCHAR);
- cs.execute
- val version = cs.getString(1)
- return version
- }
- })
- } catch (SQLException e) {
- // ignore error
- } catch (DataAccessException e) {
- // ignore error
- }
- }
- return cachedUtPlsqlVersion
- }
-
- def boolean isDbaViewAccessible() {
- if (cachedDbaViewAccessible === null) {
- try {
- val sql = '''
- SELECT 1 AS dummy
- FROM dba_objects
- WHERE 1=2
- UNION ALL
- SELECT 1
- FROM dba_synonyms
- WHERE 1=2
- UNION ALL
- SELECT 1
- FROM dba_dependencies
- WHERE 1=2
- '''
- jdbcTemplate.execute(sql)
- cachedDbaViewAccessible = true
- } catch (DataAccessException e) {
- cachedDbaViewAccessible = false
- }
- }
- return cachedDbaViewAccessible.booleanValue
- }
-
- /**
- * Gets the schema name of the utPLSQL installation.
- *
- * @return utPLSQL schema or null if no utPLSQL is not installed
- * @throws DataAccessException if there is a problem
- */
- def String getUtplsqlSchema() {
- if (cachedUtplsqlSchema === null) {
- val sql = '''
- SELECT table_owner
- FROM «IF dbaViewAccessible»dba«ELSE»all«ENDIF»_synonyms
- WHERE owner = 'PUBLIC'
- AND synonym_name = '«UTPLSQL_PACKAGE_NAME»'
- AND table_name = '«UTPLSQL_PACKAGE_NAME»'
- '''
- try {
- val schema = jdbcTemplate.queryForObject(sql, String)
- cachedUtplsqlSchema = schema
- } catch (EmptyResultDataAccessException e) {
- cachedUtplsqlSchema = null
- }
- }
- return cachedUtplsqlSchema
- }
-
- /**
- * Checks if the package ut_annotation_manager is installed.
- * This package has been introduced with utPLSQL 3.0.4.
- * This version is a prerequisite to identify
- * utPLSQL unit test procedures.
- *
- * @return true if ut_annotation_manager package has been found
- * @throws DataAccessException if there is a problem
- */
- def boolean isUtAnnotationManagerInstalled() {
- return normalizedUtPlsqlVersionNumber >= FIRST_VERSION_WITH_INTERNAL_ANNOTATION_API
- }
-
- /**
- * Checks if utPLSQL tests exist
- *
- * @param owner schema name, mandatory, case-insensitive
- * @param objectName name of the package or package body, optional, case-insensitive
- * @param subobjectName name of the procedure, optional, case-insensitive
- * @return true if at least one test has been found
- * @throws DataAccessException if a utPLSQL version less than 3.0.4 is installed or if there are other problems
- */
- def boolean containsUtplsqlTest(String owner, String objectName, String subobjectName) {
- try {
- if (normalizedUtPlsqlVersionNumber >= org.utplsql.sqldev.dal.UtplsqlDao.FIRST_VERSION_WITH_HAS_SUITES_API && objectName !== null && subobjectName !== null) {
- // use faster check function available since v3.1.3 (reliable in v3.1.8)
- val sql = '''
- DECLARE
- l_return VARCHAR2(1) := '0';
- BEGIN
- IF ut_runner.is_test(?, ?, ?) THEN
- l_return := '1';
- END IF;
- ? := l_return;
- END;
- '''
- val ret = jdbcTemplate.execute(sql, new CallableStatementCallback() {
- override Boolean doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
- cs.setString(1, owner)
- cs.setString(2, objectName)
- cs.setString(3, subobjectName)
- cs.registerOutParameter(4, Types.VARCHAR);
- cs.execute
- val ret = cs.getString(4)
- return ret == "1"
- }
- })
- return ret
- } else if (normalizedUtPlsqlVersionNumber >= FIRST_VERSION_WITH_ANNOTATION_API) {
- // using API available since 3.1.3, can handle nulls in objectName and subobjectName
- val sql = '''
- SELECT count(*)
- FROM TABLE(ut_runner.get_suites_info(upper(?), upper(?)))
- WHERE item_type IN ('UT_TEST', 'UT_SUITE')
- AND (item_name = upper(?) or ? IS NULL)
- '''
- val found = jdbcTemplate.queryForObject(sql, Integer, #[owner, objectName, subobjectName, subobjectName])
- return found > 0
- } else {
- // using internal API (deprecated)
- val sql = '''
- SELECT count(
- CASE
- WHEN a.name = 'test'
- AND (upper(a.subobject_name) = upper(?) OR ? IS NULL)
- THEN
- 1
- ELSE
- NULL
- END
- )
- FROM TABLE(«utplsqlSchema».ut_annotation_manager.get_annotated_objects(upper(?), 'PACKAGE')) o
- CROSS JOIN TABLE(o.annotations) a
- WHERE (o.object_name = upper(?) OR ? IS NULL)
- AND a.name IN ('test', 'suite')
- HAVING count(
- CASE
- WHEN a.name = 'suite' THEN
- 1
- ELSE
- NULL
- END
- ) > 0
- '''
- val found = jdbcTemplate.queryForObject(sql, Integer, #[subobjectName, subobjectName, owner, objectName, objectName])
- return found > 0
- }
- } catch (EmptyResultDataAccessException e) {
- return false
- }
- }
-
- def boolean containsUtplsqlTest(String owner) {
- if (normalizedUtPlsqlVersionNumber >= org.utplsql.sqldev.dal.UtplsqlDao.FIRST_VERSION_WITH_HAS_SUITES_API) {
- // use faster check function available since v3.1.3 (reliable in v3.1.8)
- val sql = '''
- DECLARE
- l_return VARCHAR2(1) := '0';
- BEGIN
- IF ut_runner.has_suites(?) THEN
- l_return := '1';
- END IF;
- ? := l_return;
- END;
- '''
- val ret = jdbcTemplate.execute(sql, new CallableStatementCallback() {
- override Boolean doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
- cs.setString(1, owner)
- cs.registerOutParameter(2, Types.VARCHAR);
- cs.execute
- val ret = cs.getString(2)
- return ret == "1"
- }
- })
- return ret
- } else {
- return containsUtplsqlTest(owner, null, null)
- }
- }
-
- def boolean containsUtplsqlTest(String owner, String objectName) {
- if (normalizedUtPlsqlVersionNumber >= org.utplsql.sqldev.dal.UtplsqlDao.FIRST_VERSION_WITH_HAS_SUITES_API) {
- // use faster check function available since v3.1.3 (reliable in v3.1.8)
- val sql = '''
- DECLARE
- l_return VARCHAR2(1) := '0';
- BEGIN
- IF ut_runner.is_suite(?, ?) THEN
- l_return := '1';
- END IF;
- ? := l_return;
- END;
- '''
- val ret = jdbcTemplate.execute(sql, new CallableStatementCallback() {
- override Boolean doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
- cs.setString(1, owner)
- cs.setString(2, objectName)
- cs.registerOutParameter(3, Types.VARCHAR);
- cs.execute
- val ret = cs.getString(3)
- return ret == "1"
- }
- })
- return ret
- } else {
- return containsUtplsqlTest(owner, objectName, null)
- }
- }
-
- /**
- * Gets a list of utPLSQL annotations for a given PL/SQL package specification
- *
- * @param owner schema name, mandatory, case-insensitive
- * @param objectName name of the package or package body, optional, case-insensitive
- * @return list of Annotation with name 'suite' or 'test'
- * @throws DataAccessException if a utPLSQL version less than 3.0.4 is installed or if there are other problems
- */
- def List annotations(String owner, String objectName) {
- var String sql
- if (normalizedUtPlsqlVersionNumber >= FIRST_VERSION_WITH_ANNOTATION_API) {
- // using API available since 3.1.3
- sql = '''
- SELECT object_owner,
- object_name,
- lower(substr(item_type, 4)) AS name,
- item_name as subobject_name
- FROM TABLE(ut_runner.get_suites_info(upper(?), upper(?)))
- '''
-
- } else {
- // using internal API (deprecated)
- sql = '''
- SELECT o.object_owner,
- o.object_name,
- a.name,
- a.text,
- coalesce(upper(a.subobject_name), o.object_name) AS subobject_name
- FROM TABLE(«utplsqlSchema».ut_annotation_manager.get_annotated_objects(upper(?), 'PACKAGE')) o
- CROSS JOIN TABLE(o.annotations) a
- WHERE o.object_name = upper(?)
- '''
- }
- val result = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Annotation), #[owner, objectName])
- return result
- }
-
- /**
- * Gets a list of public units in the object type
- *
- * @param objectType expected object types are PACKAGE, TYPE, FUNCTION, PROCEDURE
- * @param objectName name of the object
- * @return list of the public units in the object type
- * @throws DataAccessException if there is a problem
- */
- def List units(String objectType, String objectName) {
- if (objectType == "PACKAGE" || objectType == "TYPE") {
- val sql = '''
- SELECT procedure_name
- FROM user_procedures
- WHERE object_type = ?
- AND object_name = ?
- AND procedure_name IS NOT NULL
- GROUP BY procedure_name
- ORDER BY min(subprogram_id)
- '''
- val result = jdbcTemplate.queryForList(sql, String, #[objectType, objectName])
- return result
- } else {
- return #[objectName]
- }
- }
-
- /**
- * Gets a list of oddgen's nodes as candidates to create utPLSQL test packages.
- * Candidates are packages, types, functions and procedures in the current user.
- *
- * This functions must be called from an oddgen generator only, since the Node is not
- * defined in the utPLSQL extension.
- *
- * @param objectType expected object types are PACKAGE, TYPE, FUNCTION, PROCEDURE
- * @return list of the oddgen nodes for the requested object type
- * @throws DataAccessException if there is a problem
- */
- def List testables(String objectType) {
- var String sql;
- if (objectType == "PACKAGE") {
- if (normalizedUtPlsqlVersionNumber >= FIRST_VERSION_WITH_ANNOTATION_API) {
- // using API available since 3.1.3
- sql = '''
- SELECT DISTINCT
- object_type || '.' || object_name AS id,
- object_type AS parent_id,
- 1 AS leaf,
- 1 AS generatable,
- 1 AS multiselectable
- FROM user_procedures
- WHERE object_type = ?
- AND procedure_name IS NOT NULL
- AND object_name NOT IN (
- SELECT object_name
- FROM TABLE(ut_runner.get_suites_info(USER))
- WHERE item_type = 'UT_SUITE'
- )
- '''
- } else {
- // using internal API (deprecated)
- sql = '''
- SELECT DISTINCT
- object_type || '.' || object_name AS id,
- object_type AS parent_id,
- 1 AS leaf,
- 1 AS generatable,
- 1 AS multiselectable
- FROM user_procedures
- WHERE object_type = ?
- AND procedure_name IS NOT NULL
- AND object_name NOT IN (
- SELECT object_name
- FROM TABLE(«utplsqlSchema».ut_annotation_manager.get_annotated_objects(USER, 'PACKAGE'))
- )
- '''
- }
- }
- else if (objectType == "TYPE") {
- sql = '''
- SELECT DISTINCT
- object_type || '.' || object_name AS id,
- object_type AS parent_id,
- 1 AS leaf,
- 1 AS generatable,
- 1 AS multiselectable
- FROM user_procedures
- WHERE object_type = ?
- AND procedure_name IS NOT NULL
- '''
- }
- else {
- sql = '''
- SELECT object_type || '.' || object_name AS id,
- object_type AS parent_id,
- 1 AS leaf,
- 1 AS generatable,
- 1 AS multiselectable
- FROM user_objects
- WHERE object_type = ?
- AND generated = 'N'
- '''
- }
- val nodes = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Node), #[objectType])
- return nodes
- }
-
- /**
- * Gets a list of oddgen's nodes as candidates to run utPLSQL tests.
- *
- * This functions must be called from an oddgen generator only, since the Node is not
- * defined in the utPLSQL extension.
- *
- * @return list of oddgen nodes (complete hierarchy loaded eagerly)
- * @throws DataAccessException if there is a problem
- */
- def List runnables() {
- var String sql
- if (normalizedUtPlsqlVersionNumber >= FIRST_VERSION_WITH_ANNOTATION_API) {
- // using API available since 3.1.3
- sql = '''
- WITH
- test AS (
- SELECT object_owner,
- object_name,
- path AS suitepath,
- count(
- CASE
- WHEN item_type = 'UT_TEST' THEN
- 1
- ELSE
- NULL
- END
- ) over (partition by object_owner, object_name) AS test_count,
- item_type,
- item_name,
- item_description
- FROM TABLE(ut_runner.get_suites_info(user))
- ),
- suite_tree AS (
- SELECT null AS parent_id,
- 'SUITE' AS id,
- 'All Suites' AS name,
- 'All utPLSQL test suites' AS description,
- 'PACKAGE_FOLDER_ICON' AS iconName,
- 'No' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM dual
- UNION ALL
- SELECT DISTINCT
- 'SUITE' AS parent_id,
- object_owner || '.' || object_name AS id,
- object_name AS name,
- null AS description,
- 'PACKAGE_ICON' AS iconName,
- 'No' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM test
- WHERE item_type IN ('UT_TEST', 'UT_SUITE')
- UNION ALL
- SELECT object_owner || '.' || object_name AS parent_id,
- object_owner || '.' || object_name || '.' || item_name AS id,
- item_name AS name,
- item_description AS description,
- 'PROCEDURE_ICON' AS iconName,
- 'Yes' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM test
- WHERE item_type = 'UT_TEST'
- ),
- suitepath_tree AS (
- SELECT NULL AS parent_id,
- 'SUITEPATH' AS id,
- 'All Suitepaths' AS name,
- 'All utPLSQL test suitepathes' AS description,
- 'FOLDER_ICON' AS iconName,
- 'No' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM dual
- UNION ALL
- SELECT CASE
- WHEN regexp_replace(suitepath,'\.?\w+$','') IS NULL THEN
- 'SUITEPATH'
- ELSE
- object_owner || ':' || regexp_replace(suitepath,'\.?\w+$','')
- END AS parent_id,
- object_owner || ':' || suitepath AS id,
- item_name AS name,
- item_description AS description,
- CASE
- WHEN item_type = 'UT_SUITE' AND test_count > 0 THEN
- 'PACKAGE_ICON'
- WHEN item_type = 'UT_TEST' THEN
- 'PROCEDURE_ICON'
- ELSE
- 'FOLDER_ICON'
- END AS iconName,
- CASE item_type
- WHEN 'UT_TEST' THEN
- 'Yes'
- ELSE
- 'No'
- END AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM test
- ),
- tree AS (
- SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant
- FROM suite_tree
- UNION ALL
- SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant
- FROM suitepath_tree
- )
- SELECT parent_id, id, initcap(name) AS name, description, iconName, leaf, generatable, multiselectable, relevant
- FROM tree
- '''
- } else {
- // using internal API (deprecated)
- sql = '''
- WITH
- base AS (
- SELECT rownum AS an_id,
- o.object_owner,
- o.object_type,
- o.object_name,
- lower(a.name) AS name,
- a.text,
- a.subobject_name
- FROM table(«utplsqlSchema».ut_annotation_manager.get_annotated_objects(user, 'PACKAGE')) o
- CROSS JOIN table(o.annotations) a
- WHERE lower(a.name) in ('suite', 'suitepath', 'endcontext', 'test')
- OR lower(a.name) = 'context' AND regexp_like(text, '(\w+)(\.\w+)*')
- ),
- suite AS (
- SELECT object_owner, object_type, object_name, text AS suite_description
- FROM base
- WHERE name = 'suite'
- ),
- suitepath as (
- SELECT object_owner, object_type, object_name, lower(text) AS suitepath
- FROM base
- WHERE name = 'suitepath'
- ),
- context_base AS (
- SELECT an_id,
- lead(an_id) over (partition by object_owner, object_type, object_name order by an_id) AS an_id_end,
- object_owner,
- object_type,
- object_name,
- name,
- lead(name) over (partition by object_owner, object_type, object_name order by an_id) AS name_end,
- text as context
- FROM base
- WHERE name IN ('context', 'endcontext')
- ),
- context as (
- SELECT an_id, an_id_end, object_owner, object_type, object_name, context
- FROM context_base
- WHERE name = 'context'
- AND name_end = 'endcontext'
- ),
- test AS (
- SELECT b.an_id,
- b.object_owner,
- b.object_type,
- b.object_name,
- p.suitepath,
- c.context,
- b.subobject_name,
- b.text AS test_description
- FROM base b
- LEFT JOIN suitepath p
- ON p.object_owner = b.object_owner
- AND p.object_type = b.object_type
- AND p.object_name = b.object_name
- LEFT JOIN context c
- ON c.object_owner = b.object_owner
- AND c.object_type = b.object_type
- AND c.object_name = b.object_name
- AND b.an_id BETWEEN c.an_id AND c.an_id_end
- WHERE name = 'test'
- AND (b.object_owner, b.object_type, b.object_name) IN (
- SELECT object_owner, object_type, object_name
- FROM suite
- )
- ),
- suite_tree AS (
- SELECT null AS parent_id,
- 'SUITE' AS id,
- 'All Suites' AS name,
- 'All utPLSQL test suites' AS description,
- 'PACKAGE_FOLDER_ICON' AS iconName,
- 'No' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM dual
- UNION ALL
- SELECT DISTINCT
- 'SUITE' AS parent_id,
- object_owner || '.' || object_name AS id,
- object_name AS name,
- null AS description,
- 'PACKAGE_ICON' AS iconName,
- 'No' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM test
- UNION ALL
- SELECT object_owner || '.' || object_name AS parent_id,
- object_owner || '.' || object_name || '.' || upper(subobject_name) AS id,
- subobject_name AS name,
- null AS description,
- 'PROCEDURE_ICON' AS iconName,
- 'Yes' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM test
- ),
- suitepath_base AS (
- SELECT DISTINCT
- suitepath
- FROM suitepath
- ),
- gen AS (
- SELECT rownum AS pos
- FROM xmltable('1 to 100')
- ),
- suitepath_part AS (
- SELECT DISTINCT
- lower(substr(suitepath, 1, instr(suitepath || '.', '.', 1, g.pos) -1)) AS suitepath
- FROM suitepath_base b
- JOIN gen g
- ON g.pos <= regexp_count(suitepath, '\w+')
- ),
- suitepath_tree AS (
- SELECT NULL AS parent_id,
- 'SUITEPATH' AS id,
- 'All Suitepaths' AS name,
- 'All utPLSQL test suitepathes' AS description,
- 'FOLDER_ICON' AS iconName,
- 'No' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM dual
- UNION ALL
- SELECT CASE
- WHEN regexp_replace(suitepath,'\.?\w+$','') IS NULL THEN
- 'SUITEPATH'
- ELSE
- USER || ':' || regexp_replace(suitepath,'\.?\w+$','')
- END AS parent_id,
- USER || ':' || suitepath AS id,
- regexp_substr(suitepath, '\.?(\w+$)', 1, 1, NULL, 1) AS name,
- null AS description,
- 'FOLDER_ICON' AS iconName,
- 'No' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM suitepath_part
- UNION ALL
- SELECT DISTINCT
- object_owner || ':' || suitepath AS parent_id,
- object_owner || ':' || suitepath || '.' || lower(object_name) AS id,
- object_name AS name,
- null AS description,
- 'PACKAGE_ICON' AS iconName,
- 'No' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM test
- WHERE suitepath IS NOT NULL
- UNION ALL
- SELECT DISTINCT
- object_owner || ':' || suitepath || '.' || lower(object_name) AS parent_id,
- object_owner || ':' || suitepath || '.' || lower(object_name) || '.' || context AS id,
- context AS name,
- null AS description,
- 'FOLDER_ICON' AS iconName,
- 'No' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM test
- WHERE suitepath IS NOT NULL
- AND context IS NOT NULL
- UNION ALL
- SELECT object_owner || ':' || suitepath || '.' || lower(object_name) || CASE WHEN context IS NOT NULL THEN '.' || context END AS parent_id,
- object_owner || ':' || suitepath || '.' || lower(object_name) || CASE WHEN context IS NOT NULL THEN '.' || context END || '.' || lower(subobject_name) AS id,
- subobject_name AS name,
- null AS description,
- 'PROCEDURE_ICON' AS iconName,
- 'Yes' AS leaf,
- 'Yes' AS generatable,
- 'Yes' AS multiselectable,
- 'Yes' AS relevant
- FROM test
- WHERE suitepath IS NOT NULL
- ),
- tree AS (
- SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant
- FROM suite_tree
- UNION ALL
- SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant
- FROM suitepath_tree
- )
- SELECT parent_id, id, initcap(name) AS name, description, iconName, leaf, generatable, multiselectable, relevant
- FROM tree
- '''
- }
- val nodes = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Node))
- return nodes
- }
-
- /**
- * enable DBMS_OUTPUT
- *
- * @throws DataAccessException if there is a problem
- */
- def void enableDbmsOutput() {
- // equivalent to "set serveroutput on size unlimited"
- jdbcTemplate.update('''
- BEGIN
- sys.dbms_output.enable(NULL);
- END;
- ''')
- }
-
- /**
- * disable DBMS_OUTPUT
- *
- * @throws DataAccessException if there is a problem
- */
- def void disableDbmsOutput() {
- jdbcTemplate.update('''
- BEGIN
- sys.dbms_output.disable;
- END;
- ''')
- }
-
- /**
- * return the content of DBMS_OUTPUT as String
- *
- * @throws DataAccessException if there is a problem
- */
- def String getDbmsOutput() {
- return getDbmsOutput(1000)
- }
-
- /**
- * return the content of DBMS_OUTPUT as String
-
- * @param bufferSize maximum number of rows to be read from the DBMS_OUTPUT buffer in one network round trip
- * @return content of DBMS_OUTPUT as String
- * @throws DataAccessException if there is a problem
- */
- def String getDbmsOutput(int bufferSize) {
- val sb = new StringBuffer
- val sql = '''
- BEGIN
- sys.dbms_output.get_lines(?, ?);
- END;
- '''
- var OutputLines ret
- do {
- ret = jdbcTemplate.execute(sql, new CallableStatementCallback() {
- override OutputLines doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
- cs.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
- cs.registerOutParameter(2, Types.INTEGER)
- cs.setInt(2, bufferSize)
- cs.execute
- val out = new OutputLines
- out.lines = cs.getArray(1).array as String[]
- out.numlines = cs.getInt(2)
- return out
- }
- })
- for (i : 0 ..< ret.numlines) {
- val line = ret.lines.get(i)
- if (line !== null) {
- sb.append(ret.lines.get(i))
- }
- sb.append(System.lineSeparator)
- }
- } while (ret.numlines > 0)
- return sb.toString
- }
-
- /**
- * gets the HTML code coverage report as String
- *
- * @param pathList utPLSQL path list
- * @param schemaList list of schemas under tests. Current schema, if empty
- * @param includeObjectList list of objects to be included for coverage analysis. All, if empty
- * @param excludeObjectList list of objects to be excluded from coverage analysis. None, if empty
- * @return HTML code coverage report in HTML format
- * @throws DataAccessException if there is a problem
- */
- def String htmlCodeCoverage(List pathList, List schemaList, List includeObjectList, List excludeObjectList) {
- val sql = '''
- SELECT column_value
- FROM table(
- ut.run(
- a_paths => ut_varchar2_list(
- «FOR path : pathList SEPARATOR ", "»
- '«path»'
- «ENDFOR»
- ),
- «IF schemaList.size > 0»
- a_coverage_schemes => ut_varchar2_list(
- «FOR schema : schemaList SEPARATOR ", "»
- '«schema»'
- «ENDFOR»
- ),
- «ENDIF»
- «IF includeObjectList.size > 0»
- a_include_objects => ut_varchar2_list(
- «FOR includeObject : includeObjectList SEPARATOR ", "»
- '«includeObject»'
- «ENDFOR»
- ),
- «ENDIF»
- «IF excludeObjectList.size > 0»
- a_exclude_objects => ut_varchar2_list(
- «FOR excludeObject : excludeObjectList SEPARATOR ", "»
- '«excludeObject»'
- «ENDFOR»
- ),
- «ENDIF»
- a_reporter => ut_coverage_html_reporter()
- )
- )
- '''
- val lines = jdbcTemplate.queryForList(sql, String)
- val sb = new StringBuilder
- for (line : lines.filter[it !== null]) {
- sb.append(line)
- sb.append("\n")
- }
- return sb.toString
- }
-
- /**
- * gets dependencies of a given object.
- *
- * The result can be used as input for the includeObjectList in htmlCodeCoverage
- * The scope is reduced to non-oracle maintained schemas.
- *
- * Oracle introduced the column ORACLE_MAINTAINED in 12.1.
- * To simplify the query and compatibility the result of the following
- * query is included
- *
- * SELECT '''' || listagg(username, ''', ''') || '''' AS oracle_maintained_users
- * FROM dba_users
- * WHERE oracle_maintained = 'Y'
- * ORDER BY username;
- *
- * The result may include test packages
- *
- * @param name test package name
- * @return list of dependencies in the current schema
- */
- def List includes(String owner, String name) {
- val sql = '''
- select referenced_owner || '.' || referenced_name AS dep_name
- from «IF dbaViewAccessible»dba«ELSE»all«ENDIF»_dependencies
- WHERE owner = upper(?)
- AND name = upper(?)
- AND referenced_owner NOT IN (
- 'SYS', 'SYSTEM', 'XS$NULL', 'OJVMSYS', 'LBACSYS', 'OUTLN', 'SYS$UMF',
- 'DBSNMP', 'APPQOSSYS', 'DBSFWUSER', 'GGSYS', 'ANONYMOUS', 'CTXSYS',
- 'SI_INFORMTN_SCHEMA', 'DVF', 'DVSYS', 'GSMADMIN_INTERNAL', 'ORDPLUGINS',
- 'MDSYS', 'OLAPSYS', 'ORDDATA', 'XDB', 'WMSYS', 'ORDSYS', 'GSMCATUSER',
- 'MDDATA', 'REMOTE_SCHEDULER_AGENT', 'SYSBACKUP', 'GSMUSER', 'APEX_PUBLIC_USER',
- 'SYSRAC', 'AUDSYS', 'DIP', 'SYSKM', 'ORACLE_OCM', 'APEX_INSTANCE_ADMIN_USER',
- 'SYSDG', 'FLOWS_FILES', 'ORDS_METADATA', 'ORDS_PUBLIC_USER'
- )
- AND referenced_owner NOT LIKE 'APEX\_______'
- AND referenced_type IN ('PACKAGE', 'TYPE', 'PROCEDURE', 'FUNCTION', 'TRIGGER')
- '''
- val deps = jdbcTemplate.queryForList(sql, String, #[owner, name])
- return deps
- }
-
- /**
- * gets source of an object from the database via DBMS_METADATA
- *
- * @param owner owner of the object (schema)
- * @param objectType expected object types are PACKAGE, PACKAGE BODY
- * @param objectName name of the object
- * @return the source code of the object
- * @throws DataAccessException if there is a problem
- */
- def getSource(String owner, String objectType, String objectName) {
- // dbms_metadata uses slightly different objectTypes
- val fixedObjectType = if (objectType == "PACKAGE") {
- "PACKAGE_SPEC"
- } else if (objectType == "PACKAGE BODY") {
- "PACKAGE_BODY"
- } else {
- objectType
- }
- val sql = '''
- BEGIN
- ? := sys.dbms_metadata.get_ddl(
- schema => ?,
- object_type => ?,
- name => ?
- );
- END;
- '''
- val ret = jdbcTemplate.execute(sql, new CallableStatementCallback() {
- override String doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
- cs.registerOutParameter(1, Types.CLOB);
- cs.setString(2, owner)
- cs.setString(3, fixedObjectType)
- cs.setString(4, objectName)
- cs.execute
- return cs.getString(1)
- }
- })
- return ret
- }
-
- /**
- * gets the object type of a database object
- *
- * The object types "PACKAGE BODY", "TYPE BODY" have higher priority.
- * "PACKAGE" OR "TYPE" will be returned only when no body exists.
- *
- * @param owner owner of the object (schema)
- * @param objectName name of the object
- * @return the object type, e.g. PACKAGE BODY, TYPE BODY, PROCEDURE, FUNCTION
- */
- def getObjectType(String owner, String objectName) {
- val sql = '''
- SELECT object_type
- FROM (
- SELECT object_type
- FROM «IF dbaViewAccessible»dba«ELSE»all«ENDIF»_objects
- WHERE owner = ?
- AND object_name = ?
- ORDER BY decode(object_type, 'PACKAGE', 10, 'TYPE', 10, 'SYNONYM', 20, 1)
- )
- WHERE rownum = 1
- '''
- val objectType = jdbcTemplate.queryForObject(sql, #[owner, objectName], String)
- return objectType
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/exception/GenericDatabaseAccessException.java b/sqldev/src/main/java/org/utplsql/sqldev/exception/GenericDatabaseAccessException.java
new file mode 100644
index 00000000..a343592b
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/exception/GenericDatabaseAccessException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.exception;
+
+public class GenericDatabaseAccessException extends RuntimeException {
+ private static final long serialVersionUID = -5489500390596695295L;
+
+ public GenericDatabaseAccessException(String message) {
+ super(message);
+ }
+
+ public GenericDatabaseAccessException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public GenericDatabaseAccessException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/RealtimeReporterEvent.xtend b/sqldev/src/main/java/org/utplsql/sqldev/exception/GenericRuntimeException.java
similarity index 53%
rename from sqldev/src/main/java/org/utplsql/sqldev/model/runner/RealtimeReporterEvent.xtend
rename to sqldev/src/main/java/org/utplsql/sqldev/exception/GenericRuntimeException.java
index 5b6ec099..5a89ad13 100644
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/RealtimeReporterEvent.xtend
+++ b/sqldev/src/main/java/org/utplsql/sqldev/exception/GenericRuntimeException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Philipp Salvisberg
+ * Copyright 2020 Philipp Salvisberg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,9 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.utplsql.sqldev.model.runner
+package org.utplsql.sqldev.exception;
-import org.utplsql.sqldev.model.AbstractModel
+public class GenericRuntimeException extends RuntimeException {
+ private static final long serialVersionUID = -6258053040039956647L;
-abstract class RealtimeReporterEvent extends AbstractModel {
+ public GenericRuntimeException(String message) {
+ super(message);
+ }
+
+ public GenericRuntimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public GenericRuntimeException(Throwable cause) {
+ super(cause);
+ }
}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.java b/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.java
new file mode 100644
index 00000000..a7e74654
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.java
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.menu;
+
+import java.awt.Component;
+import java.net.URL;
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import javax.swing.JEditorPane;
+
+import org.utplsql.sqldev.coverage.CodeCoverageReporter;
+import org.utplsql.sqldev.dal.RealtimeReporterDao;
+import org.utplsql.sqldev.dal.UtplsqlDao;
+import org.utplsql.sqldev.exception.GenericRuntimeException;
+import org.utplsql.sqldev.model.DatabaseTools;
+import org.utplsql.sqldev.model.StringTools;
+import org.utplsql.sqldev.model.URLTools;
+import org.utplsql.sqldev.model.oddgen.GenContext;
+import org.utplsql.sqldev.model.parser.PlsqlObject;
+import org.utplsql.sqldev.model.preference.PreferenceModel;
+import org.utplsql.sqldev.oddgen.TestTemplate;
+import org.utplsql.sqldev.parser.UtplsqlParser;
+import org.utplsql.sqldev.runner.UtplsqlRunner;
+import org.utplsql.sqldev.runner.UtplsqlWorksheetRunner;
+
+import oracle.dbtools.raptor.navigator.db.DBNavigatorWindow;
+import oracle.dbtools.raptor.navigator.db.DatabaseConnection;
+import oracle.dbtools.raptor.navigator.impl.ChildObjectElement;
+import oracle.dbtools.raptor.navigator.impl.DatabaseSourceNode;
+import oracle.dbtools.raptor.navigator.impl.ObjectFolder;
+import oracle.dbtools.raptor.navigator.impl.SchemaFolder;
+import oracle.dbtools.raptor.navigator.plsql.PlSqlNode;
+import oracle.dbtools.raptor.utils.Connections;
+import oracle.dbtools.worksheet.editor.Worksheet;
+import oracle.ide.Context;
+import oracle.ide.Ide;
+import oracle.ide.config.Preferences;
+import oracle.ide.controller.Controller;
+import oracle.ide.controller.IdeAction;
+import oracle.ide.editor.Editor;
+import oracle.ide.model.Node;
+import oracle.ide.view.View;
+
+@SuppressWarnings("all")
+public class UtplsqlController implements Controller {
+ private static final Logger logger = Logger.getLogger(UtplsqlController.class.getName());
+
+ public static int UTPLSQL_TEST_CMD_ID = (Ide.findCmdID("utplsql.test")).intValue();
+ public static int UTPLSQL_COVERAGE_CMD_ID = (Ide.findCmdID("utplsql.coverage")).intValue();
+ public static int UTPLSQL_GENERATE_CMD_ID = (Ide.findCmdID("utplsql.generate")).intValue();
+ public static final IdeAction UTPLSQL_TEST_ACTION = IdeAction.get(UTPLSQL_TEST_CMD_ID);
+ public static final IdeAction UTPLSQL_COVERAGE_ACTION = IdeAction.get(UTPLSQL_COVERAGE_CMD_ID);
+ public static final IdeAction UTPLSQL_GENERATE_ACTION = IdeAction.get(UTPLSQL_GENERATE_CMD_ID);
+
+ @Override
+ public boolean handleEvent(final IdeAction action, final Context context) {
+ try {
+ if (action.getCommandId() == UTPLSQL_TEST_CMD_ID) {
+ logger.finer(() -> "handle utplsql.test");
+ runTest(context);
+ return true;
+ } else if (action.getCommandId() == UTPLSQL_COVERAGE_CMD_ID) {
+ logger.finer(() -> "handle utplsql.coverage");
+ codeCoverage(context);
+ return true;
+ } else if (action.getCommandId() == UTPLSQL_GENERATE_CMD_ID) {
+ logger.finer(() -> "handle utplsql.generate");
+ generateTest(context);
+ return true;
+ }
+ } catch (Exception e) {
+ final String msg = "Failed to handle event for action " + action.toString() + ".";
+ logger.severe(() -> msg);
+ throw new GenericRuntimeException(msg, e);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean update(final IdeAction action, final Context context) {
+ if (action.getCommandId() == UTPLSQL_TEST_CMD_ID || action.getCommandId() == UTPLSQL_COVERAGE_CMD_ID) {
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ action.setEnabled(false);
+ final View view = context.getView();
+ if (view instanceof Editor) {
+ final Component component = ((Editor) view).getDefaultFocusComponent();
+ if (component instanceof JEditorPane) {
+ if (preferences.isCheckRunUtplsqlTest()) {
+ final Node node = context.getNode();
+ String connectionName = null;
+ String owner = null;
+ if (node instanceof DatabaseSourceNode) {
+ connectionName = ((DatabaseSourceNode) node).getConnectionName();
+ owner = ((DatabaseSourceNode) node).getOwner();
+ } else {
+ if (view instanceof Worksheet) {
+ connectionName = ((Worksheet) view).getConnectionName();
+ }
+ }
+ logger.fine("connectionName: " + connectionName);
+ final String text = ((JEditorPane) component).getText();
+ final Connection conn = DatabaseTools.getConnection(connectionName);
+ final UtplsqlParser parser = new UtplsqlParser(text, conn, owner);
+ if (!parser.getPathAt(((JEditorPane) component).getCaretPosition()).isEmpty()) {
+ action.setEnabled(true);
+ }
+ } else {
+ action.setEnabled(true);
+ }
+ }
+ } else if (view instanceof DBNavigatorWindow) {
+ action.setEnabled(true);
+ // disable action if a node in the selection is not runnable
+ for (int i = 0; i < context.getSelection().length; i++) {
+ logger.fine("section " + i + " is " + context.getSelection()[i].toString() + " of class "
+ + context.getSelection()[i].getClass().getName());
+ if (action.isEnabled()) {
+ final Object element = context.getSelection()[i];
+ final String connectionName = URLTools.getConnectionName(getURL(context));
+ if (Connections.getInstance().isConnectionOpen(connectionName)) {
+ Connection conn = DatabaseTools.getConnection(connectionName);
+ final UtplsqlDao dao = new UtplsqlDao(conn);
+ if (preferences.isCheckRunUtplsqlTest() && dao.isUtAnnotationManagerInstalled()) {
+ if (element instanceof DatabaseConnection) {
+ final String schema = DatabaseTools.getSchema((DatabaseConnection) element);
+ action.setEnabled(dao.containsUtplsqlTest(schema));
+ } else if (element instanceof SchemaFolder) {
+ final String schema = ((SchemaFolder) element).getSchemaName();
+ action.setEnabled(dao.containsUtplsqlTest(schema));
+ } else if (element instanceof ObjectFolder) {
+ final String schema = URLTools.getSchema(((ObjectFolder) element).getURL());
+ action.setEnabled(dao.containsUtplsqlTest(schema));
+ } else if (element instanceof PlSqlNode) {
+ final String schema = ((PlSqlNode) element).getOwner();
+ final String objectName = ((PlSqlNode) element).getObjectName();
+ action.setEnabled(dao.containsUtplsqlTest(schema, objectName));
+ } else if (element instanceof ChildObjectElement) {
+ final String schema = URLTools.getSchema(((ChildObjectElement) element).getURL());
+ final String objectName = URLTools.getMemberObject(((ChildObjectElement) element).getURL());
+ final String subObjectName = ((ChildObjectElement) element).getShortLabel();
+ action.setEnabled(dao.containsUtplsqlTest(schema, objectName, subObjectName));
+ }
+ }
+ } else {
+ action.setEnabled(false);
+ }
+ }
+ }
+ }
+ return true;
+ } else if (action.getCommandId() == UTPLSQL_GENERATE_CMD_ID) {
+ action.setEnabled(false);
+ // enable if generation is possible
+ final View view = context.getView();
+ if (view instanceof Editor) {
+ final Component component = ((Editor) view).getDefaultFocusComponent();
+ if (component instanceof JEditorPane) {
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ if (preferences.isCheckGenerateUtplsqlTest()) {
+ final String text = ((JEditorPane) component).getText();
+ final UtplsqlParser parser = new UtplsqlParser(text);
+ PlsqlObject plsqlObject = parser.getObjectAt(((JEditorPane) component).getCaretPosition());
+ action.setEnabled(plsqlObject != null);
+ } else {
+ action.setEnabled(true);
+ }
+ }
+ } else if (view instanceof DBNavigatorWindow) {
+ // multiselection is not supported, use oddgen to generte tests for multiple objects
+ if (context.getSelection().length == 1) {
+ final Object element = context.getSelection()[0];
+ if (element instanceof PlSqlNode) {
+ final String ot = ((PlSqlNode) element).getObjectType();
+ if (ot.startsWith("PACKAGE") || ot.startsWith("TYPE") || "FUNCTION".equals(ot) || "PROCEDURE".equals(ot)) {
+ action.setEnabled(true);
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private String getPath(final Object element) {
+ String path = null;
+ if (element instanceof DatabaseConnection) {
+ path = DatabaseTools.getSchema((DatabaseConnection) element);
+ } else if (element instanceof SchemaFolder) {
+ path = ((SchemaFolder) element).getSchemaName();
+ } else if (element instanceof ObjectFolder) {
+ path = URLTools.getSchema(((ObjectFolder) element).getURL());
+ } else if (element instanceof PlSqlNode) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(((PlSqlNode) element).getOwner());
+ sb.append(".");
+ sb.append(((PlSqlNode) element).getObjectName());
+ path = sb.toString();
+ } else if (element instanceof ChildObjectElement) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(URLTools.getSchema(((ChildObjectElement) element).getURL()));
+ sb.append(".");
+ sb.append(URLTools.getMemberObject(((ChildObjectElement) element).getURL()));
+ sb.append(".");
+ sb.append( ((ChildObjectElement) element).getShortLabel());
+ path = sb.toString();
+ } else {
+ path = "";
+ }
+ logger.fine("path: " + path);
+ return path;
+ }
+
+ private ArrayList getPathList(final Context context) {
+ final ArrayList pathList = new ArrayList<>();
+ for (int i = 0; i < context.getSelection().length; i++) {
+ final Object element = context.getSelection()[i];
+ pathList.add(getPath(element));
+ }
+ return pathList;
+ }
+
+ private ArrayList getPathList(final String path) {
+ final ArrayList pathList = new ArrayList<>();
+ pathList.add(path);
+ return pathList;
+ }
+
+ private ArrayList dedupPathList(final List pathList) {
+ final HashSet set = new HashSet<>();
+ for (final String path : pathList) {
+ set.add(path);
+ }
+ final ArrayList ret = new ArrayList<>();
+ final Pattern p = Pattern.compile("(((([^\\.]+)\\.)?[^\\.]+)\\.)?[^\\.]+");
+ for (final String path : set) {
+ final Matcher m = p.matcher(path);
+ if (m.matches()) {
+ final String parent1 = m.group(4); // user
+ final String parent2 = m.group(2); // user.package
+ if (parent1 == null || !set.contains(parent1)) {
+ if (parent2 == null || !set.contains(parent2)) {
+ ret.add(path);
+ }
+ }
+ } else {
+ logger.severe("path: " + path + " did not match " + p.toString() + ", this is unexected!");
+ }
+ }
+ return ret;
+ }
+
+ private URL getURL(final Context context) {
+ URL url = null;
+ final Object element = context.getSelection()[0];
+ if (element instanceof DatabaseConnection) {
+ url = ((DatabaseConnection) element).getURL();
+ } else if (element instanceof SchemaFolder) {
+ url = ((SchemaFolder) element).getURL();
+ } else if (element instanceof ObjectFolder) {
+ url = ((ObjectFolder) element).getURL();
+ } else if (element instanceof PlSqlNode) {
+ url = ((PlSqlNode) element).getURL();
+ } else if (element instanceof ChildObjectElement) {
+ url = ((ChildObjectElement) element).getURL();
+ }
+ logger.fine("url: " + url);
+ return url;
+ }
+
+ private void populateGenContext(final GenContext genContext, final PreferenceModel preferences) {
+ genContext.setTestPackagePrefix(preferences.getTestPackagePrefix().toLowerCase());
+ genContext.setTestPackageSuffix(preferences.getTestPackageSuffix().toLowerCase());
+ genContext.setTestUnitPrefix(preferences.getTestUnitPrefix().toLowerCase());
+ genContext.setTestUnitSuffix(preferences.getTestUnitSuffix().toLowerCase());
+ genContext.setNumberOfTestsPerUnit(preferences.getNumberOfTestsPerUnit());
+ genContext.setGenerateComments(preferences.isGenerateComments());
+ genContext.setDisableTests(preferences.isDisableTests());
+ genContext.setSuitePath(preferences.getSuitePath().toLowerCase());
+ genContext.setIndentSpaces(preferences.getIndentSpaces());
+ }
+
+ private GenContext getGenContext(final Context context) {
+ final String connectionName = URLTools.getConnectionName(getURL(context));
+ final GenContext genContext = new GenContext();
+ if (Connections.getInstance().isConnectionOpen(connectionName)) {
+ genContext.setConn(DatabaseTools.getConnection(connectionName));
+ final Object element = context.getSelection()[0];
+ if (element instanceof PlSqlNode) {
+ genContext.setObjectType(((PlSqlNode) element).getObjectType().replace(" BODY", ""));
+ genContext.setObjectName(((PlSqlNode) element).getObjectName());
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ populateGenContext(genContext, preferences);
+ }
+ }
+ return genContext;
+ }
+
+ public void runTest(final Context context) {
+ final View view = context.getView();
+ final Node node = context.getNode();
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Run utPLSQL from view ");
+ sb.append(view != null ? view.getClass().getName() : "???");
+ sb.append(" and node ");
+ sb.append(node != null ? node.getClass().getName() : "???");
+ sb.append(".");
+ logger.finer(() -> sb.toString());
+ if (view instanceof Editor) {
+ final Component component = ((Editor) view).getDefaultFocusComponent();
+ if (component instanceof JEditorPane) {
+ String connectionName = null;
+ String owner = null;
+ if (node instanceof DatabaseSourceNode) {
+ connectionName = ((DatabaseSourceNode) node).getConnectionName();
+ owner = ((DatabaseSourceNode) node).getOwner();
+ } else {
+ if (view instanceof Worksheet) {
+ connectionName = ((Worksheet) view).getConnectionName();
+ }
+ }
+ logger.fine("connectionName: " + connectionName);
+ final Connection conn = DatabaseTools.getConnection(connectionName);
+ String text = ((JEditorPane) component).getText();
+ final UtplsqlParser parser = new UtplsqlParser(text, conn, owner);
+ final int position = ((JEditorPane) component).getCaretPosition();
+ final String path = parser.getPathAt(position);
+ final RealtimeReporterDao rrDao = new RealtimeReporterDao(conn);
+ if (preferences.isUseRealtimeReporter() && rrDao.isSupported()) {
+ final UtplsqlRunner runner = new UtplsqlRunner(getPathList(path), connectionName);
+ runner.runTestAsync();
+ } else {
+ final UtplsqlWorksheetRunner worksheet = new UtplsqlWorksheetRunner(getPathList(path), connectionName);
+ worksheet.runTestAsync();
+ }
+ }
+ } else if (view instanceof DBNavigatorWindow) {
+ final URL url = getURL(context);
+ if (url != null) {
+ final String connectionName = URLTools.getConnectionName(url);
+ logger.fine("connectionName: " + connectionName);
+ final Connection conn = DatabaseTools.getConnection(connectionName);
+ final RealtimeReporterDao rrDao = new RealtimeReporterDao(conn);
+ final ArrayList pathList = dedupPathList(getPathList(context));
+ if (preferences.isUseRealtimeReporter() && rrDao.isSupported()) {
+ final UtplsqlRunner runner = new UtplsqlRunner(pathList, connectionName);
+ runner.runTestAsync();
+ } else {
+ final UtplsqlWorksheetRunner worksheet = new UtplsqlWorksheetRunner(pathList, connectionName);
+ worksheet.runTestAsync();
+ }
+ }
+ }
+ }
+
+ public List dependencies(final String name, final String connectionName) {
+ List ret = null;
+ if (connectionName != null) {
+ final String owner = DatabaseTools.getSchema(connectionName);
+ ret = dependencies(owner, name, connectionName);
+ }
+ return ret;
+ }
+
+ public List dependencies(final String owner, final String name, final String connectionName) {
+ List ret = null;
+ if (connectionName != null) {
+ Connection conn = DatabaseTools.getConnection(connectionName);
+ final UtplsqlDao dao = new UtplsqlDao(conn);
+ ret = dao.includes(owner, name);
+ }
+ return ret;
+ }
+
+ public List dependencies(final Context context, final String connectionName) {
+ final HashSet ret = new HashSet();
+ for (int i = 0; i < context.getSelection().length; i++) {
+ final Object element = context.getSelection()[i];
+ if (element instanceof PlSqlNode) {
+ final String owner = ((PlSqlNode) element).getOwner();
+ final String objectName = ((PlSqlNode) element).getObjectName();
+ final List dep = dependencies(owner, objectName, connectionName);
+ ret.addAll(dep);
+ } else {
+ if (element instanceof ChildObjectElement) {
+ final String owner = URLTools.getSchema(((ChildObjectElement) element).getURL());
+ final String objectName = URLTools.getMemberObject(((ChildObjectElement) element).getURL());
+ final List dep = dependencies(owner, objectName, connectionName);
+ ret.addAll(dep);
+ }
+ }
+ }
+ return ret.stream().sorted().collect(Collectors.toList());
+ }
+
+ public void codeCoverage(final Context context) {
+ final View view = context.getView();
+ final Node node = context.getNode();
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Code coverage from view ");
+ sb.append(view != null ? view.getClass().getName() : "???");
+ sb.append(" and node ");
+ sb.append(node != null ? node.getClass().getName() : "???");
+ sb.append(".");
+ logger.finer(() -> sb.toString());
+ if (view instanceof Editor) {
+ final Component component = ((Editor) view).getDefaultFocusComponent();
+ if (component instanceof JEditorPane) {
+ String connectionName = null;
+ String owner = null;
+ if (node instanceof DatabaseSourceNode) {
+ connectionName = ((DatabaseSourceNode) node).getConnectionName();
+ } else if (view instanceof Worksheet) {
+ connectionName = ((Worksheet) view).getConnectionName();
+ }
+ logger.fine("connectionName: " + connectionName);
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ String text = ((JEditorPane) component).getText();
+ Connection conn = null;
+ if (preferences.isCheckRunUtplsqlTest()) {
+ conn = DatabaseTools.getConnection(connectionName);
+ } else {
+ conn = null;
+ }
+ final UtplsqlParser parser = new UtplsqlParser(text, conn, owner);
+ final int position = ((JEditorPane) component).getCaretPosition();
+ final String path = parser.getPathAt(position);
+ final PlsqlObject object = parser.getObjectAt(position);
+ final List includeObjectList = dependencies(object.getName(), connectionName);
+ final CodeCoverageReporter reporter = new CodeCoverageReporter(getPathList(path), includeObjectList, connectionName);
+ reporter.showParameterWindow();
+ }
+ } else if (view instanceof DBNavigatorWindow) {
+ logger.finer("Code coverage from DB navigator");
+ final URL url = getURL(context);
+ if (url != null) {
+ final String connectionName = URLTools.getConnectionName(url);
+ logger.fine(() -> "connectionName: " + connectionName);
+ final ArrayList pathList = dedupPathList(getPathList(context));
+ logger.fine(() -> "pathlist: " + StringTools.getSimpleCSV(pathList));
+ final List includeObjectList = dependencies(context, connectionName);
+ logger.finer(() -> "includeObjectList: " + StringTools.getSimpleCSV(includeObjectList));
+ final CodeCoverageReporter reporter = new CodeCoverageReporter(pathList, includeObjectList, connectionName);
+ logger.finer(() -> "showing code coverage dialog");
+ reporter.showParameterWindow();
+ logger.finer(() -> "code coverage dialog shown");
+ } else {
+ logger.warning("url is null");
+ }
+ }
+ }
+
+ public void generateTest(final Context context) {
+ final View view = context.getView();
+ final Node node = context.getNode();
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Generate utPLSQL test from view ");
+ sb.append(view != null ? view.getClass().getName() : "???");
+ sb.append(" and node ");
+ sb.append(node != null ? node.getClass().getName() : "???");
+ sb.append(".");
+ logger.finer(() -> sb.toString());
+ if (view instanceof Editor) {
+ final Component component = ((Editor) view).getDefaultFocusComponent();
+ if (component instanceof JEditorPane) {
+ String connectionName = null;
+ if (node instanceof DatabaseSourceNode) {
+ connectionName = ((DatabaseSourceNode) node).getConnectionName();
+ } else if (view instanceof Worksheet) {
+ connectionName = ((Worksheet) view).getConnectionName();
+ }
+ if (connectionName != null) {
+ if (Connections.getInstance().isConnectionOpen(connectionName)) {
+ final GenContext genContext = new GenContext();
+ genContext.setConn(DatabaseTools.getConnection(connectionName));
+ String text = ((JEditorPane) component).getText();
+ final UtplsqlParser parser = new UtplsqlParser(text);
+ final int position = ((JEditorPane) component).getCaretPosition();
+ final PlsqlObject obj = parser.getObjectAt(position);
+ if (obj != null) {
+ genContext.setObjectType(obj.getType().toUpperCase());
+ genContext.setObjectName(obj.getName().toUpperCase());
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ populateGenContext(genContext, preferences);
+ final TestTemplate testTemplate = new TestTemplate(genContext);
+ final String code = testTemplate.generate().toString();
+ UtplsqlWorksheetRunner.openWithCode(code, connectionName);
+ }
+ }
+ }
+ }
+ } else {
+ if (view instanceof DBNavigatorWindow) {
+ final URL url = getURL(context);
+ if (url != null) {
+ final String connectionName = URLTools.getConnectionName(url);
+ GenContext genContext = getGenContext(context);
+ final TestTemplate testTemplate = new TestTemplate(genContext);
+ final String code = testTemplate.generate().toString();
+ UtplsqlWorksheetRunner.openWithCode(code, connectionName);
+ }
+ }
+ }
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend b/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend
deleted file mode 100644
index 28eadd5d..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend
+++ /dev/null
@@ -1,448 +0,0 @@
-/* Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.menu
-
-import java.net.URL
-import java.util.ArrayList
-import java.util.HashSet
-import java.util.List
-import java.util.logging.Logger
-import java.util.regex.Pattern
-import javax.swing.JEditorPane
-import oracle.dbtools.raptor.navigator.db.DBNavigatorWindow
-import oracle.dbtools.raptor.navigator.db.DatabaseConnection
-import oracle.dbtools.raptor.navigator.impl.ChildObjectElement
-import oracle.dbtools.raptor.navigator.impl.DatabaseSourceNode
-import oracle.dbtools.raptor.navigator.impl.ObjectFolder
-import oracle.dbtools.raptor.navigator.impl.SchemaFolder
-import oracle.dbtools.raptor.navigator.plsql.PlSqlNode
-import oracle.dbtools.raptor.utils.Connections
-import oracle.dbtools.worksheet.editor.Worksheet
-import oracle.ide.Context
-import oracle.ide.Ide
-import oracle.ide.config.Preferences
-import oracle.ide.controller.Controller
-import oracle.ide.controller.IdeAction
-import oracle.ide.editor.Editor
-import org.utplsql.sqldev.coverage.CodeCoverageReporter
-import org.utplsql.sqldev.dal.RealtimeReporterDao
-import org.utplsql.sqldev.dal.UtplsqlDao
-import org.utplsql.sqldev.model.URLTools
-import org.utplsql.sqldev.model.oddgen.GenContext
-import org.utplsql.sqldev.model.preference.PreferenceModel
-import org.utplsql.sqldev.oddgen.TestTemplate
-import org.utplsql.sqldev.parser.UtplsqlParser
-import org.utplsql.sqldev.runner.UtplsqlRunner
-import org.utplsql.sqldev.runner.UtplsqlWorksheetRunner
-
-class UtplsqlController implements Controller {
- static final Logger logger = Logger.getLogger(UtplsqlController.name);
- val extension URLTools urlTools = new URLTools
-
- public static int UTPLSQL_TEST_CMD_ID = Ide.findCmdID("utplsql.test")
- public static int UTPLSQL_COVERAGE_CMD_ID = Ide.findCmdID("utplsql.coverage")
- public static int UTPLSQL_GENERATE_CMD_ID = Ide.findCmdID("utplsql.generate")
- public static final IdeAction UTPLSQL_TEST_ACTION = IdeAction.get(UtplsqlController.UTPLSQL_TEST_CMD_ID)
- public static final IdeAction UTPLSQL_COVERAGE_ACTION = IdeAction.get(UtplsqlController.UTPLSQL_COVERAGE_CMD_ID)
- public static final IdeAction UTPLSQL_GENERATE_ACTION = IdeAction.get(UtplsqlController.UTPLSQL_GENERATE_CMD_ID)
-
- override handleEvent(IdeAction action, Context context) {
- try {
- if (action.commandId === UTPLSQL_TEST_CMD_ID) {
- logger.finer("handle utplsql.test")
- runTest(context)
- return true
- } else if (action.commandId === UTPLSQL_COVERAGE_CMD_ID) {
- logger.finer("handle utplsql.coverage")
- codeCoverage(context)
- return true
- } else if (action.commandId === UTPLSQL_GENERATE_CMD_ID) {
- logger.finer("handle utplsql.generate")
- generateTest(context)
- return true
- }
- } catch (Exception e) {
- logger.severe("Failed to handle event due to exception " + e?.message)
- }
- return false
- }
-
- override update(IdeAction action, Context context) {
- if (action.commandId === UTPLSQL_TEST_CMD_ID || action.commandId === UTPLSQL_COVERAGE_CMD_ID) {
- val preferences = PreferenceModel.getInstance(Preferences.preferences)
- action.enabled = false
- val view = context.view
- if (view instanceof Editor) {
- val component = view.defaultFocusComponent
- if (component instanceof JEditorPane) {
- if (preferences.checkRunUtplsqlTest) {
- val node = context.node
- var String connectionName = null;
- var String owner = null;
- if (node instanceof DatabaseSourceNode) {
- connectionName = node.connectionName
- owner = node.owner
- } else if (view instanceof Worksheet) {
- connectionName = view.connectionName
- }
- logger.fine('''connectionName: «connectionName»''')
- val parser = new UtplsqlParser(component.text, Connections.instance.getConnection(connectionName), owner)
- if (!parser.getPathAt(component.caretPosition).empty) {
- action.enabled = true
- }
- } else {
- action.enabled = true
- }
- }
- } else if (view instanceof DBNavigatorWindow) {
- action.enabled = true
- // disable action if a node in the selection is not runnable
- for (i : 0 ..< context.selection.length) {
- logger.fine('''section «i» is «context.selection.get(i).toString» of class «context.selection.get(i).class.name»''')
- if (action.enabled) {
- val element = context.selection.get(i)
- if (Connections.instance.isConnectionOpen(context.URL.connectionName)) {
- val dao = new UtplsqlDao(Connections.instance.getConnection(context.URL.connectionName))
- if (preferences.checkRunUtplsqlTest && dao.utAnnotationManagerInstalled) {
- if (element instanceof DatabaseConnection) {
- action.enabled = dao.containsUtplsqlTest(element.connection.schema)
- } else if (element instanceof SchemaFolder) {
- action.enabled = dao.containsUtplsqlTest(element.schemaName)
- } else if (element instanceof ObjectFolder) {
- action.enabled = dao.containsUtplsqlTest(element.URL.schema)
- } else if (element instanceof PlSqlNode) {
- action.enabled = dao.containsUtplsqlTest(element.owner, element.objectName)
- } else if (element instanceof ChildObjectElement) {
- action.enabled = dao.containsUtplsqlTest(element.URL.schema, element.URL.memberObject, element.shortLabel)
- }
- }
- } else {
- action.enabled = false
- }
- }
- }
- }
- return true
- } else if (action.commandId === UTPLSQL_GENERATE_CMD_ID) {
- action.enabled = false
- // enable if generation is possible
- val view = context.view
- if (view instanceof Editor) {
- val component = view.defaultFocusComponent
- if (component instanceof JEditorPane) {
- val preferences = PreferenceModel.getInstance(Preferences.preferences)
- if (preferences.checkGenerateUtplsqlTest) {
- val parser = new UtplsqlParser(component.text)
- action.enabled = parser.getObjectAt(component.caretPosition) !== null
- } else {
- action.enabled = true
- }
- }
- } else if (view instanceof DBNavigatorWindow) {
- // multiselection is not supported, use oddgen to generte tests for multiple objects
- if (context.selection.length == 1) {
- val element = context.selection.get(0)
- if (element instanceof PlSqlNode) {
- val ot = element.objectType
- if (ot.startsWith("PACKAGE") || ot.startsWith("TYPE") || ot == "FUNCTION" || ot == "PROCEDURE") {
- action.enabled = true
- }
- }
- }
- }
- }
- return false
- }
-
- private def getPath(Object element) {
- var String path
- if (element instanceof DatabaseConnection) {
- path = element.connection.schema
- } else if (element instanceof SchemaFolder) {
- path = element.schemaName
- } else if (element instanceof ObjectFolder) {
- path = element.URL.schema
- } else if (element instanceof PlSqlNode) {
- path = '''«element.owner».«element.objectName»'''
- } else if (element instanceof ChildObjectElement) {
- path = '''«element.URL.schema».«element.URL.memberObject».«element.shortLabel»'''
- } else {
- path = ""
- }
- logger.fine('''path: «path»''')
- return path
- }
-
- private def getPathList(Context context) {
- val pathList = new ArrayList()
- for (i : 0 ..< context.selection.length) {
- val element = context.selection.get(i)
- pathList.add(element.path)
- }
- return pathList
- }
-
- private def getPathList(String path) {
- val pathList = new ArrayList
- pathList.add(path)
- return pathList
- }
-
- private def dedupPathList(List pathList) {
- val set = new HashSet
- for (path : pathList) {
- set.add(path)
- }
- val ret = new ArrayList
- val p = Pattern.compile("(((([^\\.]+)\\.)?[^\\.]+)\\.)?[^\\.]+")
- for (path : set) {
- val m = p.matcher(path)
- if (m.matches()) {
- val parent1 = m.group(4) // user
- val parent2 = m.group(2) // user.package
- if (parent1 === null || !set.contains(parent1)) {
- if (parent2 === null || !set.contains(parent2)) {
- ret.add(path)
- }
- }
- } else {
- logger.severe('''path: «path» did not match «p.toString», this is unexected!''')
- }
- }
- return ret
- }
-
- private def getURL(Context context) {
- var URL url
- val element = context.selection.get(0)
- if (element instanceof DatabaseConnection) {
- url = element.URL
- } else if (element instanceof SchemaFolder) {
- url = element.URL
- } else if (element instanceof ObjectFolder) {
- url = element.URL
- } else if (element instanceof PlSqlNode) {
- url = element.URL
- } else if (element instanceof ChildObjectElement) {
- url = element.URL
- }
- logger.fine('''url: «url»''')
- return url
- }
-
- private def void populateGenContext(GenContext genContext, PreferenceModel preferences) {
- genContext.testPackagePrefix = preferences.testPackagePrefix.toLowerCase
- genContext.testPackageSuffix = preferences.testPackageSuffix.toLowerCase
- genContext.testUnitPrefix = preferences.testUnitPrefix.toLowerCase
- genContext.testUnitSuffix = preferences.testUnitSuffix.toLowerCase
- genContext.numberOfTestsPerUnit = preferences.numberOfTestsPerUnit
- genContext.generateComments = preferences.generateComments
- genContext.disableTests = preferences.disableTests
- genContext.suitePath = preferences.suitePath.toLowerCase
- genContext.indentSpaces = preferences.indentSpaces
- }
-
- private def getGenContext(Context context) {
- val connectionName = context.URL.connectionName
- val genContext = new GenContext
- if (Connections.instance.isConnectionOpen(connectionName)) {
- genContext.conn = Connections.instance.getConnection(connectionName)
- val element = context.selection.get(0)
- if (element instanceof PlSqlNode) {
- genContext.objectType = element.objectType.replace(" BODY", "")
- genContext.objectName = element.objectName
- val preferences = PreferenceModel.getInstance(Preferences.preferences)
- populateGenContext(genContext, preferences)
- }
- }
- return genContext
- }
-
- def runTest(Context context) {
- val view = context.view
- val node = context.node
- val preferences = PreferenceModel.getInstance(Preferences.preferences)
- logger.finer('''Run utPLSQL from view «view?.class?.name» and node «node?.class?.name».''')
- if (view instanceof Editor) {
- val component = view.defaultFocusComponent
- if (component instanceof JEditorPane) {
- var String connectionName = null;
- var String owner = null;
- if (node instanceof DatabaseSourceNode) {
- connectionName = node.connectionName
- owner = node.owner
- } else if (view instanceof Worksheet) {
- connectionName = view.connectionName
- }
- logger.fine('''connectionName: «connectionName»''')
- // issue 59 - always use a connection to ensure the utPL/SQL annotation API is used
- val conn = Connections.instance.getConnection(connectionName)
- val parser = new UtplsqlParser(component.text, conn, owner)
- val position = component.caretPosition
- val path = parser.getPathAt(position)
- val rrDao = new RealtimeReporterDao(conn)
- if (preferences.useRealtimeReporter && rrDao.supported) {
- val runner = new UtplsqlRunner(path.pathList, connectionName)
- runner.runTestAsync
-
- } else {
- val worksheet = new UtplsqlWorksheetRunner(path.pathList, connectionName)
- worksheet.runTestAsync
- }
- }
- } else if (view instanceof DBNavigatorWindow) {
- val url=context.URL
- if (url !== null) {
- val connectionName = url.connectionName
- logger.fine('''connectionName: «connectionName»''')
- val conn = Connections.instance.getConnection(connectionName)
- val rrDao = new RealtimeReporterDao(conn)
- val pathList=context.pathList.dedupPathList
- if (preferences.useRealtimeReporter && rrDao.supported) {
- val runner = new UtplsqlRunner(pathList, connectionName)
- runner.runTestAsync
- } else {
- val worksheet = new UtplsqlWorksheetRunner(pathList, connectionName)
- worksheet.runTestAsync
- }
- }
- }
- }
-
- def List dependencies(String name, String connectionName) {
- var List ret = null
- if (connectionName !== null) {
- val owner = Connections.instance.getConnection(connectionName).schema
- ret = dependencies(owner, name, connectionName)
- }
- return ret
- }
-
- def List dependencies(String owner, String name, String connectionName) {
- var List ret = null
- if (connectionName !== null) {
- val dao = new UtplsqlDao(Connections.instance.getConnection(connectionName))
- ret = dao.includes(owner, name)
- }
- return ret
- }
-
- def List dependencies(Context context, String connectionName) {
- val HashSet ret = new HashSet
- for (i : 0 ..< context.selection.length) {
- val element = context.selection.get(i)
- if (element instanceof PlSqlNode) {
- val dep = dependencies(element.owner, element.objectName, connectionName)
- for (d : dep) {
- ret.add(d)
- }
- } else if (element instanceof ChildObjectElement) {
- val dep = dependencies(element.URL.schema, element.URL.memberObject, connectionName)
- for (d : dep) {
- ret.add(d)
- }
- }
- }
- return ret.toList.sortBy[it]
- }
-
- def codeCoverage(Context context) {
- val view = context.view
- val node = context.node
- logger.finer('''Code coverage from view «view?.class?.name» and node «node?.class?.name».''')
- if (view instanceof Editor) {
- val component = view.defaultFocusComponent
- if (component instanceof JEditorPane) {
- var String connectionName = null;
- var String owner = null;
- if (node instanceof DatabaseSourceNode) {
- connectionName = node.connectionName
- } else if (view instanceof Worksheet) {
- connectionName = view.connectionName
- }
- logger.fine('''connectionName: «connectionName»''')
- val preferences = PreferenceModel.getInstance(Preferences.preferences)
- val parser = new UtplsqlParser(component.text, if (preferences.checkRunUtplsqlTest) {Connections.instance.getConnection(connectionName)} else {null}, owner)
- val position = component.caretPosition
- val path = parser.getPathAt(position)
- val object = parser.getObjectAt(position)
- val includeObjectList = dependencies(object.name, connectionName)
- val reporter = new CodeCoverageReporter(path.pathList, includeObjectList, connectionName)
- reporter.showParameterWindow
- }
- } else if (view instanceof DBNavigatorWindow) {
- logger.finer("Code coverage from DB navigator")
- val url=context.URL
- if (url !== null) {
- val connectionName = url.connectionName
- logger.fine('''connectionName: «connectionName»''')
- val pathList=context.pathList.dedupPathList
- logger.finer('''pathList: «pathList»''')
- val includeObjectList = dependencies(context, connectionName)
- logger.finer('''includeObjectList: «includeObjectList»''')
- val reporter = new CodeCoverageReporter(pathList, includeObjectList, connectionName)
- logger.finer("showing code coverage dialog")
- reporter.showParameterWindow
- logger.finer("code coverage dialog shown")
- } else {
- logger.warning('''url is null''')
- }
- }
- }
-
- def generateTest(Context context) {
- val view = context.view
- val node = context.node
- logger.finer('''Generate utPLSQL test from view «view?.class?.name» and node «node?.class?.name».''')
- if (view instanceof Editor) {
- val component = view.defaultFocusComponent
- if (component instanceof JEditorPane) {
- var String connectionName = null;
- if (node instanceof DatabaseSourceNode) {
- connectionName = node.connectionName
- } else if (view instanceof Worksheet) {
- connectionName = view.connectionName
- }
- if (connectionName !== null) {
- if (Connections.instance.isConnectionOpen(connectionName)) {
- val genContext = new GenContext
- genContext.conn = Connections.instance.getConnection(connectionName)
- val parser = new UtplsqlParser(component.text)
- val position = component.caretPosition
- val obj = parser.getObjectAt(position)
- if (obj !== null) {
- genContext.objectType = obj.type.toUpperCase
- genContext.objectName = obj.name.toUpperCase
- val preferences = PreferenceModel.getInstance(Preferences.preferences)
- populateGenContext(genContext, preferences)
- val testTemplate = new TestTemplate(genContext)
- val code = testTemplate.generate.toString
- UtplsqlWorksheetRunner.openWithCode(code, connectionName)
- }
- }
- }
- }
-
- } else if (view instanceof DBNavigatorWindow) {
- val url=context.URL
- if (url !== null) {
- val connectionName = url.connectionName
- val testTemplate = new TestTemplate(context.genContext)
- val code = testTemplate.generate.toString
- UtplsqlWorksheetRunner.openWithCode(code, connectionName)
- }
- }
- }
-}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/DatabaseTools.java b/sqldev/src/main/java/org/utplsql/sqldev/model/DatabaseTools.java
new file mode 100644
index 00000000..9c2365ea
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/DatabaseTools.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2020 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.utplsql.sqldev.exception.GenericDatabaseAccessException;
+import org.utplsql.sqldev.exception.GenericRuntimeException;
+
+import oracle.dbtools.raptor.navigator.db.DatabaseConnection;
+import oracle.dbtools.raptor.utils.Connections;
+import oracle.javatools.db.DBException;
+import oracle.jdeveloper.db.ConnectionException;
+
+public class DatabaseTools {
+ // do not instantiate this class
+ private DatabaseTools() {
+ super();
+ }
+
+ public static Connection getConnection(DataSource dataSource) {
+ try {
+ return dataSource.getConnection();
+ } catch (SQLException e) {
+ throw new GenericDatabaseAccessException("Error getting connection.", e);
+ }
+ }
+
+ public static Connection getConnection(DatabaseConnection conn) {
+ try {
+ return conn.getConnection();
+ } catch (IOException e) {
+ final String msg = "Error getting connection for " + conn.getConnectionName() + ".";
+ throw new GenericDatabaseAccessException(msg, e);
+ }
+ }
+
+ public static Connection getConnection(String connectionName) {
+ try {
+ return Connections.getInstance().getConnection(connectionName);
+ } catch (DBException e) {
+ final String msg = "Error getting connection for " + connectionName + ".";
+ throw new GenericDatabaseAccessException(msg, e);
+ }
+ }
+
+ public static Connection cloneConnection(String connectionName) {
+ final Connection conn = getConnection(connectionName);
+ try {
+ return Connections.getInstance().cloneConnection(conn);
+ } catch (ConnectionException e) {
+ final String msg = "Error cloning connection " + connectionName + ".";
+ throw new GenericDatabaseAccessException(msg, e);
+ }
+ }
+
+ private static String createTemporaryConnection(String connectionName) {
+ try {
+ return Connections.getInstance().createTemporaryConnection(connectionName);
+ } catch (Throwable e) {
+ final String msg = "Error creating temporary connection based on " + connectionName + ".";
+ throw new GenericDatabaseAccessException(msg, e);
+ }
+ }
+
+ private static String createPrivateConnection(String connectionName) {
+ try {
+ return Connections.getInstance().createPrivateConnection(connectionName);
+ } catch (Throwable e) {
+ final String msg = "Error creating private connection based on " + connectionName + ".";
+ throw new GenericDatabaseAccessException(msg, e);
+ }
+ }
+
+ public static String createTemporaryOrPrivateConnection(String connectionName) {
+ // Private connections are closed in SQL Developer < 17.4.0 when the worksheet
+ // is closed, but in SQL Developer > 17.4.0 private connections are not closed.
+ // Temporary connections have been introduced in SQL Developer 17.4.0. They will
+ // be always closed, when a worksheet is closed.
+ // Hence we try to use temporary connections whenever possible. See also
+ // https://github.com/utPLSQL/utPLSQL-SQLDeveloper/issues/47 .
+ try {
+ return createTemporaryConnection(connectionName);
+ } catch (GenericDatabaseAccessException e) {
+ return createPrivateConnection(connectionName);
+ }
+ }
+
+ public static boolean isConnectionClosed(Connection conn) {
+ try {
+ return conn.isClosed();
+ } catch (SQLException e) {
+ throw new GenericDatabaseAccessException("Error getting status of connection.", e);
+ }
+ }
+
+ public static void closeConnection(Connection conn) {
+ if (!isConnectionClosed(conn)) {
+ try {
+ conn.close();
+ } catch (SQLException e) {
+ throw new GenericDatabaseAccessException("Could not close connection.");
+ }
+ }
+ }
+
+ public static void abortConnection(Connection conn) {
+ final SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
+ try {
+ conn.abort(taskExecutor);
+ } catch (SQLException e) {
+ throw new GenericDatabaseAccessException("Could not abort connection.");
+ }
+ }
+
+ public static String getSchema(Connection conn) {
+ try {
+ return conn.getSchema();
+ } catch (SQLException e) {
+ throw new GenericRuntimeException("Error getting schema name of connection.", e);
+ }
+ }
+
+ public static String getUser(Connection conn) {
+ try {
+ return conn.getMetaData().getUserName();
+ } catch (SQLException e) {
+ throw new GenericRuntimeException("Error getting user name of connection.", e);
+ }
+ }
+
+ public static String getSchema(DatabaseConnection conn) {
+ return getSchema(getConnection(conn));
+ }
+
+
+ public static String getSchema(String connectionName) {
+ return getSchema(getConnection(connectionName));
+ }
+
+ public static boolean isSupported(final Connection conn) {
+ try {
+ boolean ret = false;
+ if (conn != null && conn.getMetaData().getDatabaseProductName().startsWith("Oracle")
+ && (conn.getMetaData().getDatabaseMajorVersion() == 11
+ && conn.getMetaData().getDatabaseMinorVersion() >= 2
+ || conn.getMetaData().getDatabaseMajorVersion() > 11)) {
+ ret = true;
+ }
+ return ret;
+ } catch (SQLException e) {
+ throw new GenericDatabaseAccessException("Error while getting product version of connection.", e);
+ }
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/FileTools.java b/sqldev/src/main/java/org/utplsql/sqldev/model/FileTools.java
new file mode 100644
index 00000000..02b32e5f
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/FileTools.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.utplsql.sqldev.exception.GenericRuntimeException;
+
+public class FileTools {
+ // do not instantiate this class
+ private FileTools() {
+ super();
+ }
+
+ public static byte[] readFile(Path path) {
+ try {
+ return Files.readAllBytes(path);
+ } catch (IOException e) {
+ final String msg = "Cannot read file " + path.toString() + ".";
+ throw new GenericRuntimeException(msg, e);
+ }
+ }
+
+ public static void writeFile(Path path, byte[] bytes) {
+ try {
+ Files.write(path, bytes);
+ } catch (IOException e) {
+ final String msg = "Cannot write file " + path.toString() + ".";
+ throw new GenericRuntimeException(msg, e);
+ }
+ }
+
+ public static void writeFile(Path path, Iterable extends CharSequence> lines, Charset cs) {
+ try {
+ Files.write(path, lines, cs);
+ } catch (IOException e) {
+ final String msg = "Cannot write file " + path.toString() + ".";
+ throw new GenericRuntimeException(msg, e);
+ }
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/JsonToStringStyler.java b/sqldev/src/main/java/org/utplsql/sqldev/model/JsonToStringStyler.java
new file mode 100644
index 00000000..2fd04e73
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/JsonToStringStyler.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model;
+
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+
+import javax.annotation.Nullable;
+
+import org.springframework.core.style.ToStringStyler;
+import org.springframework.core.style.ValueStyler;
+
+public class JsonToStringStyler implements ToStringStyler, ValueStyler{
+ public static final ToStringStyler INSTANCE = new JsonToStringStyler();
+ public static final String INDENT_SPACES = " ";
+ private int indent = 0;
+
+ private void newLine(StringBuilder buffer) {
+ buffer.append('\n');
+ buffer.append(getIndentSpaces(0));
+ }
+
+ private String getIndentSpaces(int indentOffset) {
+ StringBuilder sb = new StringBuilder();
+ for (int i=0; i list) {
+ if (list.isEmpty()) {
+ return "[]";
+ }
+
+ StringJoiner result = new StringJoiner(",\n" + getIndentSpaces(1), "[\n" + getIndentSpaces(1) , "\n" + getIndentSpaces(0) + "]");
+ indent++;
+ for (Object o : list) {
+ result.add(style(o));
+ }
+ indent--;
+ return result.toString();
+ }
+
+ private String getMapStyle(Map, ?> map) {
+ if (map.isEmpty()) {
+ return "[]";
+ }
+
+ StringJoiner result = new StringJoiner(",\n" + getIndentSpaces(1), "[\n" + getIndentSpaces(1) , "\n" + getIndentSpaces(0) + "]");
+ indent++;
+ for (Object o : map.values()) {
+ result.add(style(o));
+ }
+ indent--;
+ return result.toString();
+ }
+
+ private String getDefaultStyle(Object value) {
+ return String.valueOf(value);
+ }
+
+ @Override
+ public void styleStart(StringBuilder buffer, Object obj) {
+ indent++;
+ if (!obj.getClass().isArray()) {
+ buffer.append("{");
+ newLine(buffer);
+ buffer.append("\"className\": ");
+ buffer.append('"');
+ buffer.append(obj.getClass().getSimpleName());
+ buffer.append('"');
+ buffer.append(',');
+ } else {
+ buffer.append('[');
+ styleValue(buffer, obj);
+ }
+ }
+
+ @Override
+ public void styleEnd(StringBuilder buffer, Object obj) {
+ indent--;
+ newLine(buffer);
+ if (!obj.getClass().isArray()) {
+ buffer.append('}');
+ } else {
+ buffer.append(']');
+ }
+ }
+
+ @Override
+ public void styleField(StringBuilder buffer, String fieldName, @Nullable Object value) {
+ newLine(buffer);
+ buffer.append('"');
+ buffer.append(fieldName);
+ buffer.append('"');
+ buffer.append(": ");
+ styleValue(buffer, value);
+ }
+
+ @Override
+ public void styleValue(StringBuilder buffer, Object value) {
+ buffer.append(style(value));
+ }
+
+ @Override
+ public void styleFieldSeparator(StringBuilder buffer) {
+ buffer.append(",");
+ }
+
+ @Override
+ public String style(Object value) {
+ if (value == null) {
+ return "null";
+ } else if (value instanceof String) {
+ return getStringStyle((String) value);
+ } else if (value instanceof Object[]) {
+ return getArrayStyle((Object[]) value);
+ } else if (value instanceof List>) {
+ return getListStyle((List>) value);
+ } else if (value instanceof Map) {
+ return getMapStyle((Map, ?>) value);
+ } else {
+ return getDefaultStyle(value);
+ }
+ }
+}
diff --git a/sqldev/src/test/java/org/utplsql/sqldev/test/dal/TestRealtimerReporterEventTimedConsumer.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/LimitedLinkedHashMap.java
similarity index 50%
rename from sqldev/src/test/java/org/utplsql/sqldev/test/dal/TestRealtimerReporterEventTimedConsumer.xtend
rename to sqldev/src/main/java/org/utplsql/sqldev/model/LimitedLinkedHashMap.java
index ff46d749..de702252 100644
--- a/sqldev/src/test/java/org/utplsql/sqldev/test/dal/TestRealtimerReporterEventTimedConsumer.xtend
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/LimitedLinkedHashMap.java
@@ -13,25 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.utplsql.sqldev.test.dal
+package org.utplsql.sqldev.model;
-import java.util.HashMap
-import org.utplsql.sqldev.dal.RealtimeReporterEventConsumer
-import org.utplsql.sqldev.model.runner.RealtimeReporterEvent
-import org.utplsql.sqldev.model.runner.PostTestEvent
+import java.util.LinkedHashMap;
+import java.util.Map;
-class TestRealtimerReporterEventTimedConsumer implements RealtimeReporterEventConsumer {
-
- val postTestEvents = new HashMap
-
- def getPostTestEvents() {
- return postTestEvents
- }
-
- override void process(RealtimeReporterEvent event) {
- if (event instanceof PostTestEvent) {
- postTestEvents.put(event.id, System.currentTimeMillis)
- }
- }
+public class LimitedLinkedHashMap extends LinkedHashMap {
+ private static final long serialVersionUID = -4184317926729190411L;
+ private final int maxEntries;
-}
\ No newline at end of file
+ public LimitedLinkedHashMap(final int maxEntries) {
+ super((maxEntries + 1), 1.0f, false);
+ this.maxEntries = maxEntries;
+ }
+
+ @Override
+ public boolean removeEldestEntry(final Map.Entry eldest) {
+ return (size() > maxEntries);
+ }
+
+ public int getMaxEntries() {
+ return maxEntries;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/LimitedLinkedHashMap.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/LimitedLinkedHashMap.xtend
deleted file mode 100644
index 2d3605d9..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/LimitedLinkedHashMap.xtend
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2019 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model
-
-import java.util.LinkedHashMap
-import java.util.Map
-
-class LimitedLinkedHashMap extends LinkedHashMap {
- val int maxEntries
-
- new (int maxEntries) {
- super(maxEntries + 1, 1.0f, false)
-
- this.maxEntries = maxEntries;
- }
-
- override removeEldestEntry(Map.Entry eldest) {
- return size > maxEntries
- }
-
- def getMaxEntries() {
- return maxEntries
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/PrefixTools.java b/sqldev/src/main/java/org/utplsql/sqldev/model/PrefixTools.java
new file mode 100644
index 00000000..e17ce69d
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/PrefixTools.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model;
+
+import java.util.List;
+
+//converted to Xtend based on Java code on https://www.geeksforgeeks.org/longest-common-prefix-using-binary-search/
+//converted back to Java with some amendments
+public class PrefixTools {
+
+ // do not instantiate this class
+ private PrefixTools() {
+ super();
+ }
+
+ public static int findMinLength(final String[] arr, final int n) {
+ int min = Integer.MAX_VALUE;
+ for (int i=0; i < n; i++) {
+ if (arr[i].length() < min) {
+ min = arr[i].length();
+ }
+ }
+ return min;
+ }
+
+ public static boolean allContainsPrefix(final String[] arr, final int n, final String str, final int start, final int end) {
+ for (int i=0; i < n; i++) {
+ String item = arr[i];
+ for (int j = start; j <= end; j++) {
+ if (item.charAt(j) != str.charAt(j)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static String commonPrefix(final String[] arr, final int n) {
+ int index = findMinLength(arr, n);
+ StringBuilder prefix = new StringBuilder();
+ int low = 0;
+ int high = index; // index-1 is wrong
+ while (low <= high) {
+ int mid = low + (high - low) / 2;
+ if (allContainsPrefix(arr, n, arr[0], low, mid)) {
+ prefix.append(arr[0].substring(low, mid + 1));
+ low = mid + 1;
+ } else {
+ high = mid - 1;
+ }
+ }
+ return prefix.toString();
+ }
+
+ public static String commonPrefix(final List list) {
+ try {
+ if (list.isEmpty()) {
+ return "";
+ } else if (list.size() == 1) {
+ final int pos = list.get(0).lastIndexOf('.');
+ if (pos > 0) {
+ return list.get(0).substring(0, pos + 1);
+ } else {
+ return "";
+ }
+ } else {
+ final String[] testArray = new String[list.size()];
+ return commonPrefix(list.toArray(testArray), list.size());
+ }
+
+ } catch (Exception e) {
+ return "";
+ }
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/PrefixTools.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/PrefixTools.xtend
deleted file mode 100644
index c1fc822f..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/PrefixTools.xtend
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2019 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model
-
-import java.util.List
-
-// converted to Xtend based on Java code on https://www.geeksforgeeks.org/longest-common-prefix-using-binary-search/
-class PrefixTools {
- def static int findMinLength(String[] arr, int n) {
- var int min = Integer.MAX_VALUE
- for (var int i = 0; i < n; i++) {
- if ({
- val _rdIndx_arr = i
- arr.get(_rdIndx_arr)
- }.length() < min) {
- min = {
- val _rdIndx_arr = i
- arr.get(_rdIndx_arr)
- }.length()
- }
- }
- return min
- }
-
- def static boolean allContainsPrefix(String[] arr, int n, String str, int start, int end) {
- for (var int i = 0; i < n; i++) {
- var String arr_i = {
- val _rdIndx_arr = i
- arr.get(_rdIndx_arr)
- }
- for (var int j = start; j <= end; j++) {
- if (arr_i.charAt(j) !== str.charAt(j)) {
- return false
- }
- }
- }
- return true
- }
-
- def static String commonPrefix(String[] arr, int n) {
- var int index = findMinLength(arr, n)
- var String prefix = ""
- var int low = 0
- var int high = index
- while (low <= high) {
- var int mid = low + (high - low) / 2
- if (allContainsPrefix(arr, n, arr.get(0), low, mid)) {
- prefix = prefix + arr.get(0).substring(low, mid + 1)
- low = mid + 1
- } else {
- high = mid - 1
- }
- }
- return prefix
- }
-
- def static String commonPrefix(List list) {
- try {
- if (list.size === 0) {
- return ""
- } else if (list.size === 1) {
- val pos = list.get(0).lastIndexOf(".");
- if (pos > 0) {
- return list.get(0).substring(0, pos + 1)
- } else {
- return ""
- }
- } else {
- var String[] testArray = newArrayOfSize(list.size)
- var prefix = commonPrefix(list.toArray(testArray), list.size)
- return prefix
- }
- } catch (Exception e) {
- return ""
- }
- }
-
-}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/StringTools.java b/sqldev/src/main/java/org/utplsql/sqldev/model/StringTools.java
new file mode 100644
index 00000000..23fc20f9
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/StringTools.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model;
+
+import java.util.Collections;
+import java.util.List;
+
+public class StringTools {
+ // do not instantiate this class
+ private StringTools() {
+ super();
+ }
+
+ public static String getCSV(List list, String indent) {
+ final StringBuilder sb = new StringBuilder();
+ for (final String item : list) {
+ if (sb.length() > 0) {
+ sb.append(",\n");
+ }
+ sb.append(indent);
+ sb.append("'");
+ sb.append(item);
+ sb.append("'");
+ }
+ sb.append("\n");
+ return sb.toString();
+ }
+
+ public static String getCSV(List list, int indentSpaces) {
+ return getCSV(list, repeat(" ", indentSpaces));
+ }
+
+ public static String getSimpleCSV(List list) {
+ final StringBuilder sb = new StringBuilder();
+ for (final String item : list) {
+ if (sb.length() > 0) {
+ sb.append(", ");
+ }
+ sb.append(item);
+ }
+ return sb.toString();
+ }
+
+ public static String repeat(String s, int times) {
+ return String.join("", Collections.nCopies(times, s));
+ }
+
+ public static String replaceTabsWithSpaces(final CharSequence input, int indentSpaces) {
+ final String spaces = StringTools.repeat(" ", indentSpaces);
+ return input.toString().replace("\t", spaces);
+ }
+
+ public static String formatDateTime(final String dateTime) {
+ if (dateTime == null) {
+ return null;
+ } else {
+ if (dateTime.length() == 26) {
+ return dateTime.replace("T", " ").substring(0, 23);
+ } else {
+ return dateTime;
+ }
+ }
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/SystemTools.java b/sqldev/src/main/java/org/utplsql/sqldev/model/SystemTools.java
new file mode 100644
index 00000000..30a75172
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/SystemTools.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model;
+
+public class SystemTools {
+ // do not instantiate this class
+ private SystemTools() {
+ super();
+ }
+
+ public static void sleep(int millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ public static void waitForThread(Thread thread, int maxTimeInMillis) {
+ try {
+ thread.join(maxTimeInMillis);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/URLTools.java b/sqldev/src/main/java/org/utplsql/sqldev/model/URLTools.java
new file mode 100644
index 00000000..de225bcf
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/URLTools.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model;
+
+import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class URLTools {
+
+ // do not instantiate this class
+ private URLTools() {
+ super();
+ }
+
+ public static String replaceHexChars(final String input) {
+ String output = input;
+ final Pattern p = Pattern.compile("%([0-9A-F]{2})");
+ final Matcher m = p.matcher(input);
+ while (m.find()) {
+ final String what = m.group(0);
+ final int decimal = Integer.parseInt(m.group(1), 16);
+ final String with = String.valueOf((char) decimal);
+ output = output.replace(what, with);
+ }
+ return output;
+ }
+
+ public static String getConnectionName(final URL url) {
+ final Pattern p = Pattern.compile("(sqldev.nav:)([^/]+)(//)?");
+ final Matcher m = p.matcher(url.toString());
+ if (m.find()) {
+ return replaceHexChars(m.group(2).replace("IdeConnections%2523", "IdeConnections%23"));
+ } else {
+ return "";
+ }
+ }
+
+ public static String getSchema(final URL url) {
+ final Pattern p = Pattern.compile("(//)([^/]+)");
+ final Matcher m = p.matcher(url.toString());
+ if (m.find()) {
+ return m.group(2);
+ } else {
+ return "";
+ }
+ }
+
+ public static String getObjectType(final URL url) {
+ final Pattern p = Pattern.compile("(//)([^/]+)(/)([^/]+)");
+ final Matcher m = p.matcher(url.toString());
+ if (m.find()) {
+ return m.group(4);
+ } else {
+ return "";
+ }
+ }
+
+ public static String getMemberObject(final URL url) {
+ final Pattern p = Pattern.compile("(/)([^/]+)(#MEMBER)");
+ final Matcher m = p.matcher(url.toString());
+ if (m.find()) {
+ return m.group(2);
+ } else {
+ return "";
+ }
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/URLTools.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/URLTools.xtend
deleted file mode 100644
index 507d7035..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/URLTools.xtend
+++ /dev/null
@@ -1,74 +0,0 @@
-/* Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model
-
-import java.net.URL
-import java.util.regex.Pattern
-
-class URLTools {
- def replaceHexChars(String input) {
- var String output = input;
- val p = Pattern.compile("%([0-9A-F]{2})")
- val m = p.matcher(input)
- while (m.find) {
- val what = m.group(0);
- val decimal = Integer.parseInt(m.group(1), 16)
- val with = String.valueOf(decimal as char)
- output = output.replace(what, with)
- }
- return output
- }
-
- def getConnectionName(URL url) {
- val p = Pattern.compile("(sqldev.nav:)([^/]+)(//)?")
- val m = p.matcher(url.toString)
- if (m.find) {
- return m.group(2).replace("IdeConnections%2523", "IdeConnections%23").replaceHexChars
- } else {
- return ""
- }
- }
-
- def getSchema(URL url) {
- val p = Pattern.compile("(//)([^/]+)")
- val m = p.matcher(url.toString)
- if (m.find) {
- return m.group(2)
- } else {
- return ""
- }
- }
-
- def getObjectType(URL url) {
- val p = Pattern.compile("(//)([^/]+)(/)([^/]+)")
- val m = p.matcher(url.toString)
- if (m.find) {
- return m.group(4)
- } else {
- return ""
- }
- }
-
- def getMemberObject(URL url) {
- val p = Pattern.compile("(/)([^/]+)(#MEMBER)")
- val m = p.matcher(url.toString)
-
- if (m.find) {
- return m.group(2)
- } else {
- return ""
- }
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/XMLTools.java b/sqldev/src/main/java/org/utplsql/sqldev/model/XMLTools.java
new file mode 100644
index 00000000..b9f2b982
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/XMLTools.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.logging.Logger;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.utplsql.sqldev.exception.GenericRuntimeException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class XMLTools {
+ private static final Logger logger = Logger.getLogger(XMLTools.class.getName());
+ private final XPathFactory xpathFactory = XPathFactory.newInstance();
+ private final XPath xpath = xpathFactory.newXPath();
+
+ public NodeList getNodeList(final Node doc, final String xpathString) {
+ try {
+ final XPathExpression expr = xpath.compile(xpathString);
+ return ((NodeList) expr.evaluate(doc, XPathConstants.NODESET));
+ } catch (XPathExpressionException e) {
+ final String msg = "XPathExpressionException for " + xpathString + ".";
+ logger.severe(() -> msg);
+ throw new GenericRuntimeException(msg, e);
+ }
+ }
+
+ public Node getNode(final Node doc, final String xpathString) {
+ try {
+ final XPathExpression expr = xpath.compile(xpathString);
+ return ((Node) expr.evaluate(doc, XPathConstants.NODE));
+ } catch (XPathExpressionException e) {
+ final String msg = "XPathExpressionException for " + xpathString + ".";
+ logger.severe(() -> msg);
+ throw new GenericRuntimeException(msg, e);
+ }
+ }
+
+ public void trimWhitespace(final Node node) {
+ final NodeList children = node.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ final Node child = children.item(i);
+ if (child.getNodeType() == Node.TEXT_NODE) {
+ child.setTextContent(child.getTextContent().trim());
+ }
+ trimWhitespace(child);
+ }
+ }
+
+ public String nodeToString(final Node node, final String cdataSectionElements) {
+ try {
+ trimWhitespace(node);
+ final StringWriter writer = new StringWriter();
+ TransformerFactory factory = TransformerFactory.newInstance();
+ factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ final Transformer transformer = factory.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
+ transformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, cdataSectionElements);
+ transformer.transform( new DOMSource(node), new StreamResult(writer));
+ final String result = writer.toString();
+ return result.replaceAll("", "");
+ } catch (TransformerException e) {
+ final String msg = "TransformerException for " + cdataSectionElements + ".";
+ logger.severe(() -> msg);
+ throw new GenericRuntimeException(msg, e);
+ }
+ }
+
+ public String getAttributeValue(final Node node, final String namedItem) {
+ String value = null;
+ if (node instanceof Element) {
+ final NamedNodeMap attributes = ((Element) node).getAttributes();
+ if (attributes != null) {
+ final Node item = attributes.getNamedItem(namedItem);
+ if (item != null) {
+ value = item.getNodeValue();
+ }
+ }
+ }
+ return value;
+ }
+
+ public String getElementValue(final Node node, final String tagName) {
+ String value = null;
+ final Node item = getElementNode(node, tagName);
+ if (item != null) {
+ value = item.getTextContent();
+ }
+ return value;
+ }
+
+ public Node getElementNode(final Node node, final String tagName) {
+ Node resultNode = null;
+ if (node instanceof Element) {
+ NodeList list = ((Element) node).getElementsByTagName(tagName);
+ if (list != null && list.getLength() > 0) {
+ resultNode = list.item(0);
+ }
+ }
+ return resultNode;
+ }
+
+ public DocumentBuilder createDocumentBuilder() {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ try {
+ factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+ return factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ final String msg = "Could not create no document builder.";
+ logger.severe(() -> msg);
+ throw new GenericRuntimeException(msg, e);
+ }
+ }
+
+ public Document parse(final DocumentBuilder builder, final InputSource inputSource) {
+ try {
+ return builder.parse(inputSource);
+ } catch (SAXException | IOException e) {
+ final String msg = "Could not parse XML input.";
+ logger.severe(() -> msg);
+ throw new GenericRuntimeException(msg, e);
+ }
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/XMLTools.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/XMLTools.xtend
deleted file mode 100644
index 5126486a..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/XMLTools.xtend
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model
-
-import java.io.StringWriter
-import javax.xml.transform.OutputKeys
-import javax.xml.transform.TransformerFactory
-import javax.xml.transform.dom.DOMSource
-import javax.xml.transform.stream.StreamResult
-import javax.xml.xpath.XPathConstants
-import javax.xml.xpath.XPathFactory
-import org.w3c.dom.Node
-import org.w3c.dom.NodeList
-
-class XMLTools {
- val xpathFactory = XPathFactory.newInstance()
- val xpath = xpathFactory.newXPath()
-
- def getNodeList(Node doc, String xpathString) {
- val expr = xpath.compile(xpathString);
- val NodeList nodeList = expr.evaluate(doc, XPathConstants.NODESET) as NodeList
- return nodeList
- }
-
- def getNode(Node doc, String xpathString) {
- val expr = xpath.compile(xpathString);
- val Node node = expr.evaluate(doc, XPathConstants.NODE) as Node
- return node
- }
-
- def void trimWhitespace(Node node) {
- val children = node.childNodes
- for (i : 0 ..< children.length) {
- val child = children.item(i)
- if (child.nodeType == Node.TEXT_NODE) {
- child.textContent = child.textContent.trim
- }
- trimWhitespace(child);
- }
- }
-
- def nodeToString(Node node, String cdataSectionElements) {
- node.trimWhitespace
- val writer = new StringWriter()
- val factory = TransformerFactory.newInstance().newTransformer()
- factory.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
- factory.setOutputProperty(OutputKeys.INDENT, "yes")
- factory.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
- factory.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, cdataSectionElements)
- factory.transform(new DOMSource(node), new StreamResult(writer))
- val result = writer.toString()
- val fixedResult = result.replaceAll('''''',"")
- return fixedResult
- }
-}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/oddgen/GenContext.java b/sqldev/src/main/java/org/utplsql/sqldev/model/oddgen/GenContext.java
new file mode 100644
index 00000000..30fdfbf9
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/oddgen/GenContext.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.oddgen;
+
+import java.sql.Connection;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class GenContext {
+ private Connection conn;
+ private String objectType;
+ private String objectName;
+ private String testPackagePrefix;
+ private String testPackageSuffix;
+ private String testUnitPrefix;
+ private String testUnitSuffix;
+ private int numberOfTestsPerUnit;
+ private boolean generateComments;
+ private boolean disableTests;
+ private String suitePath;
+ private int indentSpaces;
+
+ public Connection getConn() {
+ return conn;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("conn", conn)
+ .append("objectType", objectType)
+ .append("objectName", objectName)
+ .append("testPackagePrefix", testPackagePrefix)
+ .append("testPackageSuffix", testPackageSuffix)
+ .append("testUnitPrefix", testUnitPrefix)
+ .append("testUnitSuffix", testUnitSuffix)
+ .append("numberOfTestsPerUnit", numberOfTestsPerUnit)
+ .append("generateComments", generateComments)
+ .append("disableTests", disableTests)
+ .append("suitePath", suitePath)
+ .append("indentSpaces", indentSpaces)
+ .toString();
+ }
+
+ public void setConn(final Connection conn) {
+ this.conn = conn;
+ }
+
+ public String getObjectType() {
+ return objectType;
+ }
+
+ public void setObjectType(final String objectType) {
+ this.objectType = objectType;
+ }
+
+ public String getObjectName() {
+ return objectName;
+ }
+
+ public void setObjectName(final String objectName) {
+ this.objectName = objectName;
+ }
+
+ public String getTestPackagePrefix() {
+ return testPackagePrefix;
+ }
+
+ public void setTestPackagePrefix(final String testPackagePrefix) {
+ this.testPackagePrefix = testPackagePrefix;
+ }
+
+ public String getTestPackageSuffix() {
+ return testPackageSuffix;
+ }
+
+ public void setTestPackageSuffix(final String testPackageSuffix) {
+ this.testPackageSuffix = testPackageSuffix;
+ }
+
+ public String getTestUnitPrefix() {
+ return testUnitPrefix;
+ }
+
+ public void setTestUnitPrefix(final String testUnitPrefix) {
+ this.testUnitPrefix = testUnitPrefix;
+ }
+
+ public String getTestUnitSuffix() {
+ return testUnitSuffix;
+ }
+
+ public void setTestUnitSuffix(final String testUnitSuffix) {
+ this.testUnitSuffix = testUnitSuffix;
+ }
+
+ public int getNumberOfTestsPerUnit() {
+ return numberOfTestsPerUnit;
+ }
+
+ public void setNumberOfTestsPerUnit(final int numberOfTestsPerUnit) {
+ this.numberOfTestsPerUnit = numberOfTestsPerUnit;
+ }
+
+ public boolean isGenerateComments() {
+ return generateComments;
+ }
+
+ public void setGenerateComments(final boolean generateComments) {
+ this.generateComments = generateComments;
+ }
+
+ public boolean isDisableTests() {
+ return disableTests;
+ }
+
+ public void setDisableTests(final boolean disableTests) {
+ this.disableTests = disableTests;
+ }
+
+ public String getSuitePath() {
+ return suitePath;
+ }
+
+ public void setSuitePath(final String suitePath) {
+ this.suitePath = suitePath;
+ }
+
+ public int getIndentSpaces() {
+ return indentSpaces;
+ }
+
+ public void setIndentSpaces(final int indentSpaces) {
+ this.indentSpaces = indentSpaces;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/parser/PlsqlObject.java b/sqldev/src/main/java/org/utplsql/sqldev/model/parser/PlsqlObject.java
new file mode 100644
index 00000000..122cfc1c
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/parser/PlsqlObject.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.parser;
+
+import java.util.List;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+import org.utplsql.sqldev.model.ut.Annotation;
+
+public class PlsqlObject {
+ private String name;
+ private String type;
+ private Integer position;
+ private List annotations;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("name", name)
+ .append("type", type)
+ .append("position", position)
+ .append("annotations", annotations)
+ .toString();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(final String type) {
+ this.type = type;
+ }
+
+ public Integer getPosition() {
+ return position;
+ }
+
+ public void setPosition(final Integer position) {
+ this.position = position;
+ }
+
+ public List getAnnotations() {
+ return annotations;
+ }
+
+ public void setAnnotations(final List annotations) {
+ this.annotations = annotations;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/parser/PlsqlObject.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/parser/PlsqlObject.xtend
deleted file mode 100644
index 96b71db1..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/parser/PlsqlObject.xtend
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.parser
-
-import java.util.List
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.model.AbstractModel
-import org.utplsql.sqldev.model.ut.Annotation
-
-@Accessors
-class PlsqlObject extends AbstractModel {
- String name
- String type
- Integer position
- List annotations
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/parser/Unit.java b/sqldev/src/main/java/org/utplsql/sqldev/model/parser/Unit.java
new file mode 100644
index 00000000..990e877c
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/parser/Unit.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.parser;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class Unit {
+ private String name;
+ private Integer position;
+ private Integer positionOfName;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("name", name)
+ .append("position", position)
+ .append("positionOfName", positionOfName)
+ .toString();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public Integer getPosition() {
+ return position;
+ }
+
+ public void setPosition(final Integer position) {
+ this.position = position;
+ }
+
+ public Integer getPositionOfName() {
+ return positionOfName;
+ }
+
+ public void setPositionOfName(final Integer positionOfName) {
+ this.positionOfName = positionOfName;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/parser/Unit.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/parser/Unit.xtend
deleted file mode 100644
index a913f70b..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/parser/Unit.xtend
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.parser
-
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.model.AbstractModel
-
-@Accessors
-class Unit extends AbstractModel {
- String name
- Integer position
- Integer positionOfName
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.java b/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.java
new file mode 100644
index 00000000..693ace05
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.preference;
+
+import java.io.File;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+import oracle.javatools.data.HashStructure;
+import oracle.javatools.data.HashStructureAdapter;
+import oracle.javatools.data.PropertyStorage;
+
+public class PreferenceModel extends HashStructureAdapter {
+ public static final String DEFAULT_OUTPUT_DIRECTORY = System.getProperty("user.home") + File.separator + "utplsql" + File.separator + "generated";
+ private static final String DATA_KEY = "utplsql";
+
+ private PreferenceModel(final HashStructure hash) {
+ super(hash);
+ }
+
+ public static PreferenceModel getInstance(final PropertyStorage prefs) {
+ return new PreferenceModel(findOrCreate(prefs, DATA_KEY));
+ }
+
+ private static final String KEY_USE_REALTIME_REPORTER = "useRealtimeRorter";
+ private static final String KEY_UNSHARED_WORKSHEET = "unsharedWorksheet";
+ private static final String KEY_RESET_PACKAGE = "resetPackage";
+ private static final String KEY_CLEAR_SCREEN = "clearScreen";
+ private static final String KEY_AUTO_EXECUTE = "autoExecute";
+ private static final String KEY_CHECK_RUN_UTPLSQL_TEST = "checkRunUtplsqlTest";
+ private static final String KEY_USE_SMART_TIMES = "useSmartTimes";
+ private static final String KEY_NUMBER_OF_RUNS_IN_HISTORY = "numberOfRunsInHistory";
+ private static final String KEY_SHOW_DISABLED_COUNTER = "showDisabledCounter";
+ private static final String KEY_SHOW_WARNINGS_COUNTER = "showWarningsCounter";
+ private static final String KEY_SHOW_INFO_COUNTER = "showInfoCounter";
+ private static final String KEY_SHOW_WARNING_INDICATOR = "showWarningIndicator";
+ private static final String KEY_SHOW_INFO_INDICATOR = "showInfoIndicator";
+ private static final String KEY_SHOW_SUCCESSFUL_TESTS = "showSuccessfulTests";
+ private static final String KEY_SHOW_DISABLED_TESTS = "showDisabledTests";
+ private static final String KEY_SHOW_TEST_DESCRIPTION = "showTestDescription";
+ private static final String KEY_SYNC_DETAIL_TAB = "syncDetailTab";
+ private static final String KEY_TEST_PACKAGE_PREFIX = "testPackagePrefix";
+ private static final String KEY_TEST_PACKAGE_SUFFIX = "testPackageSuffix";
+ private static final String KEY_TEST_UNIT_PREFIX = "testUnitPrefix";
+ private static final String KEY_TEST_UNIT_SUFFIX = "testUnitSuffix";
+ private static final String KEY_NUMBER_OF_TESTS_PER_UNIT = "numberOfTestsPerUnit";
+ private static final String KEY_CHECK_GENERATE_UTPLSQL_TEST = "checkGenerateUtplsqlTest";
+ private static final String KEY_GENERATE_COMMENTS = "generateComments";
+ private static final String KEY_DISABLE_TESTS = "disableTests";
+ private static final String KEY_SUITE_PATH = "suitePath";
+ private static final String KEY_INDENT_SPACES = "indentSpaces";
+ private static final String KEY_GENERATE_FILES = "generateFiles";
+ private static final String KEY_OUTPUT_DIRECTORY = "outputDirectory";
+ private static final String KEY_DELETE_EXISTING_FILES = "deleteExistingFiles";
+ private static final String KEY_ROOT_FOLDER_IN_ODDGEN_VIEW = "rootFolderInOddgenView";
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append(KEY_USE_REALTIME_REPORTER, isUseRealtimeReporter())
+ .append(KEY_UNSHARED_WORKSHEET, isUnsharedWorksheet())
+ .append(KEY_RESET_PACKAGE, isResetPackage())
+ .append(KEY_CLEAR_SCREEN, isClearScreen())
+ .append(KEY_AUTO_EXECUTE, isAutoExecute())
+ .append(KEY_CHECK_RUN_UTPLSQL_TEST, isCheckRunUtplsqlTest())
+ .append(KEY_USE_SMART_TIMES, isUseSmartTimes())
+ .append(KEY_NUMBER_OF_RUNS_IN_HISTORY, getNumberOfRunsInHistory())
+ .append(KEY_SHOW_DISABLED_COUNTER, isShowDisabledCounter())
+ .append(KEY_SHOW_WARNINGS_COUNTER, isShowWarningsCounter())
+ .append(KEY_SHOW_INFO_COUNTER, isShowInfoCounter())
+ .append(KEY_SHOW_WARNING_INDICATOR, isShowWarningIndicator())
+ .append(KEY_SHOW_INFO_INDICATOR, isShowInfoIndicator())
+ .append(KEY_SHOW_SUCCESSFUL_TESTS, isShowSuccessfulTests())
+ .append(KEY_SHOW_DISABLED_TESTS, isShowDisabledTests())
+ .append(KEY_SHOW_TEST_DESCRIPTION, isShowTestDescription())
+ .append(KEY_SYNC_DETAIL_TAB, isSyncDetailTab())
+ .append(KEY_TEST_PACKAGE_PREFIX, getTestPackagePrefix())
+ .append(KEY_TEST_PACKAGE_SUFFIX, getTestPackageSuffix())
+ .append(KEY_TEST_UNIT_PREFIX, getTestUnitPrefix())
+ .append(KEY_TEST_UNIT_SUFFIX, getTestUnitSuffix())
+ .append(KEY_NUMBER_OF_TESTS_PER_UNIT, getNumberOfTestsPerUnit())
+ .append(KEY_CHECK_GENERATE_UTPLSQL_TEST, isCheckGenerateUtplsqlTest())
+ .append(KEY_GENERATE_COMMENTS, isGenerateComments())
+ .append(KEY_DISABLE_TESTS, isDisableTests())
+ .append(KEY_SUITE_PATH, getSuitePath())
+ .append(KEY_INDENT_SPACES, getIndentSpaces())
+ .append(KEY_GENERATE_FILES, isGenerateFiles())
+ .append(KEY_OUTPUT_DIRECTORY, getOutputDirectory())
+ .append(KEY_DELETE_EXISTING_FILES, isDeleteExistingFiles())
+ .append(KEY_ROOT_FOLDER_IN_ODDGEN_VIEW, getRootFolderInOddgenView())
+ .toString();
+ }
+
+ public boolean isUseRealtimeReporter() {
+ return getHashStructure().getBoolean(KEY_USE_REALTIME_REPORTER, true);
+ }
+
+ public void setUseRealtimeReporter(final boolean useRealtimeReporter) {
+ getHashStructure().putBoolean(KEY_USE_REALTIME_REPORTER, useRealtimeReporter);
+ }
+
+ public boolean isUnsharedWorksheet() {
+ return getHashStructure().getBoolean(KEY_UNSHARED_WORKSHEET, true);
+ }
+
+ public void setUnsharedWorksheet(final boolean unsharedWorksheet) {
+ getHashStructure().putBoolean(KEY_UNSHARED_WORKSHEET, unsharedWorksheet);
+ }
+
+ public boolean isResetPackage() {
+ return getHashStructure().getBoolean(KEY_RESET_PACKAGE, false);
+ }
+
+ public void setResetPackage(final boolean resetPackage) {
+ getHashStructure().putBoolean(KEY_RESET_PACKAGE, resetPackage);
+ }
+
+ public boolean isClearScreen() {
+ return getHashStructure().getBoolean(KEY_CLEAR_SCREEN, false);
+ }
+
+ public void setClearScreen(final boolean clearScreen) {
+ getHashStructure().putBoolean(KEY_CLEAR_SCREEN, clearScreen);
+ }
+
+ public boolean isAutoExecute() {
+ return getHashStructure().getBoolean(KEY_AUTO_EXECUTE, true);
+ }
+
+ public void setAutoExecute(final boolean autoExecute) {
+ getHashStructure().putBoolean(KEY_AUTO_EXECUTE, autoExecute);
+ }
+
+ public boolean isCheckRunUtplsqlTest() {
+ return getHashStructure().getBoolean(KEY_CHECK_RUN_UTPLSQL_TEST, false);
+ }
+
+ public void setCheckRunUtplsqlTest(final boolean checkRunUtplsqlTest) {
+ getHashStructure().putBoolean(KEY_CHECK_RUN_UTPLSQL_TEST, checkRunUtplsqlTest);
+ }
+
+ public boolean isUseSmartTimes() {
+ return getHashStructure().getBoolean(KEY_USE_SMART_TIMES, false);
+ }
+
+ public void setUseSmartTimes(final boolean useSmartTimes) {
+ getHashStructure().putBoolean(KEY_USE_SMART_TIMES, useSmartTimes);
+ }
+
+ public int getNumberOfRunsInHistory() {
+ return getHashStructure().getInt(KEY_NUMBER_OF_RUNS_IN_HISTORY, 10);
+ }
+
+ public void setNumberOfRunsInHistory(final int runs) {
+ getHashStructure().putInt(KEY_NUMBER_OF_RUNS_IN_HISTORY, runs);
+ }
+
+ public boolean isShowDisabledCounter() {
+ return getHashStructure().getBoolean(KEY_SHOW_DISABLED_COUNTER, false);
+ }
+
+ public void setShowDisabledCounter(final boolean showDisabledCounter) {
+ getHashStructure().putBoolean(KEY_SHOW_DISABLED_COUNTER, showDisabledCounter);
+ }
+
+ public boolean isShowWarningsCounter() {
+ return getHashStructure().getBoolean(KEY_SHOW_WARNINGS_COUNTER, false);
+ }
+
+ public void setShowWarningsCounter(final boolean showWarningCounter) {
+ getHashStructure().putBoolean(KEY_SHOW_WARNINGS_COUNTER, showWarningCounter);
+ }
+
+ public boolean isShowInfoCounter() {
+ return getHashStructure().getBoolean(KEY_SHOW_INFO_COUNTER, false);
+ }
+
+ public void setShowInfoCounter(final boolean showInfoCounter) {
+ getHashStructure().putBoolean(KEY_SHOW_INFO_COUNTER, showInfoCounter);
+ }
+
+ public boolean isShowWarningIndicator() {
+ return getHashStructure().getBoolean(KEY_SHOW_WARNING_INDICATOR, false);
+ }
+
+ public void setShowWarningIndicator(final boolean showWarningIndicator) {
+ getHashStructure().putBoolean(KEY_SHOW_WARNING_INDICATOR, showWarningIndicator);
+ }
+
+ public boolean isShowInfoIndicator() {
+ return getHashStructure().getBoolean(KEY_SHOW_INFO_INDICATOR, false);
+ }
+
+ public void setShowInfoIndicator(final boolean showInfoIndicator) {
+ getHashStructure().putBoolean(KEY_SHOW_INFO_INDICATOR, showInfoIndicator);
+ }
+
+ public boolean isShowSuccessfulTests() {
+ return getHashStructure().getBoolean(KEY_SHOW_SUCCESSFUL_TESTS, true);
+ }
+
+ public void setShowSuccessfulTests(final boolean showSuccessfulTests) {
+ getHashStructure().putBoolean(KEY_SHOW_SUCCESSFUL_TESTS, showSuccessfulTests);
+ }
+
+ public boolean isShowDisabledTests() {
+ return getHashStructure().getBoolean(KEY_SHOW_DISABLED_TESTS, true);
+ }
+
+ public void setShowDisabledTests(final boolean showDisabledTests) {
+ getHashStructure().putBoolean(KEY_SHOW_DISABLED_TESTS, showDisabledTests);
+ }
+
+ public boolean isShowTestDescription() {
+ return getHashStructure().getBoolean(KEY_SHOW_TEST_DESCRIPTION, false);
+ }
+
+ public void setShowTestDescription(final boolean showTestDescription) {
+ getHashStructure().putBoolean(KEY_SHOW_TEST_DESCRIPTION, showTestDescription);
+ }
+
+ public boolean isSyncDetailTab() {
+ return getHashStructure().getBoolean(KEY_SYNC_DETAIL_TAB, true);
+ }
+
+ public void setSyncDetailTab(final boolean syncDetailTab) {
+ getHashStructure().putBoolean(KEY_SYNC_DETAIL_TAB, syncDetailTab);
+ }
+
+ public String getTestPackagePrefix() {
+ return getHashStructure().getString(KEY_TEST_PACKAGE_PREFIX, "test_");
+ }
+
+ public void setTestPackagePrefix(final String testPackagePrefix) {
+ getHashStructure().putString(KEY_TEST_PACKAGE_PREFIX, testPackagePrefix);
+ }
+
+ public String getTestPackageSuffix() {
+ return getHashStructure().getString(KEY_TEST_PACKAGE_SUFFIX, "");
+ }
+
+ public void setTestPackageSuffix(final String testPackageSuffix) {
+ getHashStructure().putString(KEY_TEST_PACKAGE_SUFFIX, testPackageSuffix);
+ }
+
+ public String getTestUnitPrefix() {
+ return getHashStructure().getString(KEY_TEST_UNIT_PREFIX, "");
+ }
+
+ public void setTestUnitPrefix(final String testUnitPrefix) {
+ getHashStructure().putString(KEY_TEST_UNIT_PREFIX, testUnitPrefix);
+ }
+
+ public String getTestUnitSuffix() {
+ return getHashStructure().getString(KEY_TEST_UNIT_SUFFIX, "");
+ }
+
+ public void setTestUnitSuffix(final String testUnitSuffix) {
+ getHashStructure().putString(KEY_TEST_UNIT_SUFFIX, testUnitSuffix);
+ }
+
+ public int getNumberOfTestsPerUnit() {
+ return getHashStructure().getInt(KEY_NUMBER_OF_TESTS_PER_UNIT, 1);
+ }
+
+ public void setNumberOfTestsPerUnit(final int numberOfTestsPerUnit) {
+ getHashStructure().putInt(KEY_NUMBER_OF_TESTS_PER_UNIT, numberOfTestsPerUnit);
+ }
+
+ public boolean isCheckGenerateUtplsqlTest() {
+ return getHashStructure().getBoolean(KEY_CHECK_GENERATE_UTPLSQL_TEST, false);
+ }
+
+ public void setCheckGenerateUtplsqlTest(final boolean checkGenerateUtplsqlTest) {
+ getHashStructure().putBoolean(KEY_CHECK_GENERATE_UTPLSQL_TEST, checkGenerateUtplsqlTest);
+ }
+
+ public boolean isGenerateComments() {
+ return getHashStructure().getBoolean(KEY_GENERATE_COMMENTS, true);
+ }
+
+ public void setGenerateComments(final boolean generateComments) {
+ getHashStructure().putBoolean(KEY_GENERATE_COMMENTS, generateComments);
+ }
+
+ public boolean isDisableTests() {
+ return getHashStructure().getBoolean(KEY_DISABLE_TESTS, false);
+ }
+
+ public void setDisableTests(final boolean disableTests) {
+ getHashStructure().putBoolean(KEY_DISABLE_TESTS, disableTests);
+ }
+
+ public String getSuitePath() {
+ return getHashStructure().getString(KEY_SUITE_PATH, "alltests");
+ }
+
+ public void setSuitePath(final String suitePath) {
+ getHashStructure().putString(KEY_SUITE_PATH, suitePath);
+ }
+
+ public int getIndentSpaces() {
+ return getHashStructure().getInt(KEY_INDENT_SPACES, 3);
+ }
+
+ public void setIndentSpaces(final int indentSpaces) {
+ getHashStructure().putInt(KEY_INDENT_SPACES, indentSpaces);
+ }
+
+ public boolean isGenerateFiles() {
+ return getHashStructure().getBoolean(KEY_GENERATE_FILES, true);
+ }
+
+ public void setGenerateFiles(final boolean generateFiles) {
+ getHashStructure().putBoolean(KEY_GENERATE_FILES, generateFiles);
+ }
+
+ public String getOutputDirectory() {
+ return getHashStructure().getString(KEY_OUTPUT_DIRECTORY, DEFAULT_OUTPUT_DIRECTORY);
+ }
+
+ public void setOutputDirectory(final String outputDirectory) {
+ final String dir = outputDirectory.isEmpty() ? DEFAULT_OUTPUT_DIRECTORY : outputDirectory;
+ getHashStructure().putString(KEY_OUTPUT_DIRECTORY, dir);
+ }
+
+ public boolean isDeleteExistingFiles() {
+ return getHashStructure().getBoolean(KEY_DELETE_EXISTING_FILES, false);
+ }
+
+ public void setDeleteExistingFiles(final boolean deleteExistingFiles) {
+ getHashStructure().putBoolean(KEY_DELETE_EXISTING_FILES, deleteExistingFiles);
+ }
+
+ public String getRootFolderInOddgenView() {
+ return getHashStructure().getString(KEY_ROOT_FOLDER_IN_ODDGEN_VIEW, "utPLSQL");
+ }
+
+ public void setRootFolderInOddgenView(final String rootFolder) {
+ final String folder = rootFolder.isEmpty() ? "utPLSQL" : rootFolder;
+ getHashStructure().putString(KEY_ROOT_FOLDER_IN_ODDGEN_VIEW, folder);
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.xtend
deleted file mode 100644
index 6ae9ea80..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.xtend
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.preference
-
-import java.io.File
-import oracle.javatools.data.HashStructure
-import oracle.javatools.data.HashStructureAdapter
-import oracle.javatools.data.PropertyStorage
-import org.eclipse.xtext.xbase.lib.util.ToStringBuilder
-
-class PreferenceModel extends HashStructureAdapter {
- public static final String DEFAULT_OUTPUT_DIRECTORY = '''«System.getProperty("user.home")»«File.separator»utplsql«File.separator»generated'''
- static final String DATA_KEY = "utplsql"
-
- private new(HashStructure hash) {
- super(hash)
- }
-
- def static getInstance(PropertyStorage prefs) {
- return new PreferenceModel(findOrCreate(prefs, DATA_KEY))
- }
-
- static final String KEY_USE_REALTIME_REPORTER = "useRealtimeRorter"
- static final String KEY_UNSHARED_WORKSHEET = "unsharedWorksheet"
- static final String KEY_RESET_PACKAGE = "resetPackage"
- static final String KEY_CLEAR_SCREEN = "clearScreen"
- static final String KEY_AUTO_EXECUTE = "autoExecute"
- static final String KEY_CHECK_RUN_UTPLSQL_TEST = "checkRunUtplsqlTest"
- static final String KEY_USE_SMART_TIMES = "useSmartTimes"
- static final String KEY_NUMBER_OF_RUNS_IN_HISTORY = "numberOfRunsInHistory"
- static final String KEY_SHOW_DISABLED_COUNTER = "showDisabledCounter"
- static final String KEY_SHOW_WARNINGS_COUNTER = "showWarningsCounter"
- static final String KEY_SHOW_INFO_COUNTER = "showInfoCounter"
- static final String KEY_SHOW_WARNING_INDICATOR = "showWarningIndicator"
- static final String KEY_SHOW_INFO_INDICATOR = "showInfoIndicator"
- static final String KEY_SHOW_SUCCESSFUL_TESTS = "showSuccessfulTests"
- static final String KEY_SHOW_DISABLED_TESTS = "showDisabledTests"
- static final String KEY_SHOW_TEST_DESCRIPTION = "showTestDescription"
- static final String KEY_SYNC_DETAIL_TAB = "syncDetailTab"
- static final String KEY_TEST_PACKAGE_PREFIX = "testPackagePrefix"
- static final String KEY_TEST_PACKAGE_SUFFIX = "testPackageSuffix"
- static final String KEY_TEST_UNIT_PREFIX = "testUnitPrefix"
- static final String KEY_TEST_UNIT_SUFFIX = "testUnitSuffix"
- static final String KEY_NUMBER_OF_TESTS_PER_UNIT = "numberOfTestsPerUnit"
- static final String KEY_CHECK_GENERATE_UTPLSQL_TEST = "checkGenerateUtplsqlTest"
- static final String KEY_GENERATE_COMMENTS = "generateComments"
- static final String KEY_DISABLE_TESTS = "disableTests"
- static final String KEY_SUITE_PATH="suitePath"
- static final String KEY_INDENT_SPACES="indentSpaces"
- static final String KEY_GENERATE_FILES="generateFiles"
- static final String KEY_OUTPUT_DIRECTORY = "outputDirectory"
- static final String KEY_DELETE_EXISTING_FILES="deleteExistingFiles"
- static final String KEY_ROOT_FOLDER_IN_ODDGEN_VIEW = "rootFolderInOddgenView"
-
- def isUseRealtimeReporter() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_USE_REALTIME_REPORTER, true)
- }
-
- def setUseRealtimeReporter(boolean useRealtimeReporter) {
- getHashStructure.putBoolean(PreferenceModel.KEY_USE_REALTIME_REPORTER, useRealtimeReporter)
- }
-
- def isUnsharedWorksheet() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_UNSHARED_WORKSHEET, true)
- }
-
- def setUnsharedWorksheet(boolean unsharedWorksheet) {
- getHashStructure.putBoolean(PreferenceModel.KEY_UNSHARED_WORKSHEET, unsharedWorksheet)
- }
-
- def isResetPackage() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_RESET_PACKAGE, false)
- }
-
- def setResetPackage(boolean resetPackage) {
- getHashStructure.putBoolean(PreferenceModel.KEY_RESET_PACKAGE, resetPackage)
- }
-
- def isClearScreen() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_CLEAR_SCREEN, false)
- }
-
- def setClearScreen(boolean clearScreen) {
- getHashStructure.putBoolean(PreferenceModel.KEY_CLEAR_SCREEN, clearScreen)
- }
-
- def isAutoExecute() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_AUTO_EXECUTE, true)
- }
-
- def setAutoExecute(boolean autoExecute) {
- getHashStructure.putBoolean(PreferenceModel.KEY_AUTO_EXECUTE, autoExecute)
- }
-
- def isCheckRunUtplsqlTest() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_CHECK_RUN_UTPLSQL_TEST, false)
- }
-
- def setCheckRunUtplsqlTest(boolean checkRunUtplsqlTest) {
- getHashStructure.putBoolean(PreferenceModel.KEY_CHECK_RUN_UTPLSQL_TEST, checkRunUtplsqlTest)
- }
-
- def isUseSmartTimes() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_USE_SMART_TIMES, false)
- }
-
- def setUseSmartTimes(boolean useSmartTimes) {
- getHashStructure.putBoolean(PreferenceModel.KEY_USE_SMART_TIMES, useSmartTimes)
- }
-
- def getNumberOfRunsInHistory() {
- return getHashStructure.getInt(PreferenceModel.KEY_NUMBER_OF_RUNS_IN_HISTORY, 10)
- }
-
- def setNumberOfRunsInHistory(int runs) {
- getHashStructure.putInt(PreferenceModel.KEY_NUMBER_OF_RUNS_IN_HISTORY, runs)
- }
-
- def isShowDisabledCounter() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_SHOW_DISABLED_COUNTER, false)
- }
-
- def setShowDisabledCounter(boolean showDisabledCounter) {
- getHashStructure.putBoolean(PreferenceModel.KEY_SHOW_DISABLED_COUNTER, showDisabledCounter)
- }
-
- def isShowWarningsCounter() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_SHOW_WARNINGS_COUNTER, false)
- }
-
- def setShowWarningsCounter(boolean showWarningCounter) {
- getHashStructure.putBoolean(PreferenceModel.KEY_SHOW_WARNINGS_COUNTER, showWarningCounter)
- }
-
- def isShowInfoCounter() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_SHOW_INFO_COUNTER, false)
- }
-
- def setShowInfoCounter(boolean showInfoCounter) {
- getHashStructure.putBoolean(PreferenceModel.KEY_SHOW_INFO_COUNTER, showInfoCounter)
- }
-
- def isShowWarningIndicator() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_SHOW_WARNING_INDICATOR, false)
- }
-
- def setShowWarningIndicator(boolean showWarningIndicator) {
- getHashStructure.putBoolean(PreferenceModel.KEY_SHOW_WARNING_INDICATOR, showWarningIndicator)
- }
-
- def isShowInfoIndicator() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_SHOW_INFO_INDICATOR, false)
- }
-
- def setShowInfoIndicator(boolean showInfoIndicator) {
- getHashStructure.putBoolean(PreferenceModel.KEY_SHOW_INFO_INDICATOR, showInfoIndicator)
- }
-
- def isShowSuccessfulTests() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_SHOW_SUCCESSFUL_TESTS, true)
- }
-
- def setShowSuccessfulTests(boolean showSuccessfulTests) {
- getHashStructure.putBoolean(PreferenceModel.KEY_SHOW_SUCCESSFUL_TESTS, showSuccessfulTests)
- }
-
- def isShowDisabledTests() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_SHOW_DISABLED_TESTS, true)
- }
-
- def setShowDisabledTests(boolean showDisabledTests) {
- getHashStructure.putBoolean(PreferenceModel.KEY_SHOW_DISABLED_TESTS, showDisabledTests)
- }
-
- def isShowTestDescription() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_SHOW_TEST_DESCRIPTION, false)
- }
-
- def setShowTestDescription(boolean showTestDescription) {
- getHashStructure.putBoolean(PreferenceModel.KEY_SHOW_TEST_DESCRIPTION, showTestDescription)
- }
-
- def isSyncDetailTab() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_SYNC_DETAIL_TAB, true)
- }
-
- def setSyncDetailTab(boolean syncDetailTab) {
- getHashStructure.putBoolean(PreferenceModel.KEY_SYNC_DETAIL_TAB, syncDetailTab)
- }
-
- def getTestPackagePrefix() {
- return getHashStructure.getString(PreferenceModel.KEY_TEST_PACKAGE_PREFIX, "test_")
- }
-
- def setTestPackagePrefix(String testPackagePrefix) {
- getHashStructure.putString(PreferenceModel.KEY_TEST_PACKAGE_PREFIX, testPackagePrefix)
- }
-
- def getTestPackageSuffix() {
- return getHashStructure.getString(PreferenceModel.KEY_TEST_PACKAGE_SUFFIX, "")
- }
-
- def setTestPackageSuffix(String testPackageSuffix) {
- getHashStructure.putString(PreferenceModel.KEY_TEST_PACKAGE_SUFFIX, testPackageSuffix)
- }
-
- def getTestUnitPrefix() {
- return getHashStructure.getString(PreferenceModel.KEY_TEST_UNIT_PREFIX, "")
- }
-
- def setTestUnitPrefix(String testUnitPrefix) {
- getHashStructure.putString(PreferenceModel.KEY_TEST_UNIT_PREFIX, testUnitPrefix)
- }
-
- def getTestUnitSuffix() {
- return getHashStructure.getString(PreferenceModel.KEY_TEST_UNIT_SUFFIX, "")
- }
-
- def setTestUnitSuffix(String testUnitSuffix) {
- getHashStructure.putString(PreferenceModel.KEY_TEST_UNIT_SUFFIX, testUnitSuffix)
- }
-
- def getNumberOfTestsPerUnit() {
- return getHashStructure.getInt(PreferenceModel.KEY_NUMBER_OF_TESTS_PER_UNIT, 1)
- }
-
- def setNumberOfTestsPerUnit(int numberOfTestsPerUnit) {
- getHashStructure.putInt(PreferenceModel.KEY_NUMBER_OF_TESTS_PER_UNIT, numberOfTestsPerUnit)
- }
-
- def isCheckGenerateUtplsqlTest() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_CHECK_GENERATE_UTPLSQL_TEST, false)
- }
-
- def setCheckGenerateUtplsqlTest(boolean checkGenerateUtplsqlTest) {
- getHashStructure.putBoolean(PreferenceModel.KEY_CHECK_GENERATE_UTPLSQL_TEST, checkGenerateUtplsqlTest)
- }
-
- def isGenerateComments() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_GENERATE_COMMENTS, true)
- }
-
- def setGenerateComments(boolean generateComments) {
- getHashStructure.putBoolean(PreferenceModel.KEY_GENERATE_COMMENTS, generateComments)
- }
-
- def isDisableTests() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_DISABLE_TESTS, false)
- }
-
- def setDisableTests(boolean disableTests) {
- getHashStructure.putBoolean(PreferenceModel.KEY_DISABLE_TESTS, disableTests)
- }
-
- def getSuitePath() {
- return getHashStructure.getString(PreferenceModel.KEY_SUITE_PATH, "alltests")
- }
-
- def setSuitePath(String suitePath) {
- getHashStructure.putString(PreferenceModel.KEY_SUITE_PATH, suitePath)
- }
-
- def getIndentSpaces() {
- return getHashStructure.getInt(PreferenceModel.KEY_INDENT_SPACES, 3)
- }
-
- def setIndentSpaces(int indentSpaces) {
- getHashStructure.putInt(PreferenceModel.KEY_INDENT_SPACES, indentSpaces)
- }
-
- def isGenerateFiles() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_GENERATE_FILES, true)
- }
-
- def setGenerateFiles(boolean generateFiles) {
- getHashStructure.putBoolean(PreferenceModel.KEY_GENERATE_FILES, generateFiles)
- }
-
- def getOutputDirectory() {
- return getHashStructure.getString(PreferenceModel.KEY_OUTPUT_DIRECTORY, DEFAULT_OUTPUT_DIRECTORY)
- }
-
- def setOutputDirectory(String outputDirectory) {
- val dir = if (outputDirectory.empty) {DEFAULT_OUTPUT_DIRECTORY} else {outputDirectory}
- getHashStructure.putString(PreferenceModel.KEY_OUTPUT_DIRECTORY, dir)
- }
-
- def isDeleteExistingFiles() {
- return getHashStructure.getBoolean(PreferenceModel.KEY_DELETE_EXISTING_FILES, false)
- }
-
- def setDeleteExistingFiles(boolean deleteExistingFiles) {
- getHashStructure.putBoolean(PreferenceModel.KEY_DELETE_EXISTING_FILES, deleteExistingFiles)
- }
-
- def getRootFolderInOddgenView() {
- return getHashStructure.getString(PreferenceModel.KEY_ROOT_FOLDER_IN_ODDGEN_VIEW, "utPLSQL")
- }
-
- def setRootFolderInOddgenView(String rootFolder) {
- val folder = if (rootFolder.empty) {"utPLSQL"} else {rootFolder}
- getHashStructure.putString(PreferenceModel.KEY_ROOT_FOLDER_IN_ODDGEN_VIEW, folder)
- }
-
- override toString() {
- new ToStringBuilder(this).addAllFields.toString
- }
-}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Counter.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Counter.java
new file mode 100644
index 00000000..77ffceb9
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Counter.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class Counter {
+ private Integer disabled;
+ private Integer success;
+ private Integer failure;
+ private Integer error;
+ private Integer warning;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("disabled", disabled)
+ .append("success", success)
+ .append("failure", failure)
+ .append("error", error)
+ .append("warning", warning)
+ .toString();
+ }
+
+ public Integer getDisabled() {
+ return disabled;
+ }
+
+ public void setDisabled(final Integer disabled) {
+ this.disabled = disabled;
+ }
+
+ public Integer getSuccess() {
+ return success;
+ }
+
+ public void setSuccess(final Integer success) {
+ this.success = success;
+ }
+
+ public Integer getFailure() {
+ return failure;
+ }
+
+ public void setFailure(final Integer failure) {
+ this.failure = failure;
+ }
+
+ public Integer getError() {
+ return error;
+ }
+
+ public void setError(final Integer error) {
+ this.error = error;
+ }
+
+ public Integer getWarning() {
+ return warning;
+ }
+
+ public void setWarning(final Integer warning) {
+ this.warning = warning;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Counter.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Counter.xtend
deleted file mode 100644
index 0d496e42..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Counter.xtend
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.model.AbstractModel
-
-@Accessors
-class Counter extends AbstractModel {
- Integer disabled
- Integer success
- Integer failure
- Integer error
- Integer warning
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Expectation.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Expectation.java
new file mode 100644
index 00000000..2738bce1
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Expectation.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class Expectation {
+ private String description;
+ private String message;
+ private String caller;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("description", description)
+ .append("message", message)
+ .append("caller", caller)
+ .append("failureText", getFailureText())
+ .append("shortFailureText", getShortFailureText())
+ .append("callerLine", getCallerLine())
+ .toString();
+ }
+
+ public String getFailureText() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(message.trim());
+ if (caller != null) {
+ sb.append('\n');
+ sb.append(caller.trim());
+ }
+ return sb.toString();
+ }
+
+ public String getShortFailureText() {
+ final StringBuilder sb = new StringBuilder();
+ if (description != null) {
+ sb.append(description);
+ sb.append(" (line ");
+ sb.append(getCallerLine());
+ sb.append(")");
+ } else {
+ sb.append("Line ");
+ sb.append(getCallerLine());
+ }
+ return sb.toString();
+ }
+
+ public Integer getCallerLine() {
+ Integer line = null;
+ if (caller != null) {
+ final Pattern p = Pattern.compile("(?i)\"[^\\\"]+\",\\s+line\\s*([0-9]+)");
+ final Matcher m = p.matcher(caller);
+ if (m.find()) {
+ line = Integer.valueOf(m.group(1));
+ }
+ }
+ return line;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(final String message) {
+ this.message = message;
+ }
+
+ public String getCaller() {
+ return caller;
+ }
+
+ public void setCaller(final String caller) {
+ this.caller = caller;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Expectation.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Expectation.xtend
deleted file mode 100644
index 67d7cc19..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Expectation.xtend
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import java.util.regex.Pattern
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.model.AbstractModel
-
-@Accessors
-class Expectation extends AbstractModel {
- String description
- String message
- String caller
-
- def getFailureText() {
- return '''
- «message.trim»
- «caller?.trim»
- '''.toString.trim
- }
-
- def getShortFailureText() {
- return '''«IF description !== null»«description» (line «callerLine»)«ELSE»Line «callerLine»«ENDIF»'''.toString
- }
-
- def getCallerLine() {
- var Integer line = null
- if (caller !== null) {
- val p = Pattern.compile("(?i)\"[^\\\"]+\",\\s+line\\s*([0-9]+)")
- val m = p.matcher(caller)
- if (m.find) {
- line = Integer.valueOf(m.group(1))
- }
- }
- return line
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Item.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Item.java
new file mode 100644
index 00000000..70bcef0c
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Item.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public abstract class Item {
+ private String id;
+ private String startTime;
+ private String endTime;
+ private Double executionTime;
+ private Counter counter;
+ private String errorStack;
+ private String serverOutput;
+ private String warnings;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("id", id)
+ .append("startTime", startTime)
+ .append("endTime", endTime)
+ .append("executionTime", executionTime)
+ .append("counter", counter)
+ .append("errorStack", errorStack)
+ .append("serverOutput", serverOutput)
+ .append("warnings", warnings)
+ .toString();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public String getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(final String startTime) {
+ this.startTime = startTime;
+ }
+
+ public String getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(final String endTime) {
+ this.endTime = endTime;
+ }
+
+ public Double getExecutionTime() {
+ return executionTime;
+ }
+
+ public void setExecutionTime(final Double executionTime) {
+ this.executionTime = executionTime;
+ }
+
+ public Counter getCounter() {
+ return counter;
+ }
+
+ public void setCounter(final Counter counter) {
+ this.counter = counter;
+ }
+
+ public String getErrorStack() {
+ return errorStack;
+ }
+
+ public void setErrorStack(final String errorStack) {
+ this.errorStack = errorStack;
+ }
+
+ public String getServerOutput() {
+ return serverOutput;
+ }
+
+ public void setServerOutput(final String serverOutput) {
+ this.serverOutput = serverOutput;
+ }
+
+ public String getWarnings() {
+ return warnings;
+ }
+
+ public void setWarnings(final String warnings) {
+ this.warnings = warnings;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Item.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Item.xtend
deleted file mode 100644
index 01db70a6..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Item.xtend
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.model.AbstractModel
-
-@Accessors
-abstract class Item extends AbstractModel {
- String id
- String startTime
- String endTime
- Double executionTime
- Counter counter
- String errorStack
- String serverOutput
- String warnings
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostEvent.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostEvent.java
new file mode 100644
index 00000000..f24f8f52
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostEvent.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public abstract class PostEvent extends RealtimeReporterEvent {
+ private String startTime;
+ private String endTime;
+ private Double executionTime;
+ private Counter counter;
+ private String errorStack;
+ private String serverOutput;
+ private String warnings;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("startTime", startTime)
+ .append("endTime", endTime)
+ .append("executionTime", executionTime)
+ .append("counter", counter)
+ .append("errorStack", errorStack)
+ .append("serverOutput", serverOutput)
+ .append("warnings", warnings)
+ .toString();
+ }
+
+ public PostEvent() {
+ counter = new Counter();
+ }
+
+ public String getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(final String startTime) {
+ this.startTime = startTime;
+ }
+
+ public String getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(final String endTime) {
+ this.endTime = endTime;
+ }
+
+ public Double getExecutionTime() {
+ return executionTime;
+ }
+
+ public void setExecutionTime(final Double executionTime) {
+ this.executionTime = executionTime;
+ }
+
+ public Counter getCounter() {
+ return counter;
+ }
+
+ public void setCounter(final Counter counter) {
+ this.counter = counter;
+ }
+
+ public String getErrorStack() {
+ return errorStack;
+ }
+
+ public void setErrorStack(final String errorStack) {
+ this.errorStack = errorStack;
+ }
+
+ public String getServerOutput() {
+ return serverOutput;
+ }
+
+ public void setServerOutput(final String serverOutput) {
+ this.serverOutput = serverOutput;
+ }
+
+ public String getWarnings() {
+ return warnings;
+ }
+
+ public void setWarnings(final String warnings) {
+ this.warnings = warnings;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostEvent.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostEvent.xtend
deleted file mode 100644
index 67d9c61c..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostEvent.xtend
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import org.eclipse.xtend.lib.annotations.Accessors
-
-@Accessors
-abstract class PostEvent extends RealtimeReporterEvent {
- String startTime
- String endTime
- Double executionTime
- Counter counter
- String errorStack
- String serverOutput
- String warnings
-
- new() {
- counter = new Counter
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostRunEvent.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostRunEvent.java
new file mode 100644
index 00000000..8c8dbe2f
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostRunEvent.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class PostRunEvent extends PostEvent {
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ // ancestor
+ .append("startTime", getStartTime())
+ .append("endTime", getEndTime())
+ .append("executionTime", getExecutionTime())
+ .append("counter", getCounter())
+ .append("errorStack", getErrorStack())
+ .append("serverOutput", getServerOutput())
+ .append("warnings", getWarnings())
+ .toString();
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostSuiteEvent.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostSuiteEvent.java
new file mode 100644
index 00000000..292671c4
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostSuiteEvent.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class PostSuiteEvent extends PostEvent {
+ private String id;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ // ancestor
+ .append("startTime", getStartTime())
+ .append("endTime", getEndTime())
+ .append("executionTime", getExecutionTime())
+ .append("counter", getCounter())
+ .append("errorStack", getErrorStack())
+ .append("serverOutput", getServerOutput())
+ .append("warnings", getWarnings())
+ // local
+ .append("id", id)
+ .toString();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostSuiteEvent.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostSuiteEvent.xtend
deleted file mode 100644
index 10a674ed..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostSuiteEvent.xtend
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import org.eclipse.xtend.lib.annotations.Accessors
-
-@Accessors
-class PostSuiteEvent extends PostEvent {
- String id
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostTestEvent.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostTestEvent.java
new file mode 100644
index 00000000..92a43484
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostTestEvent.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class PostTestEvent extends PostEvent {
+ private String id;
+ private Integer testNumber;
+ private Integer totalNumberOfTests;
+ private List failedExpectations;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ // ancestor
+ .append("startTime", getStartTime())
+ .append("endTime", getEndTime())
+ .append("executionTime", getExecutionTime())
+ .append("counter", getCounter())
+ .append("errorStack", getErrorStack())
+ .append("serverOutput", getServerOutput())
+ .append("warnings", getWarnings())
+ // local
+ .append("id", id)
+ .append("testNumber", testNumber)
+ .append("totalNumberOfTests", totalNumberOfTests)
+ .append("failedExpectations", failedExpectations)
+ .toString();
+ }
+
+ public PostTestEvent() {
+ failedExpectations = new ArrayList<>();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public Integer getTestNumber() {
+ return testNumber;
+ }
+
+ public void setTestNumber(final Integer testNumber) {
+ this.testNumber = testNumber;
+ }
+
+ public Integer getTotalNumberOfTests() {
+ return totalNumberOfTests;
+ }
+
+ public void setTotalNumberOfTests(final Integer totalNumberOfTests) {
+ this.totalNumberOfTests = totalNumberOfTests;
+ }
+
+ public List getFailedExpectations() {
+ return failedExpectations;
+ }
+
+ public void setFailedExpectations(final List failedExpectations) {
+ this.failedExpectations = failedExpectations;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostTestEvent.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostTestEvent.xtend
deleted file mode 100644
index bd28ab6c..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostTestEvent.xtend
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import java.util.ArrayList
-import java.util.List
-import org.eclipse.xtend.lib.annotations.Accessors
-
-@Accessors
-class PostTestEvent extends PostEvent {
- String id
- Integer testNumber
- Integer totalNumberOfTests
- List failedExpectations
-
- new() {
- failedExpectations = new ArrayList
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreRunEvent.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreRunEvent.java
new file mode 100644
index 00000000..dd1f0db8
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreRunEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class PreRunEvent extends RealtimeReporterEvent {
+ private List- items;
+ private Integer totalNumberOfTests;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("items", items)
+ .append("totalNumberOfTests", totalNumberOfTests)
+ .toString();
+ }
+
+ public PreRunEvent() {
+ items = new ArrayList<>();
+ }
+
+ public List
- getItems() {
+ return items;
+ }
+
+ public void setItems(final List
- items) {
+ this.items = items;
+ }
+
+ public Integer getTotalNumberOfTests() {
+ return totalNumberOfTests;
+ }
+
+ public void setTotalNumberOfTests(final Integer totalNumberOfTests) {
+ this.totalNumberOfTests = totalNumberOfTests;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreRunEvent.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreRunEvent.xtend
deleted file mode 100644
index 5750cd8e..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreRunEvent.xtend
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import java.util.ArrayList
-import java.util.List
-import org.eclipse.xtend.lib.annotations.Accessors
-
-@Accessors
-class PreRunEvent extends RealtimeReporterEvent {
- List
- items
- Integer totalNumberOfTests
-
- new() {
- items = new ArrayList
-
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/oddgen/GenContext.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreSuiteEvent.java
similarity index 54%
rename from sqldev/src/main/java/org/utplsql/sqldev/model/oddgen/GenContext.xtend
rename to sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreSuiteEvent.java
index bb4afc77..7b3ccf5c 100644
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/oddgen/GenContext.xtend
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreSuiteEvent.java
@@ -13,24 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.utplsql.sqldev.model.oddgen
+package org.utplsql.sqldev.model.runner;
-import java.sql.Connection
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.model.AbstractModel
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
-@Accessors
-class GenContext extends AbstractModel {
- Connection conn
- String objectType
- String objectName
- String testPackagePrefix
- String testPackageSuffix
- String testUnitPrefix
- String testUnitSuffix
- int numberOfTestsPerUnit
- boolean generateComments
- boolean disableTests
- String suitePath
- int indentSpaces
+public class PreSuiteEvent extends RealtimeReporterEvent {
+ private String id;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("id", id)
+ .toString();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreSuiteEvent.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreSuiteEvent.xtend
deleted file mode 100644
index 0304f071..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreSuiteEvent.xtend
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import org.eclipse.xtend.lib.annotations.Accessors
-
-@Accessors
-class PreSuiteEvent extends RealtimeReporterEvent {
- String id
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreTestEvent.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreTestEvent.java
new file mode 100644
index 00000000..1fdbd362
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreTestEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class PreTestEvent extends RealtimeReporterEvent {
+ private String id;
+ private Integer testNumber;
+ private Integer totalNumberOfTests;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("id", id)
+ .append("testNumber", testNumber)
+ .append("totalNumberOfTests", totalNumberOfTests)
+ .toString();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public Integer getTestNumber() {
+ return testNumber;
+ }
+
+ public void setTestNumber(final Integer testNumber) {
+ this.testNumber = testNumber;
+ }
+
+ public Integer getTotalNumberOfTests() {
+ return totalNumberOfTests;
+ }
+
+ public void setTotalNumberOfTests(final Integer totalNumberOfTests) {
+ this.totalNumberOfTests = totalNumberOfTests;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreTestEvent.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreTestEvent.xtend
deleted file mode 100644
index a54e3c5e..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PreTestEvent.xtend
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import org.eclipse.xtend.lib.annotations.Accessors
-
-@Accessors
-class PreTestEvent extends RealtimeReporterEvent {
- String id
- Integer testNumber
- Integer totalNumberOfTests
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostRunEvent.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/RealtimeReporterEvent.java
similarity index 81%
rename from sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostRunEvent.xtend
rename to sqldev/src/main/java/org/utplsql/sqldev/model/runner/RealtimeReporterEvent.java
index ee5edc30..3f7d7d1d 100644
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/PostRunEvent.xtend
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/RealtimeReporterEvent.java
@@ -13,10 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.utplsql.sqldev.model.runner
+package org.utplsql.sqldev.model.runner;
-import org.eclipse.xtend.lib.annotations.Accessors
-
-@Accessors
-class PostRunEvent extends PostEvent {
+public abstract class RealtimeReporterEvent {
}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Run.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Run.java
new file mode 100644
index 00000000..ed775d36
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Run.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2019 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class Run {
+ private String reporterId;
+ private String connectionName;
+ private List pathList;
+ private Integer currentTestNumber;
+ private Test currentTest;
+ private Integer totalNumberOfTests;
+ private String startTime;
+ private String endTime;
+ private Double executionTime;
+ private Counter counter;
+ private Integer infoCount;
+ private String errorStack;
+ private String serverOutput;
+ private LinkedHashMap tests;
+ private String status;
+ private Long start;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("reporterId", reporterId)
+ .append("connectionName", connectionName)
+ .append("pathList", pathList)
+ .append("currentTestNumber", currentTestNumber)
+ .append("currentTest", currentTest)
+ .append("totalNumberOfTests", totalNumberOfTests)
+ .append("startTime", startTime)
+ .append("endTime", endTime)
+ .append("executionTime", executionTime)
+ .append("counter", counter)
+ .append("infoCount", infoCount)
+ .append("errorStack", errorStack)
+ .append("serverOutput", serverOutput)
+ .append("tests", tests)
+ .append("status", status)
+ .append("start", start)
+ .append("endTime", endTime)
+ .append("totalNumberOfCompletedTests", getTotalNumberOfCompletedTests())
+ .toString();
+ }
+
+ public Run(final String reporterId, final String connectionName, final List pathList) {
+ this.reporterId = reporterId;
+ this.connectionName = connectionName;
+ this.pathList = pathList;
+ counter = new Counter();
+ tests = new LinkedHashMap<>();
+ }
+
+ public void setStartTime(final String startTime) {
+ this.startTime = startTime;
+ start = System.currentTimeMillis();
+ }
+
+ public String getName() {
+ final String time = startTime.substring(11, 19);
+ final String conn = connectionName != null ? connectionName.substring(15) : "n/a";
+ final StringBuilder sb = new StringBuilder();
+ sb.append(time);
+ sb.append(" (");
+ sb.append(conn);
+ sb.append(")");
+ return sb.toString();
+ }
+
+ public void put(final List
- items) {
+ for (final Item item : items) {
+ if (item instanceof Test) {
+ tests.put(((Test) item).getId(), (Test) item);
+ }
+ if (item instanceof Suite) {
+ put(((Suite) item).getItems());
+ }
+ }
+ }
+
+ public Test getTest(final String id) {
+ return tests.get(id);
+ }
+
+ public int getTotalNumberOfCompletedTests() {
+ if (counter.getDisabled() == null || counter.getSuccess() == null || counter.getFailure() == null
+ || counter.getError() == null) {
+ return -1;
+ }
+ return counter.getDisabled() + counter.getSuccess() + counter.getFailure() + counter.getError();
+ }
+
+ public String getReporterId() {
+ return reporterId;
+ }
+
+ public void setReporterId(final String reporterId) {
+ this.reporterId = reporterId;
+ }
+
+ public String getConnectionName() {
+ return connectionName;
+ }
+
+ public void setConnectionName(final String connectionName) {
+ this.connectionName = connectionName;
+ }
+
+ public List getPathList() {
+ return pathList;
+ }
+
+ public void setPathList(final List pathList) {
+ this.pathList = pathList;
+ }
+
+ public Integer getCurrentTestNumber() {
+ return currentTestNumber;
+ }
+
+ public void setCurrentTestNumber(final Integer currentTestNumber) {
+ this.currentTestNumber = currentTestNumber;
+ }
+
+ public Test getCurrentTest() {
+ return currentTest;
+ }
+
+ public void setCurrentTest(final Test currentTest) {
+ this.currentTest = currentTest;
+ }
+
+ public Integer getTotalNumberOfTests() {
+ return totalNumberOfTests;
+ }
+
+ public void setTotalNumberOfTests(final Integer totalNumberOfTests) {
+ this.totalNumberOfTests = totalNumberOfTests;
+ }
+
+ public String getStartTime() {
+ return startTime;
+ }
+
+ public String getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(final String endTime) {
+ this.endTime = endTime;
+ }
+
+ public Double getExecutionTime() {
+ return executionTime;
+ }
+
+ public void setExecutionTime(final Double executionTime) {
+ this.executionTime = executionTime;
+ }
+
+ public Counter getCounter() {
+ return counter;
+ }
+
+ public void setCounter(final Counter counter) {
+ this.counter = counter;
+ }
+
+ public Integer getInfoCount() {
+ return infoCount;
+ }
+
+ public void setInfoCount(final Integer infoCount) {
+ this.infoCount = infoCount;
+ }
+
+ public String getErrorStack() {
+ return errorStack;
+ }
+
+ public void setErrorStack(final String errorStack) {
+ this.errorStack = errorStack;
+ }
+
+ public String getServerOutput() {
+ return serverOutput;
+ }
+
+ public void setServerOutput(final String serverOutput) {
+ this.serverOutput = serverOutput;
+ }
+
+ public LinkedHashMap getTests() {
+ return tests;
+ }
+
+ public void setTests(final LinkedHashMap tests) {
+ this.tests = tests;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(final String status) {
+ this.status = status;
+ }
+
+ public Long getStart() {
+ return start;
+ }
+
+ public void setStart(final Long start) {
+ this.start = start;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Run.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Run.xtend
deleted file mode 100644
index 37b11926..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Run.xtend
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2019 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import java.util.LinkedHashMap
-import java.util.List
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.model.AbstractModel
-
-@Accessors
-class Run extends AbstractModel {
- String reporterId
- String connectionName
- List pathList
- Integer currentTestNumber
- Test currentTest
- Integer totalNumberOfTests
- String startTime
- String endTime
- Double executionTime
- Counter counter
- Integer infoCount
- String errorStack
- String serverOutput
- LinkedHashMap tests
- String status
- Long start
-
- new(String reporterId, String connectionName, List pathList) {
- this.reporterId = reporterId
- this.connectionName = connectionName
- this.pathList = pathList
- this.counter = new Counter
- this.tests = new LinkedHashMap
- }
-
- def void setStartTime(String startTime) {
- this.startTime = startTime
- start = System.currentTimeMillis
- }
-
- def getName() {
- val time = startTime.substring(11,19)
- val conn = connectionName?.substring(15)
- return '''«time» («conn»)'''
- }
-
- def void put(List
- items) {
- for (item : items) {
- if (item instanceof Test) {
- this.tests.put(item.id, item)
- }
- if (item instanceof Suite) {
- item.items.put
- }
- }
- }
-
- def getTest(String id) {
- return tests.get(id)
- }
-
- def getTotalNumberOfCompletedTests() {
- return counter.disabled + counter.success + counter.failure + counter.error
- }
-
-}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Suite.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Suite.java
new file mode 100644
index 00000000..b6ec4be2
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Suite.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class Suite extends Item {
+ private String name;
+ private String description;
+ private List
- items;
+
+ public Suite() {
+ items = new ArrayList<>();
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ // ancestor
+ .append("id", getId())
+ .append("startTime", getStartTime())
+ .append("endTime", getEndTime())
+ .append("executionTime", getExecutionTime())
+ .append("counter", getCounter())
+ .append("errorStack", getErrorStack())
+ .append("serverOutput", getServerOutput())
+ .append("warnings", getWarnings())
+ // local
+ .append("name", name)
+ .append("description", description)
+ .append("items", items)
+ .toString();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ public List
- getItems() {
+ return items;
+ }
+
+ public void setItems(final List
- items) {
+ this.items = items;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Suite.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Suite.xtend
deleted file mode 100644
index d75efadc..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Suite.xtend
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import java.util.ArrayList
-import java.util.List
-import org.eclipse.xtend.lib.annotations.Accessors
-
-@Accessors
-class Suite extends Item {
- String name
- String description
- List
- items
-
- new() {
- items = new ArrayList
-
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Test.java b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Test.java
new file mode 100644
index 00000000..9e7d78ad
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Test.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.runner;
+
+import java.util.List;
+
+import javax.swing.Icon;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+import org.utplsql.sqldev.resources.UtplsqlResources;
+
+public class Test extends Item {
+ private String executableType;
+ private String ownerName;
+ private String objectName;
+ private String procedureName;
+ private Boolean disabled;
+ private String name;
+ private String description;
+ private Integer testNumber;
+ private List failedExpectations;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ // ancestor
+ .append("id", getId())
+ .append("startTime", getStartTime())
+ .append("endTime", getEndTime())
+ .append("executionTime", getExecutionTime())
+ .append("counter", getCounter())
+ .append("errorStack", getErrorStack())
+ .append("serverOutput", getServerOutput())
+ .append("warnings", getWarnings())
+ // local
+ .append("executableType", executableType)
+ .append("ownerName", ownerName)
+ .append("objectName", objectName)
+ .append("procedureName", procedureName)
+ .append("disabled", disabled)
+ .append("name", name)
+ .append("description", description)
+ .append("testNumber", testNumber)
+ .append("failedExpectations", failedExpectations)
+ .append("statusIcon", getStatusIcon())
+ .append("warningIcon", getWarningIcon())
+ .append("infoIcon", getInfoIcon())
+ .toString();
+ }
+
+ public Icon getStatusIcon() {
+ Icon icon = null;
+ if (getStartTime() != null && getEndTime() == null) {
+ icon = UtplsqlResources.getIcon("PROGRESS_ICON");
+ } else {
+ if (getCounter() != null) {
+ if (getCounter().getSuccess() > 0) {
+ icon = UtplsqlResources.getIcon("SUCCESS_ICON");
+ } else if (getCounter().getError() > 0) {
+ icon = UtplsqlResources.getIcon("ERROR_ICON");
+ } else if (getCounter().getFailure() > 0) {
+ icon = UtplsqlResources.getIcon("FAILURE_ICON");
+ } else if (getCounter().getDisabled() > 0) {
+ icon = UtplsqlResources.getIcon("DISABLED_ICON");
+ }
+ }
+ }
+ return icon;
+ }
+
+ public Icon getWarningIcon() {
+ Icon icon = null;
+ if (getCounter() != null && getCounter().getWarning() > 0) {
+ icon = UtplsqlResources.getIcon("WARNING_ICON");
+ }
+ return icon;
+ }
+
+ public Icon getInfoIcon() {
+ Icon icon = null;
+ if (getServerOutput() != null && getServerOutput().length() > 0) {
+ icon = UtplsqlResources.getIcon("INFO_ICON");
+ }
+ return icon;
+ }
+
+ public String getExecutableType() {
+ return executableType;
+ }
+
+ public void setExecutableType(final String executableType) {
+ this.executableType = executableType;
+ }
+
+ public String getOwnerName() {
+ return ownerName;
+ }
+
+ public void setOwnerName(final String ownerName) {
+ this.ownerName = ownerName;
+ }
+
+ public String getObjectName() {
+ return objectName;
+ }
+
+ public void setObjectName(final String objectName) {
+ this.objectName = objectName;
+ }
+
+ public String getProcedureName() {
+ return procedureName;
+ }
+
+ public void setProcedureName(final String procedureName) {
+ this.procedureName = procedureName;
+ }
+
+ public Boolean getDisabled() {
+ return disabled;
+ }
+
+ public void setDisabled(final Boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ public Integer getTestNumber() {
+ return testNumber;
+ }
+
+ public void setTestNumber(final Integer testNumber) {
+ this.testNumber = testNumber;
+ }
+
+ public List getFailedExpectations() {
+ return failedExpectations;
+ }
+
+ public void setFailedExpectations(final List failedExpectations) {
+ this.failedExpectations = failedExpectations;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Test.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Test.xtend
deleted file mode 100644
index 30070e85..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/runner/Test.xtend
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.runner
-
-import java.util.List
-import javax.swing.Icon
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.resources.UtplsqlResources
-
-@Accessors
-class Test extends Item {
- String executableType
- String ownerName
- String objectName
- String procedureName
- Boolean disabled
- String name
- String description
- Integer testNumber
- List failedExpectations
-
- def getStatusIcon() {
- var Icon icon = null
- if (startTime !== null && endTime === null ) {
- icon = UtplsqlResources.getIcon("PROGRESS_ICON")
- } else {
- if (counter !== null) {
- if (counter.success > 0) {
- icon = UtplsqlResources.getIcon("SUCCESS_ICON")
- } else if (counter.error > 0) {
- icon = UtplsqlResources.getIcon("ERROR_ICON")
- } else if (counter.failure > 0) {
- icon = UtplsqlResources.getIcon("FAILURE_ICON")
- } else if (counter.disabled > 0) {
- icon = UtplsqlResources.getIcon("DISABLED_ICON")
- }
- }
- }
- return icon
- }
-
- def getWarningIcon() {
- var Icon icon = null
- if (counter !== null) {
- if (counter.warning > 0) {
- icon = UtplsqlResources.getIcon("WARNING_ICON")
- }
- }
- return icon
- }
-
- def getInfoIcon() {
- var Icon icon = null
- if (serverOutput !== null && serverOutput.length > 0) {
- icon = UtplsqlResources.getIcon("INFO_ICON")
- }
- return icon
- }
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/ut/Annotation.java b/sqldev/src/main/java/org/utplsql/sqldev/model/ut/Annotation.java
new file mode 100644
index 00000000..3f69ef77
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/ut/Annotation.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.ut;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class Annotation {
+ private String objectOwner;
+ private String objectName;
+ private String name;
+ private String text;
+ private String subobjectName;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("objectOwner", objectOwner)
+ .append("objectName", objectName)
+ .append("name", name)
+ .append("text", text)
+ .append("subobjectName", subobjectName)
+ .toString();
+ }
+
+ public String getObjectOwner() {
+ return objectOwner;
+ }
+
+ public void setObjectOwner(final String objectOwner) {
+ this.objectOwner = objectOwner;
+ }
+
+ public String getObjectName() {
+ return objectName;
+ }
+
+ public void setObjectName(final String objectName) {
+ this.objectName = objectName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(final String text) {
+ this.text = text;
+ }
+
+ public String getSubobjectName() {
+ return subobjectName;
+ }
+
+ public void setSubobjectName(final String subobjectName) {
+ this.subobjectName = subobjectName;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/ut/Annotation.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/ut/Annotation.xtend
deleted file mode 100644
index ee658e91..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/ut/Annotation.xtend
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.ut
-
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.model.AbstractModel
-
-@Accessors
-class Annotation extends AbstractModel {
- String objectOwner
- String objectName
- String name
- String text
- String subobjectName
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/ut/OutputLines.java b/sqldev/src/main/java/org/utplsql/sqldev/model/ut/OutputLines.java
new file mode 100644
index 00000000..a8a041ae
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/model/ut/OutputLines.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.model.ut;
+
+import org.springframework.core.style.ToStringCreator;
+import org.utplsql.sqldev.model.JsonToStringStyler;
+
+public class OutputLines {
+ private String[] lines;
+ private Integer numlines;
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this, JsonToStringStyler.INSTANCE)
+ .append("lines", lines)
+ .append("numlines", numlines)
+ .toString();
+ }
+
+ public String[] getLines() {
+ return lines;
+ }
+
+ public void setLines(final String[] lines) {
+ this.lines = lines;
+ }
+
+ public Integer getNumlines() {
+ return numlines;
+ }
+
+ public void setNumlines(final Integer numlines) {
+ this.numlines = numlines;
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/model/ut/OutputLines.xtend b/sqldev/src/main/java/org/utplsql/sqldev/model/ut/OutputLines.xtend
deleted file mode 100644
index 7b1c946c..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/model/ut/OutputLines.xtend
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.model.ut
-
-import org.eclipse.xtend.lib.annotations.Accessors
-import org.utplsql.sqldev.model.AbstractModel
-
-@Accessors
-class OutputLines extends AbstractModel {
- String[] lines;
- Integer numlines;
-}
\ No newline at end of file
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/oddgen/RunGenerator.java b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/RunGenerator.java
new file mode 100644
index 00000000..215baf2f
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/RunGenerator.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.oddgen;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.oddgen.sqldev.generators.OddgenGenerator2;
+import org.oddgen.sqldev.generators.model.Node;
+import org.utplsql.sqldev.dal.UtplsqlDao;
+import org.utplsql.sqldev.model.DatabaseTools;
+import org.utplsql.sqldev.model.StringTools;
+import org.utplsql.sqldev.model.preference.PreferenceModel;
+import org.utplsql.sqldev.resources.UtplsqlResources;
+
+import oracle.ide.config.Preferences;
+
+public class RunGenerator implements OddgenGenerator2 {
+ public static final String YES = "Yes";
+ public static final String NO = "No";
+ public static final String RESET_PACKAGE = UtplsqlResources.getString("PREF_RESET_PACKAGE_LABEL");
+ public static final String CLEAR_SCREEN = UtplsqlResources.getString("PREF_CLEAR_SCREEN_LABEL");
+ public static final String INDENT_SPACES = UtplsqlResources.getString("PREF_INDENT_SPACES_LABEL");
+
+ // oddgen node cache
+ private List runnables = null;
+
+ @Override
+ public boolean isSupported(final Connection conn) {
+ return DatabaseTools.isSupported(conn);
+ }
+
+ @Override
+ public String getName(final Connection conn) {
+ return "Run test";
+ }
+
+ @Override
+ public String getDescription(final Connection conn) {
+ return "Runs utPLSQL test packages in the current user.";
+ }
+
+ @Override
+ public List getFolders(final Connection conn) {
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ final ArrayList folders = new ArrayList<>();
+ for (String f : preferences.getRootFolderInOddgenView().split(",")) {
+ if (f != null) {
+ folders.add(f.trim());
+ }
+ }
+ return folders;
+ }
+
+ @Override
+ public String getHelp(final Connection conn) {
+ return "
not yet available
";
+ }
+
+ @Override
+ public List getNodes(final Connection conn, final String parentNodeId) {
+ // oddgen asks for children for each parent node, regardless of load strategy (eager/lazy)
+ // oddgen does not know about the load strategy, hence caching is the responsibility of the generator
+ if (runnables == null) {
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ final LinkedHashMap params = new LinkedHashMap<>();
+ params.put(RESET_PACKAGE, preferences.isResetPackage() ? YES : NO);
+ params.put(CLEAR_SCREEN, preferences.isClearScreen() ? YES : NO);
+ params.put(INDENT_SPACES, String.valueOf(preferences.getIndentSpaces()));
+ final UtplsqlDao dao = new UtplsqlDao(conn);
+ // load node tree eagerly (all nodes in one go)
+ runnables = dao.runnables();
+ for (final Node node : runnables) {
+ node.setParams(params);
+ }
+ }
+ return runnables;
+ }
+
+ @Override
+ public HashMap> getLov(final Connection conn, final LinkedHashMap params, final List nodes) {
+ final HashMap> lov = new HashMap<>();
+ lov.put(RESET_PACKAGE, Arrays.asList(YES, NO));
+ lov.put(CLEAR_SCREEN, Arrays.asList(YES, NO));
+ lov.put(INDENT_SPACES, Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8"));
+ return lov;
+ }
+
+ @Override
+ public HashMap getParamStates(final Connection conn, final LinkedHashMap params, final List nodes) {
+ return new HashMap<>();
+ }
+
+ private String getPath(final Node node, final Connection conn) {
+ if ("SUITE".equals(node.getId()) || "SUITEPATH".equals(node.getId())) {
+ return DatabaseTools.getUser(conn);
+ } else {
+ return node.getId();
+ }
+ }
+
+ public ArrayList dedup(final List nodes) {
+ final HashSet set = new HashSet<>();
+ for (final Node node : nodes) {
+ set.add(node.getId());
+ }
+ final ArrayList ret = new ArrayList<>();
+ for (final Node node : nodes) {
+ if (!set.contains(node.getParentId())) {
+ ret.add(node);
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public String generateProlog(final Connection conn, final List nodes) {
+ final ArrayList dedupNodes = dedup(nodes);
+ final LinkedHashMap params = dedupNodes.get(0).getParams();
+ final StringBuilder sb = new StringBuilder();
+ if (YES.equals(params.get(RESET_PACKAGE))) {
+ sb.append("EXECUTE dbms_session.reset_package;\n");
+ }
+ sb.append("SET SERVEROUTPUT ON SIZE UNLIMITED\n");
+ if (YES.equals(params.get(CLEAR_SCREEN))) {
+ sb.append("CLEAR SCREEN\n");
+ }
+ if (dedupNodes.size() == 1) {
+ sb.append("EXECUTE ut.run('");
+ sb.append(getPath(dedupNodes.get(0), conn));
+ sb.append("');\n");
+ } else {
+ final List paths = dedupNodes.stream().map(node -> getPath(node, conn)).collect(Collectors.toList());
+ sb.append("BEGIN\n");
+ sb.append("\tut.run(\n");
+ sb.append("\t\tut_varchar2_list(\n");
+ sb.append(StringTools.getCSV(paths, "\t\t\t"));
+ sb.append("\t\t)\n");
+ sb.append("\t);\n");
+ sb.append("END;\n");
+ sb.append("/\n");
+ }
+ final String ret = sb.toString();
+ return StringTools.replaceTabsWithSpaces(ret, Integer.valueOf(params.get(INDENT_SPACES)));
+ }
+
+ @Override
+ public String generateSeparator(final Connection conn) {
+ return "";
+ }
+
+ @Override
+ public String generateEpilog(final Connection conn, final List nodes) {
+ return "";
+ }
+
+ @Override
+ public String generate(final Connection conn, final Node node) {
+ return "";
+ }
+}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/oddgen/RunGenerator.xtend b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/RunGenerator.xtend
deleted file mode 100644
index b321b77f..00000000
--- a/sqldev/src/main/java/org/utplsql/sqldev/oddgen/RunGenerator.xtend
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2018 Philipp Salvisberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.utplsql.sqldev.oddgen
-
-import java.sql.Connection
-import java.util.ArrayList
-import java.util.HashMap
-import java.util.HashSet
-import java.util.LinkedHashMap
-import java.util.List
-import oracle.ide.config.Preferences
-import org.oddgen.sqldev.generators.OddgenGenerator2
-import org.oddgen.sqldev.generators.model.Node
-import org.utplsql.sqldev.dal.UtplsqlDao
-import org.utplsql.sqldev.model.preference.PreferenceModel
-import org.utplsql.sqldev.resources.UtplsqlResources
-
-class RunGenerator implements OddgenGenerator2 {
-
- public static val YES = "Yes"
- public static val NO = "No"
-
- public static var RESET_PACKAGE = UtplsqlResources.getString("PREF_RESET_PACKAGE_LABEL")
- public static var CLEAR_SCREEN = UtplsqlResources.getString("PREF_CLEAR_SCREEN_LABEL")
- public static var INDENT_SPACES = UtplsqlResources.getString("PREF_INDENT_SPACES_LABEL")
-
- // oddgen node cache
- var List runnables = null;
-
- override isSupported(Connection conn) {
- var ret = false
- if (conn !== null) {
- if (conn.metaData.databaseProductName.startsWith("Oracle")) {
- if (conn.metaData.databaseMajorVersion == 11) {
- if (conn.metaData.databaseMinorVersion >= 2) {
- ret = true
- }
- } else if (conn.metaData.databaseMajorVersion > 11) {
- ret = true
- }
- }
- }
- return ret
- }
-
- override getName(Connection conn) {
- return "Run test"
- }
-
- override getDescription(Connection conn) {
- return "Runs utPLSQL test packages in the current user."
- }
-
- override getFolders(Connection conn) {
- val preferences = PreferenceModel.getInstance(Preferences.preferences)
- val folders = new ArrayList
- for (f : preferences.rootFolderInOddgenView.split(",").filter[!it.empty]) {
- folders.add(f.trim)
- }
- return folders
- }
-
- override getHelp(Connection conn) {
- return "not yet available
"
- }
-
- override getNodes(Connection conn, String parentNodeId) {
- // oddgen asks for children for each parent node, regardless of load strategy (eager/lazy)
- // oddgen does not know about the load strategy, hence caching is the responsibility of the generator
- if (runnables === null) {
- val preferences = PreferenceModel.getInstance(Preferences.preferences)
- val params = new LinkedHashMap()
- params.put(RESET_PACKAGE, if (preferences.resetPackage) {YES} else {NO})
- params.put(CLEAR_SCREEN, if (preferences.clearScreen) {YES} else {NO})
- params.put(INDENT_SPACES, String.valueOf(preferences.indentSpaces))
- val UtplsqlDao dao = new UtplsqlDao(conn)
- // load node tree eagerly (all nodes in one go)
- runnables = dao.runnables
- for (node : runnables) {
- node.params = params
- }
- }
- return runnables
- }
-
- override getLov(Connection conn, LinkedHashMap params, List nodes) {
- val lov = new HashMap>()
- lov.put(RESET_PACKAGE, #[YES, NO])
- lov.put(CLEAR_SCREEN, #[YES, NO])
- lov.put(INDENT_SPACES, #["1", "2", "3", "4", "5", "6", "7", "8"])
- return lov
- }
-
- override getParamStates(Connection conn, LinkedHashMap params, List nodes) {
- return new HashMap
- }
-
- private def getPath(Node node, Connection conn) {
- if (node.id == "SUITE" || node.id == "SUITEPATH") {
- return conn.metaData.userName
- } else {
- return node.id
- }
- }
-
- private def replaceTabsWithSpaces(CharSequence input, int indentSpaces) {
- val spaces = String.format("%1$"+indentSpaces+"s", "")
- return input.toString.replace("\t", spaces)
- }
-
- def dedup(List nodes) {
- val set = new HashSet
- for (node : nodes) {
- set.add(node.id)
- }
- val ret = new ArrayList
- for (node : nodes) {
- if (!set.contains(node.parentId)) {
- ret.add(node)
- }
- }
- return ret
- }
-
- override generateProlog(Connection conn, List nodes) {
- val dedupNodes = nodes.dedup
- val params = dedupNodes.get(0).params
- val ret = '''
- «IF params.get(RESET_PACKAGE) == YES»
- EXECUTE dbms_session.reset_package;
- «ENDIF»
- SET SERVEROUTPUT ON SIZE UNLIMITED
- «IF params.get(CLEAR_SCREEN) == YES»
- CLEAR SCREEN
- «ENDIF»
- «IF dedupNodes.size == 1»
- EXECUTE ut.run('«dedupNodes.get(0).getPath(conn)»');
- «ELSE»
- BEGIN
- ut.run(
- ut_varchar2_list(
- «FOR node : dedupNodes SEPARATOR ","»
- '«node.getPath(conn)»'
- «ENDFOR»
- )
- );
- END;
- /
- «ENDIF»
- '''
- return ret.replaceTabsWithSpaces(Integer.valueOf(params.get(INDENT_SPACES)))
- }
-
- override generateSeparator(Connection conn) {
- return ""
- }
-
- override generateEpilog(Connection conn, List nodes) {
- return ""
- }
-
- override generate(Connection conn, Node node) {
- return ""
- }
-
-}
diff --git a/sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestGenerator.java b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestGenerator.java
new file mode 100644
index 00000000..77b2aa42
--- /dev/null
+++ b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestGenerator.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2018 Philipp Salvisberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.utplsql.sqldev.oddgen;
+
+import java.io.File;
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.oddgen.sqldev.generators.OddgenGenerator2;
+import org.oddgen.sqldev.generators.model.Node;
+import org.oddgen.sqldev.generators.model.NodeTools;
+import org.oddgen.sqldev.plugin.templates.TemplateTools;
+import org.utplsql.sqldev.dal.UtplsqlDao;
+import org.utplsql.sqldev.model.DatabaseTools;
+import org.utplsql.sqldev.model.oddgen.GenContext;
+import org.utplsql.sqldev.model.preference.PreferenceModel;
+import org.utplsql.sqldev.resources.UtplsqlResources;
+
+import oracle.ide.config.Preferences;
+
+public class TestGenerator implements OddgenGenerator2 {
+ private static final Logger logger = Logger.getLogger(TestGenerator.class.getName());
+
+ public static final String YES = "Yes";
+ public static final String NO = "No";
+
+ public static final String GENERATE_FILES = UtplsqlResources.getString("PREF_GENERATE_FILES_LABEL");
+ public static final String OUTPUT_DIRECTORY = UtplsqlResources.getString("PREF_OUTPUT_DIRECTORY_LABEL");
+ public static final String DELETE_EXISTING_FILES = UtplsqlResources.getString("PREF_DELETE_EXISTING_FILES_LABEL");
+ public static final String TEST_PACKAGE_PREFIX = UtplsqlResources.getString("PREF_TEST_PACKAGE_PREFIX_LABEL");
+ public static final String TEST_PACKAGE_SUFFIX = UtplsqlResources.getString("PREF_TEST_PACKAGE_SUFFIX_LABEL");
+ public static final String TEST_UNIT_PREFIX = UtplsqlResources.getString("PREF_TEST_UNIT_PREFIX_LABEL");
+ public static final String TEST_UNIT_SUFFIX = UtplsqlResources.getString("PREF_TEST_UNIT_SUFFIX_LABEL");
+ public static final String NUMBER_OF_TESTS_PER_UNIT = UtplsqlResources.getString("PREF_NUMBER_OF_TESTS_PER_UNIT_LABEL");
+ public static final String GENERATE_COMMENTS = UtplsqlResources.getString("PREF_GENERATE_COMMENTS_LABEL");
+ public static final String DISABLE_TESTS = UtplsqlResources.getString("PREF_DISABLE_TESTS_LABEL");
+ public static final String SUITE_PATH = UtplsqlResources.getString("PREF_SUITE_PATH_LABEL");
+ public static final String INDENT_SPACES = UtplsqlResources.getString("PREF_INDENT_SPACES_LABEL");
+
+ private final NodeTools nodeTools = new NodeTools();
+ private final TemplateTools templateTools = new TemplateTools();
+ private final ArrayList consoleOutput = new ArrayList<>();
+
+ private GenContext toContext(final Node node) {
+ final GenContext context = new GenContext();
+ context.setObjectType(nodeTools.toObjectType(node));
+ context.setObjectName(nodeTools.toObjectName(node));
+ context.setTestPackagePrefix(node.getParams().get(TEST_PACKAGE_PREFIX).toLowerCase());
+ context.setTestPackageSuffix(node.getParams().get(TEST_PACKAGE_SUFFIX).toLowerCase());
+ context.setTestUnitPrefix(node.getParams().get(TEST_UNIT_PREFIX).toLowerCase());
+ context.setTestUnitSuffix(node.getParams().get(TEST_UNIT_SUFFIX).toLowerCase());
+ context.setNumberOfTestsPerUnit((Integer.valueOf(node.getParams().get(NUMBER_OF_TESTS_PER_UNIT))).intValue());
+ context.setGenerateComments(YES.equals(node.getParams().get(GENERATE_COMMENTS)));
+ context.setDisableTests(YES.equals(node.getParams().get(DISABLE_TESTS)));
+ context.setSuitePath(node.getParams().get(SUITE_PATH).toLowerCase());
+ context.setIndentSpaces((Integer.valueOf(node.getParams().get(INDENT_SPACES))).intValue());
+ return context;
+ }
+
+ private void resetConsoleOutput() {
+ consoleOutput.clear();
+ }
+
+ private void saveConsoleOutput(final String s) {
+ if (s != null) {
+ for (final String line : s.split("[\\n\\r]+")) {
+ consoleOutput.add(line);
+ }
+ }
+ }
+
+ private void logConsoleOutput() {
+ for (final String line : consoleOutput) {
+ if (line.contains("error") || line.startsWith("Cannot")) {
+ logger.severe(line);
+ } else {
+ logger.fine(line);
+ }
+ }
+ }
+
+ private String deleteFile(final File file) {
+ String ret = null;
+ if (file.delete()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(file.getAbsoluteFile());
+ sb.append(" deleted.");
+ ret = sb.toString();
+ } else {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Cannot delete file ");
+ sb.append(file.getAbsoluteFile());
+ sb.append(".");
+ ret = sb.toString();
+ }
+ return ret;
+ }
+
+ private CharSequence deleteFiles(final String directory) {
+ StringBuilder sb = new StringBuilder();
+ final File dir = new File(directory);
+ for (final File file : dir.listFiles()) {
+ if (!file.isDirectory() && (file.getName().endsWith(".pks") || file.getName().endsWith(".pkb"))) {
+ sb.append(deleteFile(file));
+ sb.append('\n');
+ }
+ }
+ return sb;
+ }
+
+ @Override
+ public boolean isSupported(final Connection conn) {
+ return DatabaseTools.isSupported(conn);
+ }
+
+ @Override
+ public String getName(final Connection conn) {
+ return "Generate test";
+ }
+
+ @Override
+ public String getDescription(final Connection conn) {
+ return "Generates utPLSQL test packages for public units in packages, types, functions and procedures found in the current schema.";
+ }
+
+ @Override
+ public List getFolders(final Connection conn) {
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ final ArrayList folders = new ArrayList<>();
+ for (String f : preferences.getRootFolderInOddgenView().split(",")) {
+ if (f != null) {
+ folders.add(f.trim());
+ }
+ }
+ return folders;
+ }
+
+ @Override
+ public String getHelp(final Connection conn) {
+ return "not yet available
";
+ }
+
+ @Override
+ public List getNodes(final Connection conn, final String parentNodeId) {
+ final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences());
+ final LinkedHashMap params = new LinkedHashMap<>();
+ params.put(GENERATE_FILES, preferences.isGenerateFiles() ? YES : NO);
+ params.put(OUTPUT_DIRECTORY, preferences.getOutputDirectory());
+ params.put(DELETE_EXISTING_FILES, preferences.isDeleteExistingFiles() ? YES : NO);
+ params.put(TEST_PACKAGE_PREFIX, preferences.getTestPackagePrefix());
+ params.put(TEST_PACKAGE_SUFFIX, preferences.getTestPackageSuffix());
+ params.put(TEST_UNIT_PREFIX, preferences.getTestUnitPrefix());
+ params.put(TEST_UNIT_SUFFIX, preferences.getTestUnitSuffix());
+ params.put(NUMBER_OF_TESTS_PER_UNIT, String.valueOf(preferences.getNumberOfTestsPerUnit()));
+ params.put(GENERATE_COMMENTS, preferences.isGenerateComments() ? YES : NO);
+ params.put(DISABLE_TESTS, preferences.isDisableTests() ? YES : NO);
+ params.put(SUITE_PATH, preferences.getSuitePath());
+ params.put(INDENT_SPACES, String.valueOf(preferences.getIndentSpaces()));
+ if (parentNodeId == null || parentNodeId.isEmpty()) {
+ final Node packageNode = new Node();
+ packageNode.setId("PACKAGE");
+ packageNode.setParams(params);
+ packageNode.setLeaf(false);
+ packageNode.setGeneratable(true);
+ packageNode.setMultiselectable(true);
+ final Node typeNode = new Node();
+ typeNode.setId("TYPE");
+ typeNode.setParams(params);
+ typeNode.setLeaf(false);
+ typeNode.setGeneratable(true);
+ typeNode.setMultiselectable(true);
+ final Node functionNode = new Node();
+ functionNode.setId("FUNCTION");
+ functionNode.setParams(params);
+ functionNode.setLeaf(false);
+ functionNode.setGeneratable(true);
+ functionNode.setMultiselectable(true);
+ final Node procedureNode = new Node();
+ procedureNode.setId("PROCEDURE");
+ procedureNode.setParams(params);
+ procedureNode.setLeaf(false);
+ procedureNode.setGeneratable(true);
+ procedureNode.setMultiselectable(true);
+ return Arrays.asList(packageNode, typeNode, functionNode, procedureNode);
+ } else {
+ final UtplsqlDao dao = new UtplsqlDao(conn);
+ final List nodes = dao.testables(parentNodeId);
+ for (final Node node : nodes) {
+ node.setParams(params);
+ }
+ return nodes;
+ }
+ }
+
+ @Override
+ public HashMap> getLov(final Connection conn, final LinkedHashMap params,
+ final List nodes) {
+ final HashMap> lov = new HashMap<>();
+ lov.put(NUMBER_OF_TESTS_PER_UNIT, Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"));
+ lov.put(INDENT_SPACES, Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8"));
+ lov.put(GENERATE_COMMENTS, Arrays.asList(YES, NO));
+ lov.put(DISABLE_TESTS, Arrays.asList(YES, NO));
+ lov.put(GENERATE_FILES, Arrays.asList(YES, NO));
+ lov.put(DELETE_EXISTING_FILES, Arrays.asList(YES, NO));
+ return lov;
+ }
+
+ @Override
+ public HashMap