2222import java .sql .Connection ;
2323import java .util .ArrayList ;
2424import java .util .Arrays ;
25+ import java .util .HashMap ;
2526import java .util .List ;
27+ import java .util .Map ;
2628import java .util .logging .Logger ;
29+ import java .util .stream .Collectors ;
2730
31+ import org .utplsql .sqldev .dal .RealtimeReporterDao ;
2832import org .utplsql .sqldev .dal .UtplsqlDao ;
2933import org .utplsql .sqldev .exception .GenericDatabaseAccessException ;
3034import org .utplsql .sqldev .exception .GenericRuntimeException ;
3135import org .utplsql .sqldev .model .DatabaseTools ;
3236import org .utplsql .sqldev .model .FileTools ;
37+ import org .utplsql .sqldev .model .preference .PreferenceModel ;
38+ import org .utplsql .sqldev .runner .UtplsqlRunner ;
3339import org .utplsql .sqldev .ui .coverage .CodeCoverageReporterDialog ;
3440
41+ import oracle .ide .config .Preferences ;
42+
3543public class CodeCoverageReporter {
3644 private static final Logger logger = Logger .getLogger (CodeCoverageReporter .class .getName ());
3745
46+ private String connectionName ;
3847 private Connection conn ;
3948 private List <String > pathList ;
4049 private List <String > includeObjectList ;
@@ -47,14 +56,17 @@ public CodeCoverageReporter(final List<String> pathList, final List<String> incl
4756 final String connectionName ) {
4857 this .pathList = pathList ;
4958 this .includeObjectList = includeObjectList ;
59+ setDefaultSchema ();
5060 setConnection (connectionName );
5161 }
5262
63+ // constructor for testing purposes only
5364 public CodeCoverageReporter (final List <String > pathList , final List <String > includeObjectList ,
5465 final Connection conn ) {
5566 this .pathList = pathList ;
5667 this .includeObjectList = includeObjectList ;
5768 this .conn = conn ;
69+ setDefaultSchema ();
5870 }
5971
6072 private void setConnection (final String connectionName ) {
@@ -64,7 +76,32 @@ private void setConnection(final String connectionName) {
6476 throw new NullPointerException ();
6577 } else {
6678 // must be closed manually
67- conn = DatabaseTools .cloneConnection (connectionName );
79+ this .connectionName = connectionName ;
80+ this .conn = DatabaseTools .getConnection (connectionName );
81+ }
82+ }
83+
84+ private void setDefaultSchema () {
85+ if (includeObjectList != null && !includeObjectList .isEmpty ()) {
86+ // use the owner with the most hits in includeObjectList
87+ HashMap <String , Integer > owners = new HashMap <>();
88+ for (String entry : includeObjectList ) {
89+ String [] obj = entry .toUpperCase ().split ("\\ ." );
90+ if (obj .length == 2 ) {
91+ // only if objectOwner and objectName are available
92+ Integer count = owners .get (obj [0 ]);
93+ if (count == null ) {
94+ count = 1 ;
95+ } else {
96+ count ++;
97+ }
98+ owners .put (obj [0 ], count );
99+ }
100+ }
101+ List <String > sortedOwners = owners .entrySet ().stream ()
102+ .sorted (Map .Entry .<String , Integer >comparingByValue ().reversed ()).map (Map .Entry ::getKey )
103+ .collect (Collectors .toList ());
104+ schemas = String .join (", " , sortedOwners );
68105 }
69106 }
70107
@@ -83,12 +120,57 @@ private ArrayList<String> toStringList(final String s) {
83120 private void run () {
84121 logger .fine (() -> "Running code coverage reporter for " + pathList + "..." );
85122 try {
86- final UtplsqlDao dal = new UtplsqlDao (conn );
87- final String content = dal .htmlCodeCoverage (pathList , toStringList (schemas ),
123+ final RealtimeReporterDao dao = new RealtimeReporterDao (conn );
124+ PreferenceModel preferences ;
125+ try {
126+ preferences = PreferenceModel .getInstance (Preferences .getPreferences ());
127+ } catch (NoClassDefFoundError error ) {
128+ // not running in SQL Developer (in tests)
129+ preferences = PreferenceModel .getInstance (null );
130+ }
131+ if (preferences .isUseRealtimeReporter () && dao .isSupported () && connectionName != null ) {
132+ runCodeCoverageWithRealtimeReporter ();
133+ } else {
134+ runCodeCoverageStandalone ();
135+ }
136+ } finally {
137+ if (frame != null ) {
138+ frame .exit ();
139+ }
140+ }
141+ }
142+
143+ private void runCodeCoverageWithRealtimeReporter () {
144+ final UtplsqlRunner runner = new UtplsqlRunner (pathList , toStringList (schemas ), toStringList (includeObjects ),
145+ toStringList (excludeObjects ), connectionName );
146+ runner .runTestAsync ();
147+ }
148+
149+ private void runCodeCoverageStandalone () {
150+ Connection coverageConn = null ;
151+ try {
152+ coverageConn = conn != null ? conn : DatabaseTools .cloneConnection (connectionName );
153+ final UtplsqlDao dao = new UtplsqlDao (coverageConn );
154+ final String html = dao .htmlCodeCoverage (pathList , toStringList (schemas ),
88155 toStringList (includeObjects ), toStringList (excludeObjects ));
156+ openInBrowser (html );
157+ } finally {
158+ try {
159+ if (coverageConn != null && conn == null ) {
160+ // close only if connection has been cloned
161+ DatabaseTools .closeConnection (coverageConn );
162+ }
163+ } catch (GenericDatabaseAccessException e ) {
164+ // ignore
165+ }
166+ }
167+ }
168+
169+ public static void openInBrowser (String html ) {
170+ try {
89171 final File file = File .createTempFile ("utplsql_" , ".html" );
90172 logger .fine (() -> "Writing result to " + file + "..." );
91- FileTools .writeFile (file .toPath (), Arrays .asList (content .split (System .lineSeparator ())), StandardCharsets .UTF_8 );
173+ FileTools .writeFile (file .toPath (), Arrays .asList (html .split (System .lineSeparator ())), StandardCharsets .UTF_8 );
92174 final URL url = file .toURI ().toURL ();
93175 logger .fine (() -> "Opening " + url .toExternalForm () + " in browser..." );
94176 final Desktop desktop = Desktop .isDesktopSupported () ? Desktop .getDesktop () : null ;
@@ -97,21 +179,12 @@ private void run() {
97179 logger .fine (() -> url .toExternalForm () + " opened in browser." );
98180 } else {
99181 logger .severe (
100- () -> "Could not launch " + file + "in browser. No default browser defined on this system." );
182+ () -> "Could not launch " + file + " in browser. No default browser defined on this system." );
101183 }
102184 } catch (Exception e ) {
103- final String msg = "Error while running code coverage for " + pathList + " ." ;
185+ final String msg = "Error while opening code coverage HTML report in browser ." ;
104186 logger .severe (() -> msg );
105187 throw new GenericRuntimeException (msg , e );
106- } finally {
107- try {
108- DatabaseTools .closeConnection (conn );
109- } catch (GenericDatabaseAccessException e ) {
110- // ignore
111- }
112- if (frame != null ) {
113- frame .exit ();
114- }
115188 }
116189 }
117190
@@ -143,6 +216,10 @@ public void setSchemas(final String schemas) {
143216 this .schemas = schemas ;
144217 }
145218
219+ public String getSchemas () {
220+ return schemas ;
221+ }
222+
146223 public void setIncludeObjects (final String includeObjects ) {
147224 this .includeObjects = includeObjects ;
148225 }
0 commit comments