From 1bd02ea7a9f948a3d2e14b02e0c783ab9868304b Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sun, 7 Oct 2018 16:56:54 +0200 Subject: [PATCH 01/15] support functions, procedures, types in the parser --- .../sqldev/model/parser/PlsqlObject.xtend | 1 + .../utplsql/sqldev/parser/UtplsqlParser.xtend | 65 +++++----- .../sqldev/tests/UtplsqlParserTest.xtend | 112 +++++++++++++++--- 3 files changed, 132 insertions(+), 46 deletions(-) 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 index f9bc93d2..96b71db1 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/model/parser/PlsqlObject.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/model/parser/PlsqlObject.xtend @@ -23,6 +23,7 @@ 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/parser/UtplsqlParser.xtend b/sqldev/src/main/java/org/utplsql/sqldev/parser/UtplsqlParser.xtend index c6c523c8..6ac25a20 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/parser/UtplsqlParser.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/parser/UtplsqlParser.xtend @@ -93,10 +93,11 @@ class UtplsqlParser { } private def populateObjects() { - val p = Pattern.compile("(?i)(\\s*)(create(\\s+or\\s+replace)?\\s+(package)\\s+(body\\s+)?)([^\\s]+)(\\s+)") + val p = Pattern.compile("(?i)(\\s*)(create(\\s+or\\s+replace)?\\s+(package|type|function|procedure)\\s+(body\\s+)?)([^\\s]+)(\\s+)") val m = p.matcher(plsqlReduced) while (m.find) { val o = new PlsqlObject + o.type = m.group(4).toUpperCase o.name = m.group(6) o.position = m.start objects.add(o) @@ -145,8 +146,14 @@ class UtplsqlParser { } } } - - private def getObjectAt(int position) { + + /** + * gets the PL/SQL object based on the current editor position + * + * @param position the absolute position as used in {@link JTextComponent#getCaretPosition()} + * @return the PL/SQL object + */ + def getObjectAt(int position) { var PlsqlObject obj for (o : objects) { if (o.position <= position) { @@ -154,13 +161,29 @@ class UtplsqlParser { } } return obj - } - - private def getObjectNameAt(int position) { - val o = getObjectAt(position) - return if (o !== null) {o.name} else {""} } + /** + * converts a line and column to a postion as used in as used in {@link JTextComponent#getCaretPosition()} + * used for testing purposes only + * + * @param line the line as used in SQL Developer, starting with 1 + * @param column the column as used in SQL Developer, starting with 1 + * @return the position + */ + def toPosition(int line, int column) { + var lines=0 + for (var i=0; i Date: Sun, 7 Oct 2018 16:59:06 +0200 Subject: [PATCH 02/15] add context menu "Generate utPLSQL test" --- sqldev/extension.xml | 52 +++++++++++++++++- .../resources/UtplsqlResources.properties | 1 + .../resources/UtplsqlResources_de.properties | 1 + .../utplsql/sqldev/resources/accelerators.xml | 6 ++ .../sqldev/resources/images/oddgen.png | Bin 0 -> 3167 bytes 5 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 sqldev/src/main/resources/org/utplsql/sqldev/resources/images/oddgen.png diff --git a/sqldev/extension.xml b/sqldev/extension.xml index db4d9ff1..c27a035e 100644 --- a/sqldev/extension.xml +++ b/sqldev/extension.xml @@ -46,7 +46,7 @@ - + @@ -56,6 +56,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -66,12 +96,20 @@ Code-Editor + + + ${MENU_RUN_GENERATE_LABEL} + res:/org/utplsql/sqldev/resources/images/oddgen.png + Code-Editor + + + @@ -82,10 +120,11 @@
+
- +
+ + + +
+ +
+
+
org/utplsql/sqldev/resources/accelerators.xml diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties index a1690393..8255709e 100644 --- a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties +++ b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties @@ -14,4 +14,5 @@ PREF_CLEAR_SCREEN_LABEL=Clear script output panel before running utPLSQL? PREF_AUTO_EXECUTE_LABEL=Execute unit test automatically? PREF_CHECK_RUN_UTPLSQL_TEST_LABEL=Check availability of "Run utPLSQL test" menu option? MENU_RUN_TEST_LABEL=Run utPLSQL test +MENU_RUN_GENERATE_LABEL=Generate utPLSQL test WORKSHEET_TITLE=utPLSQL diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties index db1ad321..8cfa745a 100644 --- a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties +++ b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties @@ -8,4 +8,5 @@ PREF_CLEAR_SCREEN_LABEL=Skriptausgabe-Fenster vor der Ausf PREF_AUTO_EXECUTE_LABEL=Unit Test automatisch ausführen? PREF_CHECK_RUN_UTPLSQL_TEST_LABEL=Verfügbarkeit der Menüoption "utPLSQL Test ausführen" prüfen? MENU_RUN_TEST_LABEL=utPLSQL Test ausführen +MENU_GENERATE_TEST_LABEL=utPLSQL Test generieren WORKSHEET_TITLE=utPLSQL diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/accelerators.xml b/sqldev/src/main/resources/org/utplsql/sqldev/resources/accelerators.xml index 97522ff5..6ed2ac3e 100644 --- a/sqldev/src/main/resources/org/utplsql/sqldev/resources/accelerators.xml +++ b/sqldev/src/main/resources/org/utplsql/sqldev/resources/accelerators.xml @@ -3,10 +3,16 @@ alt shift T + + alt shift G + alt shift T + + alt shift G + diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/images/oddgen.png b/sqldev/src/main/resources/org/utplsql/sqldev/resources/images/oddgen.png new file mode 100644 index 0000000000000000000000000000000000000000..5f7d1aac8931ceebdd0a2182f5103cc0777e79ea GIT binary patch literal 3167 zcmV-l450IgP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0004sNklO7{>A6p~9A=B{~UO7=0lTWeo)e)zV@$M6@_a6oNF^5af`7 zR#QVDG}O`uL_?*}GgL$^4pA5XUSZztE52D&P%{T3H;&%Mvh-eJcc<#gh_n0hh7$ zKN1&k2M_SR1k`W?37s*-W~`2+xyle<;anu&E&-pg8{aUB5BPz<0cgZ79Esl7q6?2o zKo72A<1*#X<0htXzx<#a;viaZDq2`qNt{DBYM8}gJgu(rGj>K_qxcy6UWhj}> Date: Sun, 7 Oct 2018 16:59:54 +0200 Subject: [PATCH 03/15] enable/disable context menu "Generate utPLSQL test" --- .../sqldev/menu/UtplsqlController.xtend | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend b/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend index e3454749..998b9897 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend @@ -44,7 +44,9 @@ class UtplsqlController implements Controller { val extension URLTools urlTools = new URLTools public static int UTLPLSQL_TEST_CMD_ID = Ide.findCmdID("utplsql.test") + public static int UTLPLSQL_GENERATE_CMD_ID = Ide.findCmdID("utplsql.generate") public static final IdeAction UTLPLSQL_TEST_ACTION = IdeAction.get(UtplsqlController.UTLPLSQL_TEST_CMD_ID) + public static final IdeAction UTLPLSQL_GENERATE_ACTION = IdeAction.get(UtplsqlController.UTLPLSQL_GENERATE_CMD_ID) override handleEvent(IdeAction action, Context context) { if (action.commandId === UtplsqlController.UTLPLSQL_TEST_CMD_ID) { @@ -110,6 +112,28 @@ class UtplsqlController implements Controller { } } return true + } else if (action.commandId === UTLPLSQL_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 parser = new UtplsqlParser(component.text) + action.enabled = parser.getObjectAt(component.caretPosition) !== null + } + } 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 } From cfff1f1f7ebff5a36f036883f67d8cfc1b6eec9c Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sun, 7 Oct 2018 18:24:30 +0200 Subject: [PATCH 04/15] add generator perferences --- .../org/utplsql/sqldev/PreferencePanel.xtend | 34 +++++++++++++++ .../model/preference/PreferenceModel.xtend | 43 +++++++++++++++++++ .../resources/UtplsqlResources.properties | 5 +++ .../resources/UtplsqlResources_de.properties | 5 +++ 4 files changed, 87 insertions(+) diff --git a/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend b/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend index d49d3de5..0f23ea65 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend @@ -16,6 +16,9 @@ package org.utplsql.sqldev import javax.swing.JCheckBox +import javax.swing.JSpinner +import javax.swing.JTextField +import javax.swing.SpinnerNumberModel import oracle.ide.panels.DefaultTraversablePanel import oracle.ide.panels.TraversableContext import oracle.ide.panels.TraversalException @@ -29,6 +32,12 @@ class PreferencePanel extends DefaultTraversablePanel { val JCheckBox clearScreenCheckBox = new JCheckBox val JCheckBox autoExecuteCheckBox = new JCheckBox val JCheckBox checkRunUtplsqlTestCheckBox = new JCheckBox + val JTextField testPackagePrefixTextField = new JTextField + val JTextField testPackageSuffixTextField = new JTextField + val JTextField testUnitPrefixTextField = new JTextField + val JTextField testUnitSuffixTextField = new JTextField + val SpinnerNumberModel numberOfTestsPerUnitModel = new SpinnerNumberModel(1, 1, 10, 1); + val JSpinner numberOfTestsPerUnitSpinner = new JSpinner(numberOfTestsPerUnitModel); new() { layoutControls() @@ -52,6 +61,21 @@ class PreferencePanel extends DefaultTraversablePanel { builder.add( builder.field.label.withText(UtplsqlResources.getString("PREF_CHECK_RUN_UTPLSQL_TEST_LABEL")).component( checkRunUtplsqlTestCheckBox)) + builder.add( + builder.field.label.withText(UtplsqlResources.getString("PREF_TEST_PACKAGE_PREFIX_LABEL")).component( + testPackagePrefixTextField)) + builder.add( + builder.field.label.withText(UtplsqlResources.getString("PREF_TEST_PACKAGE_SUFFIX_LABEL")).component( + testPackageSuffixTextField)) + builder.add( + builder.field.label.withText(UtplsqlResources.getString("PREF_TEST_UNIT_PREFIX_LABEL")).component( + testUnitPrefixTextField)) + builder.add( + builder.field.label.withText(UtplsqlResources.getString("PREF_TEST_UNIT_SUFFIX_LABEL")).component( + testUnitSuffixTextField)) + builder.add( + builder.field.label.withText(UtplsqlResources.getString("PREF_NUMBER_OF_TESTS_PER_UNIT")).component( + numberOfTestsPerUnitSpinner)) builder.addVerticalSpring } @@ -62,6 +86,11 @@ class PreferencePanel extends DefaultTraversablePanel { clearScreenCheckBox.selected = info.clearScreen autoExecuteCheckBox.selected = info.autoExecute checkRunUtplsqlTestCheckBox.selected = info.checkRunUtplsqlTest + testPackagePrefixTextField.text = info.testPackagePrefix + testPackageSuffixTextField.text = info.testPackageSuffix + testUnitPrefixTextField.text = info.testUnitPrefix + testUnitSuffixTextField.text = info.testUnitSuffix + numberOfTestsPerUnitSpinner.value = info.numberOfTestsPerUnit super.onEntry(traversableContext) } @@ -72,6 +101,11 @@ class PreferencePanel extends DefaultTraversablePanel { info.clearScreen = clearScreenCheckBox.selected info.autoExecute = autoExecuteCheckBox.selected info.checkRunUtplsqlTest = checkRunUtplsqlTestCheckBox.selected + info.testPackagePrefix = testPackagePrefixTextField.text + info.testPackageSuffix = testPackageSuffixTextField.text + info.testUnitPrefix = testUnitPrefixTextField.text + info.testUnitSuffix = testUnitSuffixTextField.text + info.numberOfTestsPerUnit = numberOfTestsPerUnitSpinner.value as Integer super.onExit(traversableContext) } 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 index 3a06acd5..67b84ebc 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.xtend @@ -36,6 +36,11 @@ class PreferenceModel extends HashStructureAdapter { 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_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" def isUnsharedWorksheet() { return getHashStructure.getBoolean(PreferenceModel.KEY_UNSHARED_WORKSHEET, true) @@ -77,7 +82,45 @@ class PreferenceModel extends HashStructureAdapter { getHashStructure.putBoolean(PreferenceModel.KEY_CHECK_RUN_UTPLSQL_TEST, autoExecute) } + 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) + } override toString() { new ToStringBuilder(this).addAllFields.toString diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties index 8255709e..cc32930d 100644 --- a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties +++ b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties @@ -13,6 +13,11 @@ PREF_RESET_PACKAGE_LABEL=Reset package before running utPLSQL? PREF_CLEAR_SCREEN_LABEL=Clear script output panel before running utPLSQL? PREF_AUTO_EXECUTE_LABEL=Execute unit test automatically? PREF_CHECK_RUN_UTPLSQL_TEST_LABEL=Check availability of "Run utPLSQL test" menu option? +PREF_TEST_PACKAGE_PREFIX_LABEL=Test package prefix +PREF_TEST_PACKAGE_SUFFIX_LABEL=Test package suffix +PREF_TEST_UNIT_PREFIX_LABEL=Test unit prefix +PREF_TEST_UNIT_SUFFIX_LABEL=Test unit suffix +PREF_NUMBER_OF_TESTS_PER_UNIT=Number of tests to generate per unit MENU_RUN_TEST_LABEL=Run utPLSQL test MENU_RUN_GENERATE_LABEL=Generate utPLSQL test WORKSHEET_TITLE=utPLSQL diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties index 8cfa745a..a0b2fbab 100644 --- a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties +++ b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties @@ -7,6 +7,11 @@ PREF_RESET_PACKAGE_LABEL=Package vor der Ausf PREF_CLEAR_SCREEN_LABEL=Skriptausgabe-Fenster vor der Ausführung von utPLSQL leeren? PREF_AUTO_EXECUTE_LABEL=Unit Test automatisch ausführen? PREF_CHECK_RUN_UTPLSQL_TEST_LABEL=Verfügbarkeit der Menüoption "utPLSQL Test ausführen" prüfen? +PREF_TEST_PACKAGE_PREFIX_LABEL=Test Package Präfix +PREF_TEST_PACKAGE_SUFFIX_LABEL=Test Package Suffix +PREF_TEST_UNIT_PREFIX_LABEL=Test Unit Präfix +PREF_TEST_UNIT_SUFFIX_LABEL=Test Unit Suffix +PREF_NUMBER_OF_TESTS_PER_UNIT=Anzahl zu generierende Tests pro Unit MENU_RUN_TEST_LABEL=utPLSQL Test ausführen MENU_GENERATE_TEST_LABEL=utPLSQL Test generieren WORKSHEET_TITLE=utPLSQL From 337cfc2119852bc08d35dbbf19dc89841a86454a Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Mon, 8 Oct 2018 16:53:31 +0200 Subject: [PATCH 05/15] fix wrong menu label, add label to check availability of Generate utPLSQL test --- sqldev/extension.xml | 2 +- .../org/utplsql/sqldev/resources/UtplsqlResources.properties | 3 ++- .../utplsql/sqldev/resources/UtplsqlResources_de.properties | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sqldev/extension.xml b/sqldev/extension.xml index c27a035e..ec85bea3 100644 --- a/sqldev/extension.xml +++ b/sqldev/extension.xml @@ -98,7 +98,7 @@ - ${MENU_RUN_GENERATE_LABEL} + ${MENU_GENERATE_TEST_LABEL} res:/org/utplsql/sqldev/resources/images/oddgen.png Code-Editor diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties index cc32930d..90323f4a 100644 --- a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties +++ b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties @@ -18,6 +18,7 @@ PREF_TEST_PACKAGE_SUFFIX_LABEL=Test package suffix PREF_TEST_UNIT_PREFIX_LABEL=Test unit prefix PREF_TEST_UNIT_SUFFIX_LABEL=Test unit suffix PREF_NUMBER_OF_TESTS_PER_UNIT=Number of tests to generate per unit +PREF_CHECK_GENERATE_UTPLSQL_TEST_LABEL=Check availability of "Generate utPLSQL test" menu option? MENU_RUN_TEST_LABEL=Run utPLSQL test -MENU_RUN_GENERATE_LABEL=Generate utPLSQL test +MENU_GENERATE_TEST_LABEL=Generate utPLSQL test WORKSHEET_TITLE=utPLSQL diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties index a0b2fbab..3c7e2f17 100644 --- a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties +++ b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties @@ -12,6 +12,7 @@ PREF_TEST_PACKAGE_SUFFIX_LABEL=Test Package Suffix PREF_TEST_UNIT_PREFIX_LABEL=Test Unit Präfix PREF_TEST_UNIT_SUFFIX_LABEL=Test Unit Suffix PREF_NUMBER_OF_TESTS_PER_UNIT=Anzahl zu generierende Tests pro Unit +PREF_CHECK_GENERATE_UTPLSQL_TEST_LABEL=Verfügbarkeit der Menüoption "utPLSQL Test generieren" prüfen? MENU_RUN_TEST_LABEL=utPLSQL Test ausführen MENU_GENERATE_TEST_LABEL=utPLSQL Test generieren WORKSHEET_TITLE=utPLSQL From 4568897150aa0613fee5c2a0bbe4752d98d40ddc Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Mon, 8 Oct 2018 16:54:46 +0200 Subject: [PATCH 06/15] add checkGenerateUtplsqlTest to model --- .../sqldev/model/preference/PreferenceModel.xtend | 13 +++++++++++-- .../utplsql/sqldev/tests/PreferenceModelTest.xtend | 5 +++++ 2 files changed, 16 insertions(+), 2 deletions(-) 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 index 67b84ebc..569278e6 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.xtend @@ -41,6 +41,7 @@ class PreferenceModel extends HashStructureAdapter { 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" def isUnsharedWorksheet() { return getHashStructure.getBoolean(PreferenceModel.KEY_UNSHARED_WORKSHEET, true) @@ -78,8 +79,8 @@ class PreferenceModel extends HashStructureAdapter { return getHashStructure.getBoolean(PreferenceModel.KEY_CHECK_RUN_UTPLSQL_TEST, false) } - def setCheckRunUtplsqlTest(boolean autoExecute) { - getHashStructure.putBoolean(PreferenceModel.KEY_CHECK_RUN_UTPLSQL_TEST, autoExecute) + def setCheckRunUtplsqlTest(boolean checkRunUtplsqlTest) { + getHashStructure.putBoolean(PreferenceModel.KEY_CHECK_RUN_UTPLSQL_TEST, checkRunUtplsqlTest) } def getTestPackagePrefix() { @@ -122,6 +123,14 @@ class PreferenceModel extends HashStructureAdapter { 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) + } + override toString() { new ToStringBuilder(this).addAllFields.toString } diff --git a/sqldev/src/test/java/org/utplsql/sqldev/tests/PreferenceModelTest.xtend b/sqldev/src/test/java/org/utplsql/sqldev/tests/PreferenceModelTest.xtend index 5dafb92c..3580dd60 100644 --- a/sqldev/src/test/java/org/utplsql/sqldev/tests/PreferenceModelTest.xtend +++ b/sqldev/src/test/java/org/utplsql/sqldev/tests/PreferenceModelTest.xtend @@ -29,5 +29,10 @@ class PreferenceModelTest { Assert.assertFalse(model.clearScreen) Assert.assertTrue(model.autoExecute) Assert.assertFalse(model.checkRunUtplsqlTest) + Assert.assertEquals("test_", model.testPackagePrefix) + Assert.assertEquals("", model.testPackageSuffix) + Assert.assertEquals("", model.testUnitPrefix) + Assert.assertEquals("", model.testUnitSuffix) + Assert.assertFalse(model.checkGenerateUtplsqlTest) } } From 43b0b31b0c56d747f1bd3177b8b530b5474cfdd0 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Mon, 8 Oct 2018 16:55:48 +0200 Subject: [PATCH 07/15] add checkGenerateUtplsqlTest, group preferences --- .../org/utplsql/sqldev/PreferencePanel.xtend | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend b/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend index 0f23ea65..ac3ac1d6 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend @@ -15,7 +15,9 @@ */ package org.utplsql.sqldev +import javax.swing.BorderFactory import javax.swing.JCheckBox +import javax.swing.JPanel import javax.swing.JSpinner import javax.swing.JTextField import javax.swing.SpinnerNumberModel @@ -27,55 +29,69 @@ import org.utplsql.sqldev.model.preference.PreferenceModel import org.utplsql.sqldev.resources.UtplsqlResources class PreferencePanel extends DefaultTraversablePanel { + val JPanel runTestPanel = new JPanel(); val JCheckBox unsharedWorksheetCheckBox = new JCheckBox val JCheckBox resetPackageCheckBox = new JCheckBox val JCheckBox clearScreenCheckBox = new JCheckBox val JCheckBox autoExecuteCheckBox = new JCheckBox val JCheckBox checkRunUtplsqlTestCheckBox = new JCheckBox + val JPanel generateTestPanel = new JPanel(); val JTextField testPackagePrefixTextField = new JTextField val JTextField testPackageSuffixTextField = new JTextField val JTextField testUnitPrefixTextField = new JTextField val JTextField testUnitSuffixTextField = new JTextField val SpinnerNumberModel numberOfTestsPerUnitModel = new SpinnerNumberModel(1, 1, 10, 1); val JSpinner numberOfTestsPerUnitSpinner = new JSpinner(numberOfTestsPerUnitModel); + val JCheckBox checkGenerateUtplsqlTestCheckBox = new JCheckBox new() { layoutControls() } def private layoutControls() { - val FieldLayoutBuilder builder = new FieldLayoutBuilder(this) - builder.alignLabelsLeft = true - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_UNSHARED_WORKSHEET_LABEL")).component( + runTestPanel.border = BorderFactory.createTitledBorder(UtplsqlResources.getString("MENU_RUN_TEST_LABEL")) + val FieldLayoutBuilder b1 = new FieldLayoutBuilder(runTestPanel) + b1.alignLabelsLeft = true + b1.add( + b1.field.label.withText(UtplsqlResources.getString("PREF_UNSHARED_WORKSHEET_LABEL")).component( unsharedWorksheetCheckBox)) - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_RESET_PACKAGE_LABEL")).component( + b1.add( + b1.field.label.withText(UtplsqlResources.getString("PREF_RESET_PACKAGE_LABEL")).component( resetPackageCheckBox)) - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_CLEAR_SCREEN_LABEL")).component( + b1.add( + b1.field.label.withText(UtplsqlResources.getString("PREF_CLEAR_SCREEN_LABEL")).component( clearScreenCheckBox)) - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_AUTO_EXECUTE_LABEL")).component( + b1.add( + b1.field.label.withText(UtplsqlResources.getString("PREF_AUTO_EXECUTE_LABEL")).component( autoExecuteCheckBox)) - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_CHECK_RUN_UTPLSQL_TEST_LABEL")).component( + b1.add( + b1.field.label.withText(UtplsqlResources.getString("PREF_CHECK_RUN_UTPLSQL_TEST_LABEL")).component( checkRunUtplsqlTestCheckBox)) - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_TEST_PACKAGE_PREFIX_LABEL")).component( + generateTestPanel.border = BorderFactory.createTitledBorder(UtplsqlResources.getString("MENU_GENERATE_TEST_LABEL")) + val FieldLayoutBuilder b2 = new FieldLayoutBuilder(generateTestPanel) + b2.alignLabelsLeft = true + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_TEST_PACKAGE_PREFIX_LABEL")).component( testPackagePrefixTextField)) - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_TEST_PACKAGE_SUFFIX_LABEL")).component( + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_TEST_PACKAGE_SUFFIX_LABEL")).component( testPackageSuffixTextField)) - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_TEST_UNIT_PREFIX_LABEL")).component( + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_TEST_UNIT_PREFIX_LABEL")).component( testUnitPrefixTextField)) - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_TEST_UNIT_SUFFIX_LABEL")).component( + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_TEST_UNIT_SUFFIX_LABEL")).component( testUnitSuffixTextField)) - builder.add( - builder.field.label.withText(UtplsqlResources.getString("PREF_NUMBER_OF_TESTS_PER_UNIT")).component( + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_NUMBER_OF_TESTS_PER_UNIT")).component( numberOfTestsPerUnitSpinner)) + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_CHECK_GENERATE_UTPLSQL_TEST_LABEL")).component( + checkGenerateUtplsqlTestCheckBox)) + val FieldLayoutBuilder builder = new FieldLayoutBuilder(this) + builder.alignLabelsLeft = true + builder.addVerticalField("", runTestPanel) + builder.addVerticalField("", generateTestPanel) builder.addVerticalSpring } @@ -91,6 +107,7 @@ class PreferencePanel extends DefaultTraversablePanel { testUnitPrefixTextField.text = info.testUnitPrefix testUnitSuffixTextField.text = info.testUnitSuffix numberOfTestsPerUnitSpinner.value = info.numberOfTestsPerUnit + checkGenerateUtplsqlTestCheckBox.selected = info.checkGenerateUtplsqlTest super.onEntry(traversableContext) } @@ -106,6 +123,7 @@ class PreferencePanel extends DefaultTraversablePanel { info.testUnitPrefix = testUnitPrefixTextField.text info.testUnitSuffix = testUnitSuffixTextField.text info.numberOfTestsPerUnit = numberOfTestsPerUnitSpinner.value as Integer + info.checkGenerateUtplsqlTest = checkGenerateUtplsqlTestCheckBox.selected super.onExit(traversableContext) } From 5549f3a10860626655f496715b51061c8e74807f Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Mon, 8 Oct 2018 16:56:38 +0200 Subject: [PATCH 08/15] check availability of generate menu option based on preferences --- .../java/org/utplsql/sqldev/menu/UtplsqlController.xtend | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend b/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend index 998b9897..dd2d3e31 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend @@ -119,8 +119,13 @@ class UtplsqlController implements Controller { if (view instanceof Editor) { val component = view.defaultFocusComponent if (component instanceof JEditorPane) { - val parser = new UtplsqlParser(component.text) - action.enabled = parser.getObjectAt(component.caretPosition) !== null + 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 From fecb834c8c7267c0d33dd78f9c09c6953ff264da Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Tue, 9 Oct 2018 16:20:38 +0200 Subject: [PATCH 09/15] add a directory choose, to be used in the preferences --- .../org/utplsql/sqldev/DirectoryChooser.xtend | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 sqldev/src/main/java/org/utplsql/sqldev/DirectoryChooser.xtend diff --git a/sqldev/src/main/java/org/utplsql/sqldev/DirectoryChooser.xtend b/sqldev/src/main/java/org/utplsql/sqldev/DirectoryChooser.xtend new file mode 100644 index 00000000..2c47302b --- /dev/null +++ b/sqldev/src/main/java/org/utplsql/sqldev/DirectoryChooser.xtend @@ -0,0 +1,56 @@ +/* + * 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 + +import java.io.File +import java.util.logging.Logger +import javax.swing.JComboBox +import javax.swing.JFileChooser +import javax.swing.JFrame +import javax.swing.JTextField + +class DirectoryChooser { + val static Logger logger = Logger.getLogger(DirectoryChooser.name) + + def static choose (JFrame parentFrame, String title, String initialDirectory) { + logger.finest('''parantFrame: «parentFrame»''') + var String ret = null + val chooser = new JFileChooser() + chooser.currentDirectory = new File(initialDirectory) + chooser.dialogTitle = title + chooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY + chooser.acceptAllFileFilterUsed = false + if (chooser.showOpenDialog(parentFrame) == JFileChooser.APPROVE_OPTION) { + ret = chooser.selectedFile.absolutePath + } + return ret + } + + def static void choose (JFrame parentFrame, String title, JTextField textField) { + val dir = choose(parentFrame, title, textField.text) + if (dir !== null) { + textField.text = dir + } + } + + def static void choose (JFrame parentFrame, String title, JComboBox comboBox) { + val dir = choose(parentFrame, title, comboBox.editor.item as String); + if (dir !== null) { + comboBox.editor.item = dir + } + } + +} From 9c174676b542fff95ff95f2d2738d56dd9f38e84 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Tue, 9 Oct 2018 16:23:49 +0200 Subject: [PATCH 10/15] extended preferences for #10 and #11 --- .../org/utplsql/sqldev/PreferencePanel.xtend | 68 ++++++++++++++++++- .../resources/UtplsqlResources.properties | 9 ++- .../resources/UtplsqlResources_de.properties | 9 ++- .../sqldev/tests/PreferenceModelTest.xtend | 7 ++ 4 files changed, 90 insertions(+), 3 deletions(-) diff --git a/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend b/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend index ac3ac1d6..a235e424 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/PreferencePanel.xtend @@ -27,6 +27,9 @@ import oracle.ide.panels.TraversalException import oracle.javatools.ui.layout.FieldLayoutBuilder import org.utplsql.sqldev.model.preference.PreferenceModel import org.utplsql.sqldev.resources.UtplsqlResources +import javax.swing.JButton +import java.awt.event.ActionEvent +import java.awt.event.ActionListener class PreferencePanel extends DefaultTraversablePanel { val JPanel runTestPanel = new JPanel(); @@ -43,12 +46,23 @@ class PreferencePanel extends DefaultTraversablePanel { val SpinnerNumberModel numberOfTestsPerUnitModel = new SpinnerNumberModel(1, 1, 10, 1); val JSpinner numberOfTestsPerUnitSpinner = new JSpinner(numberOfTestsPerUnitModel); val JCheckBox checkGenerateUtplsqlTestCheckBox = new JCheckBox + val JCheckBox generateCommentsCheckBox = new JCheckBox + val JCheckBox disableTestsCheckBox = new JCheckBox + val JTextField suitePathTextField = new JTextField + val SpinnerNumberModel indentSpacesModel = new SpinnerNumberModel(1, 1, 8, 1); + val JSpinner indentSpacesSpinner = new JSpinner(indentSpacesModel); + val JPanel oddgenPanel = new JPanel(); + val JTextField rootFolderInOddgenViewTextField = new JTextField + val JCheckBox generateFilesCheckBox = new JCheckBox + val JTextField outputDirectoryTextField = new JTextField + val JButton outputDirectoryBrowse = new JButton(); new() { layoutControls() } def private layoutControls() { + // run test group runTestPanel.border = BorderFactory.createTitledBorder(UtplsqlResources.getString("MENU_RUN_TEST_LABEL")) val FieldLayoutBuilder b1 = new FieldLayoutBuilder(runTestPanel) b1.alignLabelsLeft = true @@ -67,6 +81,7 @@ class PreferencePanel extends DefaultTraversablePanel { b1.add( b1.field.label.withText(UtplsqlResources.getString("PREF_CHECK_RUN_UTPLSQL_TEST_LABEL")).component( checkRunUtplsqlTestCheckBox)) + // generate test group generateTestPanel.border = BorderFactory.createTitledBorder(UtplsqlResources.getString("MENU_GENERATE_TEST_LABEL")) val FieldLayoutBuilder b2 = new FieldLayoutBuilder(generateTestPanel) b2.alignLabelsLeft = true @@ -83,16 +98,53 @@ class PreferencePanel extends DefaultTraversablePanel { b2.field.label.withText(UtplsqlResources.getString("PREF_TEST_UNIT_SUFFIX_LABEL")).component( testUnitSuffixTextField)) b2.add( - b2.field.label.withText(UtplsqlResources.getString("PREF_NUMBER_OF_TESTS_PER_UNIT")).component( + b2.field.label.withText(UtplsqlResources.getString("PREF_NUMBER_OF_TESTS_PER_UNIT_LABEL")).component( numberOfTestsPerUnitSpinner)) + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_GENERATE_COMMENTS_LABEL")).component( + generateCommentsCheckBox)) + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_DISABLE_TESTS_LABEL")).component( + disableTestsCheckBox)) + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_SUITE_PATH_LABEL")).component( + suitePathTextField)) + b2.add( + b2.field.label.withText(UtplsqlResources.getString("PREF_INDENT_SPACES_LABEL")).component( + indentSpacesSpinner)) b2.add( b2.field.label.withText(UtplsqlResources.getString("PREF_CHECK_GENERATE_UTPLSQL_TEST_LABEL")).component( checkGenerateUtplsqlTestCheckBox)) + // oddgen group + oddgenPanel.border = BorderFactory.createTitledBorder("oddgen") + val FieldLayoutBuilder b3 = new FieldLayoutBuilder(oddgenPanel) + b3.alignLabelsLeft = true + b3.stretchComponentsWithNoButton = true + b3.add( + b3.field.label.withText(UtplsqlResources.getString("PREF_ROOT_FOLDER_IN_ODDGEN_VIEW_LABEL")).component( + rootFolderInOddgenViewTextField)) + b3.add( + b3.field.label.withText(UtplsqlResources.getString("PREF_GENERATE_FILES_LABEL")).component( + generateFilesCheckBox)) + b3.add( + b3.field.label.withText(UtplsqlResources.getString("PREF_OUTPUT_DIRECTORY_LABEL")).component( + outputDirectoryTextField).button(outputDirectoryBrowse).withText("Bro&wse")) + + // putting everything together val FieldLayoutBuilder builder = new FieldLayoutBuilder(this) builder.alignLabelsLeft = true builder.addVerticalField("", runTestPanel) builder.addVerticalField("", generateTestPanel) + builder.addVerticalField("", oddgenPanel) builder.addVerticalSpring + + // register action listener for directory chooser + outputDirectoryBrowse.addActionListener(new ActionListener() { + override actionPerformed(ActionEvent event) { + DirectoryChooser.choose(null, UtplsqlResources.getString("PREF_OUTPUT_DIRECTORY_LABEL"), + outputDirectoryTextField) + } + }) } override onEntry(TraversableContext traversableContext) { @@ -108,6 +160,13 @@ class PreferencePanel extends DefaultTraversablePanel { testUnitSuffixTextField.text = info.testUnitSuffix numberOfTestsPerUnitSpinner.value = info.numberOfTestsPerUnit checkGenerateUtplsqlTestCheckBox.selected = info.checkGenerateUtplsqlTest + generateCommentsCheckBox.selected = info.generateComments + disableTestsCheckBox.selected = info.disableTests + suitePathTextField.text = info.suitePath + indentSpacesSpinner.value = info.indentSpaces + rootFolderInOddgenViewTextField.text = info.rootFolderInOddgenView + generateFilesCheckBox.selected = info.generateFiles + outputDirectoryTextField.text = info.outputDirectory super.onEntry(traversableContext) } @@ -124,6 +183,13 @@ class PreferencePanel extends DefaultTraversablePanel { info.testUnitSuffix = testUnitSuffixTextField.text info.numberOfTestsPerUnit = numberOfTestsPerUnitSpinner.value as Integer info.checkGenerateUtplsqlTest = checkGenerateUtplsqlTestCheckBox.selected + info.generateComments = generateCommentsCheckBox.selected + info.disableTests = disableTestsCheckBox.selected + info.suitePath = suitePathTextField.text + info.indentSpaces = indentSpacesSpinner.value as Integer + info.rootFolderInOddgenView = rootFolderInOddgenViewTextField.text + info.generateFiles = generateFilesCheckBox.selected + info.outputDirectory = outputDirectoryTextField.text super.onExit(traversableContext) } diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties index 90323f4a..c03f33e5 100644 --- a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties +++ b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties @@ -17,8 +17,15 @@ PREF_TEST_PACKAGE_PREFIX_LABEL=Test package prefix PREF_TEST_PACKAGE_SUFFIX_LABEL=Test package suffix PREF_TEST_UNIT_PREFIX_LABEL=Test unit prefix PREF_TEST_UNIT_SUFFIX_LABEL=Test unit suffix -PREF_NUMBER_OF_TESTS_PER_UNIT=Number of tests to generate per unit +PREF_NUMBER_OF_TESTS_PER_UNIT_LABEL=Number of tests to generate per unit +PREF_GENERATE_COMMENTS_LABEL=Generate comments? +PREF_DISABLE_TESTS_LABEL=Disable tests? +PREF_SUITE_PATH_LABEL=Suite Path +PREF_INDENT_SPACES_LABEL=Indent Spaces PREF_CHECK_GENERATE_UTPLSQL_TEST_LABEL=Check availability of "Generate utPLSQL test" menu option? +PREF_ROOT_FOLDER_IN_ODDGEN_VIEW_LABEL=Root folder in Generators view +PREF_GENERATE_FILES_LABEL=Generate files? +PREF_OUTPUT_DIRECTORY_LABEL=Output directory MENU_RUN_TEST_LABEL=Run utPLSQL test MENU_GENERATE_TEST_LABEL=Generate utPLSQL test WORKSHEET_TITLE=utPLSQL diff --git a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties index 3c7e2f17..8f7e33e4 100644 --- a/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties +++ b/sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties @@ -11,8 +11,15 @@ PREF_TEST_PACKAGE_PREFIX_LABEL=Test Package Pr PREF_TEST_PACKAGE_SUFFIX_LABEL=Test Package Suffix PREF_TEST_UNIT_PREFIX_LABEL=Test Unit Präfix PREF_TEST_UNIT_SUFFIX_LABEL=Test Unit Suffix -PREF_NUMBER_OF_TESTS_PER_UNIT=Anzahl zu generierende Tests pro Unit +PREF_NUMBER_OF_TESTS_PER_UNIT_LABEL=Anzahl zu generierende Tests pro Unit +PREF_GENERATE_COMMENTS_LABEL=Kommentare generieren? +PREF_DISABLE_TESTS_LABEL=Tests deaktivieren? +PREF_SUITE_PATH_LABEL=Suite Path +PREF_INDENT_SPACES_LABEL=Einrückungsleerzeichen PREF_CHECK_GENERATE_UTPLSQL_TEST_LABEL=Verfügbarkeit der Menüoption "utPLSQL Test generieren" prüfen? +PREF_ROOT_FOLDER_IN_ODDGEN_VIEW_LABEL=Hauptverzeichnis in Generatoren Ansicht +PREF_GENERATE_FILES_LABEL=Dateien generieren? +PREF_OUTPUT_DIRECTORY_LABEL=Ausgabeverzeichnis MENU_RUN_TEST_LABEL=utPLSQL Test ausführen MENU_GENERATE_TEST_LABEL=utPLSQL Test generieren WORKSHEET_TITLE=utPLSQL diff --git a/sqldev/src/test/java/org/utplsql/sqldev/tests/PreferenceModelTest.xtend b/sqldev/src/test/java/org/utplsql/sqldev/tests/PreferenceModelTest.xtend index 3580dd60..206d690b 100644 --- a/sqldev/src/test/java/org/utplsql/sqldev/tests/PreferenceModelTest.xtend +++ b/sqldev/src/test/java/org/utplsql/sqldev/tests/PreferenceModelTest.xtend @@ -34,5 +34,12 @@ class PreferenceModelTest { Assert.assertEquals("", model.testUnitPrefix) Assert.assertEquals("", model.testUnitSuffix) Assert.assertFalse(model.checkGenerateUtplsqlTest) + Assert.assertTrue(model.generateComments) + Assert.assertFalse(model.disableTests) + Assert.assertEquals("alltests", model.suitePath) + Assert.assertEquals(3, model.indentSpaces) + Assert.assertTrue(model.generateFiles) + Assert.assertEquals(PreferenceModel.DEFAULT_OUTPUT_DIRECTORY, model.outputDirectory) + Assert.assertEquals("utPLSQL", model.rootFolderInOddgenView) } } From a8aabea94a28b797b16818e6914560e048b9c532 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Tue, 9 Oct 2018 16:26:21 +0200 Subject: [PATCH 11/15] added oddgen dependency (provided) to be used only via generators implementing the OddgenGenerator2 interface. Ensure that installation of oddgen is and stays optional --- sqldev/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sqldev/pom.xml b/sqldev/pom.xml index 6bbd1634..26c8f61d 100644 --- a/sqldev/pom.xml +++ b/sqldev/pom.xml @@ -157,6 +157,12 @@ spring-jdbc 5.1.0.RELEASE + + org.oddgen + org.oddgen.sqldev + 0.3.0 + provided + junit junit From 8f7f6262280111faa13e805b2de3c05091a181d9 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Tue, 9 Oct 2018 16:34:12 +0200 Subject: [PATCH 12/15] added DAO for units (subprograms) and testables (objects for unit tests) units to be used for #10 - to generate units for a single object (package, type, procedure, function) testables to be used for #11 - to populate nodes in oddgen view --- .../org/utplsql/sqldev/dal/UtplsqlDao.xtend | 86 ++++++++++++++ .../org/utplsql/sqldev/tests/DalTest.xtend | 105 +++++++++++++++++- 2 files changed, 189 insertions(+), 2 deletions(-) diff --git a/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.xtend b/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.xtend index 3ba5fedf..be00bcf3 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.xtend @@ -17,6 +17,7 @@ import java.sql.Connection import java.util.List +import org.oddgen.sqldev.generators.model.Node import org.springframework.dao.DataAccessException import org.springframework.dao.EmptyResultDataAccessException import org.springframework.jdbc.core.BeanPropertyRowMapper @@ -175,5 +176,90 @@ class UtplsqlDao { 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") { + 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 jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, true)) + val nodes = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Node), #[objectType]) + return nodes + } } \ No newline at end of file diff --git a/sqldev/src/test/java/org/utplsql/sqldev/tests/DalTest.xtend b/sqldev/src/test/java/org/utplsql/sqldev/tests/DalTest.xtend index 89c5bbee..eadcd989 100644 --- a/sqldev/src/test/java/org/utplsql/sqldev/tests/DalTest.xtend +++ b/sqldev/src/test/java/org/utplsql/sqldev/tests/DalTest.xtend @@ -35,6 +35,31 @@ class DalTest extends AbstractJdbcTest { } catch (BadSqlGrammarException e) { // ignore } + try { + jdbcTemplate.execute("DROP PACKAGE junit_no_test_pkg") + } catch (BadSqlGrammarException e) { + // ignore + } + try { + jdbcTemplate.execute("DROP TYPE junit_tab1_ot") + } catch (BadSqlGrammarException e) { + // ignore + } + try { + jdbcTemplate.execute("DROP TYPE junit_tab2_ot") + } catch (BadSqlGrammarException e) { + // ignore + } + try { + jdbcTemplate.execute("DROP FUNCTION junit_f") + } catch (BadSqlGrammarException e) { + // ignore + } + try { + jdbcTemplate.execute("DROP PROCEDURE junit_p") + } catch (BadSqlGrammarException e) { + // ignore + } } @Test @@ -63,7 +88,6 @@ class DalTest extends AbstractJdbcTest { @Test def void containsUtplsqlTest() { val dao = new UtplsqlDao(dataSource.connection) - Assert.assertFalse(dao.containsUtplsqlTest("scott")) jdbcTemplate.execute(''' CREATE OR REPLACE PACKAGE junit_utplsql_test_pkg IS -- %suite @@ -104,7 +128,6 @@ class DalTest extends AbstractJdbcTest { @Test def void annotations() { val dao = new UtplsqlDao(dataSource.connection) - Assert.assertEquals(new ArrayList, dao.annotations("scott", "junit_utplsql_test_pkg")) jdbcTemplate.execute(''' CREATE OR REPLACE PACKAGE junit_utplsql_test_pkg IS -- %suite @@ -143,4 +166,82 @@ class DalTest extends AbstractJdbcTest { Assert.assertEquals(expected.toString, effective.toString) jdbcTemplate.execute("DROP PACKAGE junit_utplsql_test_pkg") } + + @Test + def void testablesPackages() { + val dao = new UtplsqlDao(dataSource.connection) + jdbcTemplate.execute(''' + CREATE OR REPLACE PACKAGE junit_utplsql_test_pkg IS + -- %suite + + -- %test + PROCEDURE t1; + + -- %Test + PROCEDURE t2; + + PROCEDURE t3; + END junit_utplsql_test_pkg; + ''') + jdbcTemplate.execute(''' + CREATE OR REPLACE PACKAGE junit_no_test_pkg IS + PROCEDURE p1; + + PROCEDURE p2; + END junit_no_test_pkg; + ''') + val effective = dao.testables('PACKAGE') + Assert.assertEquals(1, effective.size) + Assert.assertEquals("PACKAGE.JUNIT_NO_TEST_PKG", effective.get(0).id) + } + + @Test + def void testablesTypes() { + val dao = new UtplsqlDao(dataSource.connection) + jdbcTemplate.execute(''' + CREATE OR REPLACE TYPE junit_tab1_ot IS object (a integer, b integer); + ''') + jdbcTemplate.execute(''' + CREATE OR REPLACE TYPE junit_tab2_ot IS object ( + a integer, + b integer, + member procedure c( + self in out nocopy junit_tab2_ot, + p integer + ) + ); + ''') + val effective = dao.testables('TYPE') + Assert.assertEquals(1, effective.size) + Assert.assertEquals("TYPE.JUNIT_TAB2_OT", effective.get(0).id) + } + + @Test + def void testablesFunctions() { + val dao = new UtplsqlDao(dataSource.connection) + jdbcTemplate.execute(''' + CREATE OR REPLACE FUNCTION junit_f RETURN INTEGER IS + BEGIN + RETURN 1; + END; + ''') + val effective = dao.testables('FUNCTION') + Assert.assertEquals(1, effective.size) + Assert.assertEquals("FUNCTION.JUNIT_F", effective.get(0).id) + } + + @Test + def void testablesProcedures() { + val dao = new UtplsqlDao(dataSource.connection) + jdbcTemplate.execute(''' + CREATE OR REPLACE PROCEDURE junit_p RETURN INTEGER IS + BEGIN + NULL; + END; + ''') + val effective = dao.testables('PROCEDURE') + Assert.assertEquals(1, effective.size) + Assert.assertEquals("PROCEDURE.JUNIT_P", effective.get(0).id) + } + } \ No newline at end of file From 33abdf8ecf2d46daf52a343b8670bcb22faec41d Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Tue, 9 Oct 2018 16:35:45 +0200 Subject: [PATCH 13/15] extended preferences for #10 and #11 --- .../model/preference/PreferenceModel.xtend | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) 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 index 569278e6..db7d71f4 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/model/preference/PreferenceModel.xtend @@ -15,12 +15,14 @@ */ 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) { @@ -42,7 +44,14 @@ class PreferenceModel extends HashStructureAdapter { 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_ROOT_FOLDER_IN_ODDGEN_VIEW = "rootFolderInOddgenView" + def isUnsharedWorksheet() { return getHashStructure.getBoolean(PreferenceModel.KEY_UNSHARED_WORKSHEET, true) } @@ -131,6 +140,64 @@ class PreferenceModel extends HashStructureAdapter { 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 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 } From aa909092a0abae10bda99c75adc85976a2c008d2 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Tue, 9 Oct 2018 16:38:15 +0200 Subject: [PATCH 14/15] closes #10 - Generate utPLSQL test for an object package, type, function, procedure in navigator tree and in PL/SQL editor (when parser detects such an object) --- .../org/utplsql/sqldev/UtplsqlWorksheet.xtend | 8 ++ .../sqldev/menu/UtplsqlController.xtend | 79 +++++++++++ .../utplsql/sqldev/oddgen/TestTemplate.xtend | 130 ++++++++++++++++++ .../sqldev/oddgen/model/GenContext.xtend | 38 +++++ 4 files changed, 255 insertions(+) create mode 100644 sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestTemplate.xtend create mode 100644 sqldev/src/main/java/org/utplsql/sqldev/oddgen/model/GenContext.xtend diff --git a/sqldev/src/main/java/org/utplsql/sqldev/UtplsqlWorksheet.xtend b/sqldev/src/main/java/org/utplsql/sqldev/UtplsqlWorksheet.xtend index 59cdf2dd..44e60e90 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/UtplsqlWorksheet.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/UtplsqlWorksheet.xtend @@ -117,4 +117,12 @@ class UtplsqlWorksheet { thread.start } + def static void openWithCode(String code, String connectionName) { + val worksheet = OpenWorksheetWizard.openNewTempWorksheet(connectionName, code) as Worksheet + if (connectionName === null) { + worksheet.comboConnection = null + } + WorksheetUtil.setWorksheetTabName(worksheet.context.node.URL, UtplsqlResources.getString("WORKSHEET_TITLE")) + } + } diff --git a/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend b/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend index dd2d3e31..b5d683e2 100644 --- a/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend +++ b/sqldev/src/main/java/org/utplsql/sqldev/menu/UtplsqlController.xtend @@ -37,6 +37,8 @@ import org.utplsql.sqldev.UtplsqlWorksheet import org.utplsql.sqldev.dal.UtplsqlDao import org.utplsql.sqldev.model.URLTools import org.utplsql.sqldev.model.preference.PreferenceModel +import org.utplsql.sqldev.oddgen.TestTemplate +import org.utplsql.sqldev.oddgen.model.GenContext import org.utplsql.sqldev.parser.UtplsqlParser class UtplsqlController implements Controller { @@ -52,6 +54,9 @@ class UtplsqlController implements Controller { if (action.commandId === UtplsqlController.UTLPLSQL_TEST_CMD_ID) { runTest(context) return true + } else if (action.commandId === UtplsqlController.UTLPLSQL_GENERATE_CMD_ID) { + generateTest(context) + return true } return false } @@ -188,6 +193,36 @@ class UtplsqlController implements Controller { logger.fine('''url: «url»''') return url } + + private def void populateGenContext(GenContext genContext, PreferenceModel preferences) { + genContext.generateFiles = preferences.generateFiles + genContext.outputDirectory = preferences.outputDirectory + 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 @@ -223,4 +258,48 @@ class UtplsqlController implements Controller { } } } + + 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 + UtplsqlWorksheet.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 + UtplsqlWorksheet.openWithCode(code, connectionName) + } + } + } } diff --git a/sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestTemplate.xtend b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestTemplate.xtend new file mode 100644 index 00000000..11d43564 --- /dev/null +++ b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestTemplate.xtend @@ -0,0 +1,130 @@ +/* + * 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.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.util.List +import org.utplsql.sqldev.dal.UtplsqlDao +import org.utplsql.sqldev.oddgen.model.GenContext + +class TestTemplate { + var GenContext context + var UtplsqlDao dao + var List units + var dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + var today = dateTimeFormatter.format(LocalDateTime.now()) + + new(GenContext context) { + this.context = context + dao = new UtplsqlDao(context.conn) + units = dao.units(context.objectType, context.objectName) + } + + def replaceTabsWithSpaces(CharSequence input) { + val spaces = String.format("%1$"+context.indentSpaces+"s", "") + return input.toString.replace("\t", spaces) + } + + def generateSpec() { + val ret = ''' + «val objectName = context.objectName.toLowerCase» + «val packageName = '''«context.testPackagePrefix»«objectName»«context.testPackageSuffix»'''» + CREATE OR REPLACE PACKAGE «packageName» IS + + «IF context.generateComments» + /* generated by utPLSQL for SQL Developer on «today» */ + + «ENDIF» + --%suite(«packageName») + «IF !context.suitePath.empty» + --%suitepath(«context.suitePath») + «ENDIF» + + «FOR u : units» + «val unit = u.toLowerCase» + «IF context.numberOfTestsPerUnit > 1 && (context.objectType == "PACKAGE" || context.objectType == "TYPE")» + --%context(«unit») + + «ENDIF» + «FOR i : 1 .. context.numberOfTestsPerUnit» + --%test + «IF context.disableTests» + --%disabled + «ENDIF» + PROCEDURE «context.testUnitPrefix»«unit»«context.testUnitSuffix»«IF context.numberOfTestsPerUnit > 1»«i»«ENDIF»; + + «ENDFOR» + «IF context.numberOfTestsPerUnit > 1 && (context.objectType == "PACKAGE" || context.objectType == "TYPE")» + --%endcontext + + «ENDIF» + «ENDFOR» + END «packageName»; + / + ''' + return ret.replaceTabsWithSpaces + } + + def generateBody() { + val ret = ''' + «val objectName = context.objectName.toLowerCase» + CREATE OR REPLACE PACKAGE BODY «context.testPackagePrefix»«objectName»«context.testPackageSuffix» IS + + «IF context.generateComments» + /* generated by utPLSQL for SQL Developer on «today» */ + + «ENDIF» + «FOR u : units» + «val unit = u.toLowerCase» + «FOR i : 1 .. context.numberOfTestsPerUnit» + «val procedureName = '''«context.testUnitPrefix»«unit»«context.testUnitSuffix»«IF context.numberOfTestsPerUnit > 1»«i»«ENDIF»'''» + «IF context.generateComments» + -- + -- test «unit»«IF context.numberOfTestsPerUnit > 0» case «i»: ...«ENDIF» + -- + «ENDIF» + PROCEDURE «procedureName» IS + l_actual INTEGER := 0; + l_expected INTEGER := 1; + BEGIN + «IF context.generateComments» + -- populate actual + -- «objectName».«unit»; + + -- populate expected + -- ... + + -- assert + «ENDIF» + ut.expect(l_actual).to_equal(l_expected); + END «procedureName»; + + «ENDFOR» + «ENDFOR» + + END «context.testPackagePrefix»«objectName»«context.testPackageSuffix»; + / + ''' + return ret.replaceTabsWithSpaces + } + + def generate() ''' + «generateSpec» + + «generateBody» + ''' +} \ No newline at end of file diff --git a/sqldev/src/main/java/org/utplsql/sqldev/oddgen/model/GenContext.xtend b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/model/GenContext.xtend new file mode 100644 index 00000000..d3897f6a --- /dev/null +++ b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/model/GenContext.xtend @@ -0,0 +1,38 @@ +/* + * 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.model + +import java.sql.Connection +import org.eclipse.xtend.lib.annotations.Accessors +import org.utplsql.sqldev.model.AbstractModel + +@Accessors +class GenContext extends AbstractModel { + Connection conn + String objectType + String objectName + boolean generateFiles + String outputDirectory + String testPackagePrefix + String testPackageSuffix + String testUnitPrefix + String testUnitSuffix + int numberOfTestsPerUnit + boolean generateComments + boolean disableTests + String suitePath + int indentSpaces +} From ed2077ab16307ba146232079cad703395843d964 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Tue, 9 Oct 2018 16:40:55 +0200 Subject: [PATCH 15/15] closes #11 - generate utPLSQL unit tests via oddgen all into single file (worksheet) or each package specification and package body in a dedicated file, including a install script --- .../utplsql/sqldev/oddgen/TestGenerator.xtend | 262 ++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestGenerator.xtend diff --git a/sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestGenerator.xtend b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestGenerator.xtend new file mode 100644 index 00000000..83d389f6 --- /dev/null +++ b/sqldev/src/main/java/org/utplsql/sqldev/oddgen/TestGenerator.xtend @@ -0,0 +1,262 @@ +/* + * 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.HashMap +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.oddgen.sqldev.generators.model.NodeTools +import org.oddgen.sqldev.plugin.templates.TemplateTools +import org.utplsql.sqldev.dal.UtplsqlDao +import org.utplsql.sqldev.model.preference.PreferenceModel +import org.utplsql.sqldev.resources.UtplsqlResources +import org.utplsql.sqldev.oddgen.model.GenContext + +class TestGenerator implements OddgenGenerator2 { + + public static val YES = "Yes" + public static val NO = "No" + + public static var GENERATE_FILES = "Generate files?" + public static var OUTPUT_DIRECTORY = "Output directory" + public static var TEST_PACKAGE_PREFIX = UtplsqlResources.getString("PREF_TEST_PACKAGE_PREFIX_LABEL") + public static var TEST_PACKAGE_SUFFIX = UtplsqlResources.getString("PREF_TEST_PACKAGE_SUFFIX_LABEL") + public static var TEST_UNIT_PREFIX = UtplsqlResources.getString("PREF_TEST_UNIT_PREFIX_LABEL") + public static var TEST_UNIT_SUFFIX = UtplsqlResources.getString("PREF_TEST_UNIT_SUFFIX_LABEL") + public static var NUMBER_OF_TESTS_PER_UNIT = UtplsqlResources.getString("PREF_NUMBER_OF_TESTS_PER_UNIT_LABEL") + public static var GENERATE_COMMENTS = "Generate comments?" + public static var DISABLE_TESTS = "Disable tests?" + public static var SUITE_PATH = "Suite Path" + public static var INDENT_SPACES = "Indent Spaces" + + val extension NodeTools nodeTools = new NodeTools + val extension TemplateTools templateTools = new TemplateTools + val consoleOutput = new ArrayList(); + + private def toContext(Node node) { + val context = new GenContext() + context.objectType = node.toObjectType + context.objectName = node.toObjectName + context.generateFiles = node.params.get(GENERATE_FILES) == YES + context.outputDirectory = node.params.get(OUTPUT_DIRECTORY) + context.testPackagePrefix = node.params.get(TEST_PACKAGE_PREFIX).toLowerCase + context.testPackageSuffix = node.params.get(TEST_PACKAGE_SUFFIX).toLowerCase + context.testUnitPrefix = node.params.get(TEST_UNIT_PREFIX).toLowerCase + context.testUnitSuffix = node.params.get(TEST_UNIT_SUFFIX).toLowerCase + context.numberOfTestsPerUnit = Integer.valueOf(node.params.get(NUMBER_OF_TESTS_PER_UNIT)) + context.generateComments = node.params.get(GENERATE_COMMENTS) == YES + context.disableTests = node.params.get(DISABLE_TESTS) == YES + context.suitePath = node.params.get(SUITE_PATH).toLowerCase + context.indentSpaces = Integer.valueOf(node.params.get(INDENT_SPACES)) + return context + } + + private def void resetConsoleOutput() { + consoleOutput.clear + } + + private def void saveConsoleOutput(String s) { + consoleOutput.add(s) + } + + private def String deleteFile(File file) { + var String ret + try { + if (file.delete) { + ret = '''«file.absoluteFile» deleted.''' + } else { + ret = '''Cannot delete file «file.absoluteFile».''' + } + } catch (Exception e) { + ret = '''Cannot delete file «file.absoluteFile». Got the following error message: «e.message».''' + } + return ret + } + + private def deleteFiles(String directory) ''' + «val dir = new File(directory)» + «FOR file: dir.listFiles» + «IF !file.directory» + «IF file.name.endsWith(".pks") || file.name.endsWith(".pkb")» + «file.deleteFile» + «ENDIF» + «ENDIF» + «ENDFOR» + ''' + + 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 "Generate test" + } + + override getDescription(Connection conn) { + return "Generates utPLSQL test packages for public units in packages, types, functions and procedures found in the current schema." + } + + 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) { + val preferences = PreferenceModel.getInstance(Preferences.preferences) + val params = new LinkedHashMap() + params.put(GENERATE_FILES, if (preferences.generateFiles) {YES} else {NO}) + params.put(OUTPUT_DIRECTORY, preferences.outputDirectory) + params.put(TEST_PACKAGE_PREFIX, preferences.testPackagePrefix) + params.put(TEST_PACKAGE_SUFFIX, preferences.testPackageSuffix) + params.put(TEST_UNIT_PREFIX, preferences.testUnitPrefix) + params.put(TEST_UNIT_SUFFIX, preferences.testUnitSuffix) + params.put(NUMBER_OF_TESTS_PER_UNIT, String.valueOf(preferences.numberOfTestsPerUnit)) + params.put(GENERATE_COMMENTS, if(preferences.generateComments) {YES} else {NO}) + params.put(DISABLE_TESTS, if (preferences.disableTests) {YES} else {NO}) + params.put(SUITE_PATH, preferences.suitePath) + params.put(INDENT_SPACES, String.valueOf(preferences.indentSpaces)) + if (parentNodeId === null || parentNodeId.empty) { + val packageNode = new Node + packageNode.id = "PACKAGE" + packageNode.params = params + packageNode.leaf = false + packageNode.generatable = true + packageNode.multiselectable = true + val typeNode = new Node + typeNode.id = "TYPE" + typeNode.params = params + typeNode.leaf = false + typeNode.generatable = true + typeNode.multiselectable = true + val functionNode = new Node + functionNode.id = "FUNCTION" + functionNode.params = params + functionNode.leaf = false + functionNode.generatable = true + functionNode.multiselectable = true + val procedureNode = new Node + procedureNode.id = "PROCEDURE" + procedureNode.params = params + procedureNode.leaf = false + procedureNode.generatable = true + procedureNode.multiselectable = true + return #[packageNode, typeNode, functionNode, procedureNode] + } else { + val UtplsqlDao dao = new UtplsqlDao(conn) + val nodes = dao.testables(parentNodeId) + for (node : nodes) { + node.params = params + } + return nodes + } + } + + override getLov(Connection conn, LinkedHashMap params, List nodes) { + val lov = new HashMap>() + lov.put(NUMBER_OF_TESTS_PER_UNIT, #["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]) + lov.put(INDENT_SPACES, #["1", "2", "3", "4", "5", "6", "7", "8"]) + lov.put(GENERATE_COMMENTS, #[YES, NO]) + lov.put(DISABLE_TESTS, #[YES, NO]) + lov.put(GENERATE_FILES, #[YES, NO]) + return lov + } + + override getParamStates(Connection conn, LinkedHashMap params, List nodes) { + val paramStates = new HashMap + paramStates.put(OUTPUT_DIRECTORY, params.get(GENERATE_FILES) == YES) + return paramStates + } + + override generateProlog(Connection conn, List nodes) ''' + «val generateFiles = nodes.get(0).params.get(GENERATE_FILES) == YES» + «val outputDirectory = nodes.get(0).params.get(OUTPUT_DIRECTORY)» + «IF generateFiles» + «resetConsoleOutput» + «outputDirectory.mkdirs.saveConsoleOutput» + «deleteFiles(outputDirectory).toString.saveConsoleOutput» + -- + -- install generated utPLSQL test packages + -- + «ENDIF» + «FOR node : nodes» + «val context = node.toContext» + «context.conn = conn» + «val testTemplate = new TestTemplate(context)» + «IF generateFiles» + «val packageName = '''«context.testPackagePrefix»«node.toObjectName»«context.testPackageSuffix»'''» + «writeToFile('''«outputDirectory»«File.separator»«packageName».pks'''.toString,testTemplate.generateSpec).saveConsoleOutput» + «writeToFile('''«outputDirectory»«File.separator»«packageName».pkb'''.toString,testTemplate.generateBody).saveConsoleOutput» + @«outputDirectory»«File.separator»«packageName».pks + @«outputDirectory»«File.separator»«packageName».pkb + «ELSE» + «testTemplate.generate» + + «ENDIF» + «ENDFOR» + «IF generateFiles && consoleOutput.size > 0» + + -- + -- console output produced during the generation of this script + -- + /* + + «FOR line : consoleOutput» + «line» + «ENDFOR» + + */ + «ENDIF» + ''' + + override generateSeparator(Connection conn) { + return "" + } + + override generateEpilog(Connection conn, List nodes) { + return "" + } + + override generate(Connection conn, Node node) { + return "" + } + +}