David Carr avatar David Carr committed 3586757

Only exit the VM when run on the command-line; otherwise, communicate status via exception. This allows better unit testing.

Comments (0)

Files changed (2)

app/src/main/java/deepdiff/app/AppExitException.java

+/*
+ * Copyright 2011 DeepDiff Contributors
+ *
+ * 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 deepdiff.app;
+
+public class AppExitException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+    private final int exitCode;
+
+    public AppExitException(int exitCode) {
+        super();
+        this.exitCode = exitCode;
+    }
+
+    public AppExitException(String msg, int exitCode) {
+        super(msg);
+        this.exitCode = exitCode;
+    }
+
+    public int getExitCode() {
+        return exitCode;
+    }
+}

app/src/main/java/deepdiff/app/DeepDiff.java

      * @param args the command-line arguments
      */
     public static void main(String[] args) {
-        CommandLine cl = parseCommandLine(args);
-        if (cl != null) { // Valid args
-            processCommand(cl);
-        } else { // Invalid args
-            System.exit(-1);
+        DeepDiff app = new DeepDiff();
+        try {
+            CommandLine cl = app.parseCommandLine(args);
+            app.processCommand(cl);
+            System.exit(0);
+        } catch (AppExitException ex) {
+            System.exit(ex.getExitCode());
         }
     }
 
      * 
      * @return the parsed command-line
      */
-    static CommandLine parseCommandLine(String[] args) {
+    CommandLine parseCommandLine(String[] args) {
         CommandLineParser parser = new GnuParser();
-        CommandLine cl = null;
         try {
-            cl = parser.parse(CONFIGURED_OPTIONS, args);
+            CommandLine cl = parser.parse(CONFIGURED_OPTIONS, args);
+            return cl;
         } catch (ParseException pe) {
             System.err.println("Invalid command-line options: " + pe.getMessage());
             System.err.println();
             showUsage(new PrintWriter(System.err), CONFIGURED_OPTIONS);
+            throw new AppExitException(-1);
         }
-        return cl;
     }
 
     /**
      * 
      * @param cl the commmand line options
      */
-    private static void processCommand(CommandLine cl) {
+    private void processCommand(CommandLine cl) {
+        InputSource configSource = processCommandLineOptions(cl);
+        if (configSource == null) { // Use default configuration
+            configSource = new InputSource(getDefaultConfigStream());
+        }
+        Collection<DiffScope> scopes = loadConfig(configSource);
+        DiffUnitProcessor unitProcessor = getUnitProcessor();
+        DiffPointProcessor pointProcessor = getPointProcessor();
+        addCommandLineScopes(cl, scopes);
+        scanScopes(unitProcessor, pointProcessor, scopes);
+    }
+
+    private InputSource processCommandLineOptions(CommandLine cl) {
         InputSource configSource = null;
-
         log.debug("Processing command-line options...");
         Option[] opts = cl.getOptions();
         for (int i = 0; i < opts.length; i++) {
                 try {
                     copy(getDefaultConfigStream(), new File(filePath));
                     log.info("Wrote sample configuration file to " + filePath);
-                    return;
+                    throw new AppExitException(0);
                 } catch (IOException ex) {
                     log.fatal("Failed to write sample configuration file to " + filePath);
-                    System.exit(-1);
+                    throw new AppExitException(-1);
                 }
             } else if (O_FILE.getOpt().equals(opt.getOpt())) {
                 if (configSource == null) {
                     File configFile = new File(filePath);
                     if (!configFile.exists()) {
                         log.fatal("Specified configuration file does not exist: " + filePath);
-                        System.exit(-1);
+                        throw new AppExitException(-1);
                     }
                     try {
                         configSource = new InputSource(new FileReader(configFile));
                     } catch (IOException ex) {
                         log.fatal("Failed to read configuration file from " + filePath);
-                        System.exit(-1);
+                        throw new AppExitException(-1);
                     }
                 } else {
                     log.fatal("Multiple -" + opt.getOpt() + " options specified");
                     PrintWriter pw = new PrintWriter(System.err);
                     showUsage(pw, CONFIGURED_OPTIONS);
-                    System.exit(-1);
+                    throw new AppExitException(-1);
                 }
             } else {
                 log.warn("Unknown option: " + opt.getOpt());
             }
         }
         log.debug("Done processing command-line options");
+        return configSource;
+    }
 
-        if (configSource == null) { // Use default configuration
-            configSource = new InputSource(getDefaultConfigStream());
-        }
-
-        ConfigHandler configHandler = new ConfigHandler();
-        Collection<DiffScope> scopes = new LinkedList<DiffScope>();
-        try {
-            SAXParserFactory parserFactory = SAXParserFactory.newInstance();
-            SAXParser parser = parserFactory.newSAXParser();
-            parser.parse(configSource, configHandler);
-            scopes.addAll(configHandler.getScopes());
-        } catch (SAXException saxe) {
-            log.fatal("Failure reading config", saxe);
-            System.exit(-1);
-        } catch (ParserConfigurationException pce) {
-            log.fatal("Failure reading config", pce);
-            System.exit(-1);
-        } catch (IOException ioe) {
-            log.fatal("Failure reading config", ioe);
-            System.exit(-1);
-        }
-
-        DiffUnitProcessor unitProcessor = DiffUnitProcessorFactory.getDefault();
-        DiffPointProcessor pointProcessor = DiffPointProcessorFactory.getDefault();
-        if (unitProcessor == null) {
-            log.fatal("No unit processor configured; exiting");
-            System.exit(-1);
-        }
-        if (pointProcessor == null) {
-            log.fatal("No point processor configured; exiting");
-            System.exit(-1);
-        }
-
-        List<?> argList = cl.getArgList();
-        if (argList.size() % 2 != 0) {
-            log.fatal("Comparison scopes specified as command-line arguments must be in pairs.");
-            System.exit(-1);
-        }
-        for (int i = 0; i < argList.size(); i += 2) {
-            File root1 = new File((String) argList.get(i));
-            File root2 = new File((String) argList.get(i + 1));
-            DiffScope scope = DiffUnitProcessorFactory.createInitialScope(root1, root2);
-            scopes.add(scope);
-        }
-
+    private void scanScopes(DiffUnitProcessor unitProcessor, DiffPointProcessor pointProcessor,
+            Collection<DiffScope> scopes) {
         if (scopes.isEmpty()) {
             log.warn("No scopes found");
         } else {
         }
     }
 
-    private static InputStream getDefaultConfigStream() {
-        return DeepDiff.class.getResourceAsStream(DEFAULT_CONFIG);
+    private void addCommandLineScopes(CommandLine cl, Collection<DiffScope> scopes) {
+        List<?> argList = cl.getArgList();
+        if (argList.size() % 2 != 0) {
+            log.fatal("Comparison scopes specified as command-line arguments must be in pairs.");
+            throw new AppExitException(-1);
+        }
+        for (int i = 0; i < argList.size(); i += 2) {
+            File root1 = new File((String) argList.get(i));
+            File root2 = new File((String) argList.get(i + 1));
+            DiffScope scope = DiffUnitProcessorFactory.createInitialScope(root1, root2);
+            scopes.add(scope);
+        }
+    }
+
+    DiffPointProcessor getPointProcessor() {
+        DiffPointProcessor pointProcessor = DiffPointProcessorFactory.getDefault();
+        if (pointProcessor == null) {
+            log.fatal("No point processor configured; exiting");
+            throw new AppExitException(-1);
+        }
+        return pointProcessor;
+    }
+
+    DiffUnitProcessor getUnitProcessor() {
+        DiffUnitProcessor unitProcessor = DiffUnitProcessorFactory.getDefault();
+        if (unitProcessor == null) {
+            log.fatal("No unit processor configured; exiting");
+            throw new AppExitException(-1);
+        }
+        return unitProcessor;
+    }
+
+    Collection<DiffScope> loadConfig(InputSource configSource) {
+        ConfigHandler configHandler = new ConfigHandler();
+        Collection<DiffScope> scopes = new LinkedList<DiffScope>();
+        try {
+            SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+            SAXParser parser = parserFactory.newSAXParser();
+            parser.parse(configSource, configHandler);
+            scopes.addAll(configHandler.getScopes());
+        } catch (SAXException saxe) {
+            log.fatal("Failure reading config", saxe);
+            throw new AppExitException(-1);
+        } catch (ParserConfigurationException pce) {
+            log.fatal("Failure reading config", pce);
+            throw new AppExitException(-1);
+        } catch (IOException ioe) {
+            log.fatal("Failure reading config", ioe);
+            throw new AppExitException(-1);
+        }
+        return scopes;
+    }
+
+    InputStream getDefaultConfigStream() {
+        return getClass().getResourceAsStream(DEFAULT_CONFIG);
     }
 
     /**
      * @param pw the PrintWriter to show the usage information on
      * @param options the supported options
      */
-    private static void showUsage(PrintWriter pw, Options options) {
+    private void showUsage(PrintWriter pw, Options options) {
         HelpFormatter formatter = new HelpFormatter();
         formatter.printHelp(pw, 80, USAGE,
                 "Files or directories to compare should be specified in pairs.", options, 1, 3, "",
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.