@@ -27,70 +27,101 @@ public class PEx {
27
27
/**
28
28
* Main entry point for PEx runtime.
29
29
*/
30
+ /**
31
+ * Exit codes:
32
+ * 0 - Success
33
+ * 2 - Bug found or too many choices
34
+ * 3 - Timeout
35
+ * 4 - Out of memory
36
+ * 5 - Runtime error
37
+ * 6 - Test driver error
38
+ */
30
39
public static void main (String [] args ) {
31
40
// configure Log4J
32
41
Log4JConfig .configureLog4J ();
33
42
34
- // parse the commandline arguments to create the configuration
35
- PExGlobal .setConfig (PExOptions .ParseCommandlineArgs (args ));
36
- PExGlobal .setChoiceSelector ();
37
- PExLogger .Initialize (PExGlobal .getConfig ().getVerbosity ());
38
- ComputeHash .Initialize ();
39
-
40
- // get reflections corresponding to the model
41
- Reflections reflections = new Reflections ("pex.model" );
42
-
43
- try {
44
- // get all classes extending PModel
45
- Set <Class <? extends PModel >> subTypesPModel = reflections .getSubTypesOf (PModel .class );
46
- if (subTypesPModel .isEmpty ()) {
47
- throw new Exception ("No PModel found." );
48
- }
49
- Optional <Class <? extends PModel >> pModel = subTypesPModel .stream ().findFirst ();
50
-
51
- // set model instance
52
- PExGlobal .setModel (pModel .get ().getDeclaredConstructor ().newInstance ());
53
-
54
- // set project name
55
- setProjectName ();
56
- } catch (Exception ex ) {
57
- ex .printStackTrace ();
58
- System .exit (5 );
59
- }
60
-
61
- // setup loggers, random number gen, time and memory monitors
62
- setup ();
63
-
64
- int exit_code = 0 ;
43
+ // Parse command line arguments and initialize global settings
44
+ initializeEnvironment (args );
45
+
46
+ int exitCode = 0 ;
65
47
try {
66
- // set test driver
48
+ // Get model and test driver
49
+ Reflections reflections = initializeModel ();
50
+
51
+ // Setup loggers, random number gen, time and memory monitors
52
+ setup ();
53
+
54
+ // Set test driver and run analysis
67
55
setTestDriver (reflections );
68
-
69
- // run the analysis
70
56
RuntimeExecutor .run ();
71
- } catch (TooManyChoicesException e ) {
72
- exit_code = 2 ;
73
57
} catch (BugFoundException e ) {
74
- exit_code = 2 ;
58
+ PExLogger .logInfo ("Bug found or too many choices: " + e .getMessage ());
59
+ PExLogger .logTrace (e );
60
+ exitCode = 2 ;
75
61
} catch (InvocationTargetException ex ) {
76
- ex .printStackTrace ();
77
- exit_code = 5 ;
62
+ PExLogger .logInfo ("Invocation target exception: " + ex .getMessage ());
63
+ PExLogger .logTrace (ex );
64
+ exitCode = 5 ;
78
65
} catch (Exception ex ) {
79
- if (ex .getMessage ().equals ("TIMEOUT" )) {
80
- exit_code = 3 ;
81
- } else if (ex .getMessage ().equals ("MEMOUT" )) {
82
- exit_code = 4 ;
66
+ if ("TIMEOUT" .equals (ex .getMessage ())) {
67
+ PExLogger .logInfo ("Execution timed out" );
68
+ exitCode = 3 ;
69
+ } else if ("MEMOUT" .equals (ex .getMessage ())) {
70
+ PExLogger .logInfo ("Out of memory: " + MemoryMonitor .getMemSpent () + " MB used" );
71
+ exitCode = 4 ;
83
72
} else {
84
- ex .printStackTrace ();
85
- exit_code = 5 ;
73
+ PExLogger .logInfo ("Runtime exception: " + ex .getMessage ());
74
+ PExLogger .logTrace (ex );
75
+ exitCode = 5 ;
86
76
}
87
77
} finally {
88
- // log end-of-run metrics
89
- StatWriter .log ("exit-code" , String .format ("%d" , exit_code ));
90
-
91
- // exit
92
- System .exit (exit_code );
78
+ // Log end-of-run metrics
79
+ StatWriter .log ("exit-code" , String .format ("%d" , exitCode ));
80
+
81
+ // Exit
82
+ System .exit (exitCode );
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Initialize global environment settings
88
+ *
89
+ * @param args Command line arguments
90
+ */
91
+ private static void initializeEnvironment (String [] args ) {
92
+ PExGlobal .setConfig (PExOptions .ParseCommandlineArgs (args ));
93
+ PExGlobal .setChoiceSelector ();
94
+ PExLogger .Initialize (PExGlobal .getConfig ().getVerbosity ());
95
+ ComputeHash .Initialize ();
96
+ }
97
+
98
+ /**
99
+ * Initialize the model
100
+ *
101
+ * @return Reflections object for model package
102
+ * @throws Exception if model initialization fails
103
+ */
104
+ private static Reflections initializeModel () throws Exception {
105
+ // Get reflections corresponding to the model
106
+ Reflections reflections = new Reflections ("pex.model" );
107
+
108
+ // Get all classes extending PModel
109
+ Set <Class <? extends PModel >> subTypesPModel = reflections .getSubTypesOf (PModel .class );
110
+ if (subTypesPModel .isEmpty ()) {
111
+ throw new Exception ("No PModel implementation found in pex.model package." );
93
112
}
113
+
114
+ // Get first model and instantiate it
115
+ Class <? extends PModel > modelClass = subTypesPModel .stream ()
116
+ .findFirst ()
117
+ .orElseThrow (() -> new Exception ("Failed to get PModel instance." ));
118
+
119
+ PExGlobal .setModel (modelClass .getDeclaredConstructor ().newInstance ());
120
+
121
+ // Set project name
122
+ setProjectName ();
123
+
124
+ return reflections ;
94
125
}
95
126
96
127
/**
@@ -134,45 +165,50 @@ private static void setProjectName() {
134
165
* @param reflections reflections corresponding to the pex.model
135
166
* @throws Exception Throws exception if test driver is not found
136
167
*/
137
- private static void setTestDriver (Reflections reflections )
138
- throws Exception {
139
- final String name = PExGlobal .getConfig ().getTestDriver ();
168
+ private static void setTestDriver (Reflections reflections ) throws Exception {
169
+ final String requestedName = PExGlobal .getConfig ().getTestDriver ();
140
170
final String defaultTestDriver = PExGlobal .getConfig ().getTestDriverDefault ();
141
-
142
- Set <Class <? extends PTestDriver >> subTypesDriver = reflections .getSubTypesOf (PTestDriver .class );
143
- PTestDriver driver = null ;
144
- for (Class <? extends PTestDriver > td : subTypesDriver ) {
145
- if (PTestDriver .getTestName (td ).equals (name )) {
146
- driver = td .getDeclaredConstructor ().newInstance ();
147
- break ;
148
- }
171
+ final Set <Class <? extends PTestDriver >> availableDrivers = reflections .getSubTypesOf (PTestDriver .class );
172
+
173
+ // Try to find driver by name
174
+ Optional <Class <? extends PTestDriver >> driverClass = availableDrivers .stream ()
175
+ .filter (d -> PTestDriver .getTestName (d ).equals (requestedName ))
176
+ .findFirst ();
177
+
178
+ // If not found but using default driver name and only one driver exists, use that one
179
+ if (driverClass .isEmpty () && requestedName .equals (defaultTestDriver ) && availableDrivers .size () == 1 ) {
180
+ driverClass = availableDrivers .stream ().findFirst ();
149
181
}
150
- if (driver == null && name .equals (defaultTestDriver ) && subTypesDriver .size () == 1 ) {
151
- for (Class <? extends PTestDriver > td : subTypesDriver ) {
152
- driver = td .getDeclaredConstructor ().newInstance ();
153
- break ;
154
- }
182
+
183
+ // If we found a driver, instantiate and configure it
184
+ if (driverClass .isPresent ()) {
185
+ PTestDriver driver = driverClass .get ().getDeclaredConstructor ().newInstance ();
186
+ PExGlobal .getConfig ().setTestDriver (PTestDriver .getTestName (driver .getClass ()));
187
+ PExGlobal .getModel ().setTestDriver (driver );
188
+ return ;
155
189
}
156
- if (driver == null ) {
157
- if (!name .equals (defaultTestDriver )) {
158
- PExLogger .logInfo ("No test driver found named \" " + name + "\" " );
159
- }
160
- PExLogger .logInfo (
161
- String .format (
162
- "Error: We found '%d' test cases. Please provide a more precise name of the test case you wish to check using (--testcase | -tc)." ,
163
- subTypesDriver .size ()));
164
- PExLogger .logInfo ("Possible options are:" );
165
- for (Class <? extends PTestDriver > td : subTypesDriver ) {
166
- PExLogger .logInfo (String .format ("%s" , PTestDriver .getTestName (td )));
167
- }
168
- if (!name .equals (defaultTestDriver )) {
169
- throw new Exception ("No test driver found named \" " + PExGlobal .getConfig ().getTestDriver () + "\" " );
170
- } else {
171
- System .exit (6 );
172
- }
190
+
191
+ // No driver found, report error with available options
192
+ if (!requestedName .equals (defaultTestDriver )) {
193
+ PExLogger .logInfo ("No test driver found named \" " + requestedName + "\" " );
194
+ }
195
+
196
+ PExLogger .logInfo (String .format (
197
+ "Error: We found %d test cases. Please provide a more precise name using (--testcase | -tc)." ,
198
+ availableDrivers .size ()));
199
+
200
+ if (!availableDrivers .isEmpty ()) {
201
+ PExLogger .logInfo ("Available test driver options:" );
202
+ availableDrivers .forEach (td ->
203
+ PExLogger .logInfo (String .format (" - %s" , PTestDriver .getTestName (td ))));
204
+ }
205
+
206
+ // Exit with appropriate error
207
+ if (!requestedName .equals (defaultTestDriver )) {
208
+ throw new Exception ("No test driver found named \" " + requestedName + "\" " );
209
+ } else {
210
+ System .exit (6 );
173
211
}
174
- PExGlobal .getConfig ().setTestDriver (PTestDriver .getTestName (driver .getClass ()));
175
- PExGlobal .getModel ().setTestDriver (driver );
176
212
}
177
213
178
214
}
0 commit comments