Further unit tests: CFB and Delta
authorChris Jaekl <cejaekl@yahoo.com>
Thu, 31 Dec 2015 09:48:02 +0000 (18:48 +0900)
committerChris Jaekl <cejaekl@yahoo.com>
Thu, 31 Dec 2015 09:48:02 +0000 (18:48 +0900)
prod/net/jaekl/cfb/CFB.java
prod/net/jaekl/cfb/CfbBundle.java
test/net/jaekl/cfb/CFBMock.java [new file with mode: 0644]
test/net/jaekl/cfb/CFBTest.java [new file with mode: 0644]
test/net/jaekl/cfb/CfbBundleMock.java [new file with mode: 0644]
test/net/jaekl/cfb/analyze/DeltaTest.java
test/net/jaekl/cfb/db/driver/ConnectionMock.java
test/net/jaekl/cfb/db/driver/DbDriverMock.java

index 639a73198088ffcf7e9335286dbeb4932512ad0a..c97a1c8f7b4e74196f528b80d11bb16dfdd22884 100644 (file)
@@ -42,7 +42,7 @@ import org.xml.sax.SAXException;
 public class CFB {
        DbDriver m_driver;
        CfbSchema m_schema;
-       CfbBundle m_bundle;     
+       volatile static CfbBundle m_bundle = null;      
        Locale m_locale;
        
        Config m_config;
@@ -60,7 +60,7 @@ public class CFB {
                m_driver = new PostgresqlDriver();
                m_schema = new CfbSchema(m_driver);
                m_locale = locale;
-               m_bundle = CfbBundle.getInst(m_locale);
+               m_bundle = null;
                m_config = new Config();
                
                m_configFile = new File("config.properties");
@@ -72,6 +72,18 @@ public class CFB {
                m_output = null;
        }
        
+       CfbBundle getBundle() {
+               CfbBundle bundle = m_bundle;
+               if (null == bundle) {
+                       synchronized(CFB.class) {
+                               if (null == m_bundle) {
+                                       m_bundle = bundle = CfbBundle.getInst(m_locale);
+                               }
+                       }
+               }
+               return bundle;
+       }
+       
        Options createOptions() {
                Options opt = new Options();
                
@@ -141,7 +153,7 @@ public class CFB {
        }
        
        String trans(String key) {
-               return m_bundle.get(key);
+               return getBundle().get(key);
        }
        
        String getenv(String varName) {
@@ -187,6 +199,23 @@ public class CFB {
                MessageMap messageMap = new MessageMap();
                messageMap.load(findBugsDir, Locale.getDefault(Category.DISPLAY));
                
+               if (!ensureDbInitialized(pw, messageMap)) {
+                       return;
+               }
+               
+               Analyzer analyzer = new Analyzer(messageMap);
+               Analysis analysis = analyzer.analyze(pw, workDir, m_fbp, m_projName, m_buildNum);
+               if (null == analysis) {
+                       pw.println(trans(CfbBundle.ANALYSIS_FAILED));
+                       return;
+               }
+               
+               storeAndReport(pw, messageMap, analysis);
+       }
+
+       boolean ensureDbInitialized(PrintWriter pw, MessageMap messageMap)
+                       throws TypeMismatchException 
+       {
                try (Connection con = m_driver.connect(
                                        m_config.getDbHost(), m_config.getDbPort(), 
                                        m_config.getDbName(), 
@@ -197,23 +226,22 @@ public class CFB {
                        
                        if (m_removeSchema) {
                                m_schema.purge(con);
-                               return;
+                               return false;   // do not continue execution
                        }
                        m_schema.ensureDbInitialized(con);
                        messageMap.loadIds(con, m_driver);
                }
                catch (SQLException exc) {
                        reportUnableToConnect(pw, exc);
-                       return;
-               }
-               
-               Analyzer analyzer = new Analyzer(messageMap);
-               Analysis analysis = analyzer.analyze(pw, workDir, m_fbp, m_projName, m_buildNum);
-               if (null == analysis) {
-                       pw.println(trans(CfbBundle.ANALYSIS_FAILED));
-                       return;
+                       return false;   // do not continue execution
                }
                
+               return true;    // all OK; continue execution
+       }
+
+       void storeAndReport(PrintWriter pw, MessageMap messageMap, Analysis analysis) 
+                       throws TypeMismatchException, IOException 
+       {
                try (
                                Connection con = m_driver.connect(
                                                m_config.getDbHost(), m_config.getDbPort(), 
@@ -228,21 +256,19 @@ public class CFB {
                        Analysis prior = store.getPrior(analysis);
                        Delta delta = new Delta(prior, analysis);
 
-                       HtmlReport report = new HtmlReport(m_bundle, messageMap.getColl(), delta);
+                       HtmlReport report = new HtmlReport(getBundle(), messageMap.getColl(), delta);
                        if (null != m_output) {
                                report.write(m_output);
                        }
                        
-                       Notifier notifier = new Notifier(m_bundle, m_config);
+                       Notifier notifier = new Notifier(getBundle(), m_config);
                        notifier.sendEmailIfNeeded(pw, report);
                }
                catch (StoreException exc) {
                        exc.printStackTrace(pw);
-                       return;
                }
                catch (SQLException exc) {
                        reportUnableToConnect(pw, exc);
-                       return;
                }
        }
 
index 5f5aa9ee8b52ce303cf45c623a8853800c32b1e4..b46b2905722a3eaaed88a054f2ed188b4a9405e1 100644 (file)
@@ -58,6 +58,11 @@ public class CfbBundle {
                m_bundle = QDBundleFactory.getInst().getBundle(BUNDLE_NAME, locale); 
        }
        
+       // This constructor is intended only for use during unit testing.
+       CfbBundle() {
+               m_bundle = null;
+       }
+       
        public String get(String key, Object... arguments) {
                try {
                        if (null != m_bundle) {
@@ -71,10 +76,15 @@ public class CfbBundle {
                        // Fall through to the fallback behaviour below
                }
                
+               return fallbackGet(key, arguments);
+       }
+       
+       String fallbackGet(String key, Object... arguments) {
                StringBuilder sb = new StringBuilder("[" + key + "]");
                for (Object obj : arguments) {
                        sb.append("[" + obj + "]");
                }
                return sb.toString();
+               
        }
 }
diff --git a/test/net/jaekl/cfb/CFBMock.java b/test/net/jaekl/cfb/CFBMock.java
new file mode 100644 (file)
index 0000000..b76876f
--- /dev/null
@@ -0,0 +1,24 @@
+package net.jaekl.cfb;
+
+import java.util.Locale;
+
+import net.jaekl.cfb.db.CfbSchema;
+import net.jaekl.cfb.db.driver.DbDriver;
+
+public class CFBMock extends CFB {
+       private CfbBundleMock mock_bundle;
+       
+       CFBMock(Locale locale, DbDriver driver) 
+       {
+               super(locale);
+               m_driver = driver;
+               m_schema = new CfbSchema(m_driver);
+               mock_bundle = new CfbBundleMock();
+       }
+       
+       @Override
+       CfbBundle getBundle()
+       {
+               return mock_bundle;
+       }
+}
diff --git a/test/net/jaekl/cfb/CFBTest.java b/test/net/jaekl/cfb/CFBTest.java
new file mode 100644 (file)
index 0000000..de10fe7
--- /dev/null
@@ -0,0 +1,136 @@
+package net.jaekl.cfb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Locale;
+
+import net.jaekl.cfb.analyze.Analysis;
+import net.jaekl.cfb.analyze.MessageMap;
+import net.jaekl.cfb.db.CfbSchema;
+import net.jaekl.cfb.db.Column;
+import net.jaekl.cfb.db.Condition;
+import net.jaekl.cfb.db.Operation;
+import net.jaekl.cfb.db.Row;
+import net.jaekl.cfb.db.Table;
+import net.jaekl.cfb.db.TypeMismatchException;
+import net.jaekl.cfb.db.driver.DbDriverMock;
+import net.jaekl.cfb.util.Command;
+import net.jaekl.cfb.xml.MessagesXmlData;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class CFBTest {
+       private CFBMock m_cfb;
+       private DbDriverMock m_driver;
+       
+       private static final String BUG_COLLECTION_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+                       + "<BugCollection version=\"2.0.3\" sequence=\"0\" timestamp=\"1425655198000\" analysisTimestamp=\"1451305502231\" release=\"\">"
+                       + "<Project projectName=\"JUnit\">"
+                       + "<Jar>/data/prog/findbugs-3.0.1/lib/junit.jar</Jar>"
+                       + "</Project>"
+                       + "<BugInstance type=\"VO_VOLATILE_INCREMENT\" priority=\"2\" abbrev=\"VO\" category=\"MT_CORRECTNESS\">"
+                       + "<Class classname=\"junit.extensions.ActiveTestSuite\">"
+                       + "<SourceLine classname=\"junit.extensions.ActiveTestSuite\" sourcefile=\"ActiveTestSuite.java\" sourcepath=\"junit/extensions/ActiveTestSuite.java\"/>"
+                       + "</Class>"
+                       + "<Method classname=\"junit.extensions.ActiveTestSuite\" name=\"runFinished\" signature=\"()V\" isStatic=\"false\">"
+                       + "<SourceLine classname=\"junit.extensions.ActiveTestSuite\" start=\"67\" end=\"69\" startBytecode=\"0\" endBytecode=\"64\" sourcefile=\"ActiveTestSuite.java\" sourcepath=\"junit/extensions/ActiveTestSuite.java\"/>"
+                       + "</Method>"
+                       + "<Field classname=\"junit.extensions.ActiveTestSuite\" name=\"fActiveTestDeathCount\" signature=\"I\" isStatic=\"false\">"
+                       + "<SourceLine classname=\"junit.extensions.ActiveTestSuite\" sourcefile=\"ActiveTestSuite.java\" sourcepath=\"junit/extensions/ActiveTestSuite.java\"/>"
+                       + "</Field>"
+                       + "<SourceLine classname=\"junit.extensions.ActiveTestSuite\" start=\"67\" end=\"67\" startBytecode=\"7\" endBytecode=\"7\" sourcefile=\"ActiveTestSuite.java\" sourcepath=\"junit/extensions/ActiveTestSuite.java\"/>"
+                       + "</BugInstance>"
+                       + "<BugInstance type=\"DM_NUMBER_CTOR\" priority=\"2\" abbrev=\"Bx\" category=\"PERFORMANCE\">"
+                       + "<Class classname=\"junit.framework.Assert\">"
+                       + "<SourceLine classname=\"junit.framework.Assert\" sourcefile=\"Assert.java\" sourcepath=\"junit/framework/Assert.java\"/>"
+                       + "</Class>"
+                       + "<Method classname=\"junit.framework.Assert\" name=\"assertEquals\" signature=\"(Ljava/lang/String;BB)V\" isStatic=\"true\">"
+                       + "<SourceLine classname=\"junit.framework.Assert\" start=\"156\" end=\"157\" startBytecode=\"0\" endBytecode=\"86\" sourcefile=\"Assert.java\" sourcepath=\"junit/framework/Assert.java\"/>"
+                       + "</Method>"
+                       + "<Method classname=\"java.lang.Byte\" name=\"&lt;init&gt;\" signature=\"(B)V\" isStatic=\"false\" role=\"METHOD_CALLED\">"
+                       + "<SourceLine classname=\"java.lang.Byte\" start=\"307\" end=\"309\" startBytecode=\"0\" endBytecode=\"41\" sourcefile=\"Byte.java\" sourcepath=\"java/lang/Byte.java\"/>"
+                       + "</Method>"
+                       + "<Method classname=\"java.lang.Byte\" name=\"valueOf\" signature=\"(B)Ljava/lang/Byte;\" isStatic=\"true\" role=\"SHOULD_CALL\">"
+                       + "<SourceLine classname=\"java.lang.Byte\" start=\"87\" end=\"87\" startBytecode=\"0\" endBytecode=\"33\" sourcefile=\"Byte.java\" sourcepath=\"java/lang/Byte.java\"/>"
+                       + "</Method>"
+                       + "<SourceLine classname=\"junit.framework.Assert\" start=\"156\" end=\"156\" startBytecode=\"6\" endBytecode=\"6\" sourcefile=\"Assert.java\" sourcepath=\"junit/framework/Assert.java\"/>"
+                       + "</BugInstance>"
+                       + "<BugInstance type=\"DM_NUMBER_CTOR\" priority=\"2\" abbrev=\"Bx\" category=\"PERFORMANCE\">"
+                       + "<Class classname=\"junit.framework.Assert\">"
+                       + "<SourceLine classname=\"junit.framework.Assert\" sourcefile=\"Assert.java\" sourcepath=\"junit/framework/Assert.java\"/>"
+                       + "</Class>"
+                       + "<Method classname=\"junit.framework.Assert\" name=\"assertEquals\" signature=\"(Ljava/lang/String;CC)V\" isStatic=\"true\">"
+                       + "<SourceLine classname=\"junit.framework.Assert\" start=\"169\" end=\"170\" startBytecode=\"0\" endBytecode=\"86\" sourcefile=\"Assert.java\" sourcepath=\"junit/framework/Assert.java\"/>"
+                       + "</Method>"
+                       + "<Method classname=\"java.lang.Character\" name=\"&lt;init&gt;\" signature=\"(C)V\" isStatic=\"false\" role=\"METHOD_CALLED\">"
+                       + "<SourceLine classname=\"java.lang.Character\" start=\"2056\" end=\"2058\" startBytecode=\"0\" endBytecode=\"41\" sourcefile=\"Character.java\" sourcepath=\"java/lang/Character.java\"/>"
+                       + "</Method>"
+                       + "<Method classname=\"java.lang.Character\" name=\"valueOf\" signature=\"(C)Ljava/lang/Character;\" isStatic=\"true\" role=\"SHOULD_CALL\">"
+                       + "<SourceLine classname=\"java.lang.Character\" start=\"2085\" end=\"2088\" startBytecode=\"0\" endBytecode=\"52\" sourcefile=\"Character.java\" sourcepath=\"java/lang/Character.java\"/>"
+                       + "</Method>"
+                       + "<SourceLine classname=\"junit.framework.Assert\" start=\"169\" end=\"169\" startBytecode=\"6\" endBytecode=\"6\" sourcefile=\"Assert.java\" sourcepath=\"junit/framework/Assert.java\"/>"
+                       + "</BugInstance>"
+                       + "</BugCollection>";
+
+       private Analysis analysisFromXml(String xml, String projectName, String version) 
+                       throws FileNotFoundException, IOException, SAXException 
+       {
+               Analysis analysis = new Analysis(projectName, version);
+               ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes(Command.UTF_8));
+               InputSource inputSource = new InputSource(bais); 
+               analysis.parse(inputSource);
+               
+               return analysis;
+       }
+               
+       @Before
+       public void setUp()
+       {
+               m_driver = new DbDriverMock();
+               m_cfb = new CFBMock(Locale.getDefault(), m_driver);
+       }
+       
+       @Test
+       public void testStoreAndReport_noPrior() throws IOException, SQLException, SAXException, TypeMismatchException 
+       {
+               final String PROJECT_NAME = "ProjectName";
+               final String VERSION = "1.0.1";
+               
+               try (
+                               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                               PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, Charset.forName(Command.UTF_8)));
+                       )
+               {
+                       MessageMap msgMap = new MessageMap();
+                       msgMap.parse(new InputSource(new ByteArrayInputStream(MessagesXmlData.XML.getBytes(Command.UTF_8))));
+                       
+                       Analysis analysis = analysisFromXml(BUG_COLLECTION_XML, PROJECT_NAME, VERSION);
+                       
+                       m_cfb.ensureDbInitialized(pw, msgMap);
+                       m_cfb.storeAndReport(pw, msgMap, analysis);
+               }
+               
+               Connection con = m_driver.connect("host", 1234, "dbName", "dbUser", "dbPass");
+               Column[] columns = { CfbSchema.RUNID, CfbSchema.PROJNAME, CfbSchema.VERSION };
+               Table[] tables = { CfbSchema.RUNS };
+               Condition[] conditions = { new Condition(CfbSchema.RUNID, Operation.NOT_NULL) };
+               
+               Row row = m_driver.selectExactlyOne(con, columns, tables, conditions);
+               assertNotNull(row);
+               assertEquals(PROJECT_NAME, row.getValue(1));
+               assertEquals(VERSION, row.getValue(2));
+       }
+}
diff --git a/test/net/jaekl/cfb/CfbBundleMock.java b/test/net/jaekl/cfb/CfbBundleMock.java
new file mode 100644 (file)
index 0000000..71aea1d
--- /dev/null
@@ -0,0 +1,19 @@
+package net.jaekl.cfb;
+
+import java.util.Locale;
+
+public class CfbBundleMock extends CfbBundle {
+       public CfbBundleMock() 
+       {
+               super();
+               synchronized(CfbBundle.class){
+                       m_bundleMap.put(Locale.getDefault(), this);
+               }
+       }
+       
+       @Override 
+       public String get(String key, Object... arguments)
+       {
+               return fallbackGet(key, arguments);
+       }
+}
index 04f1dcd4338d9dab398f884e706460967a3555af..cb2222c77f35d31152852aaa0d3fb093b8cbdfd4 100644 (file)
@@ -44,7 +44,6 @@ public class DeltaTest {
                        + "<SourceLine classname=\"net.jaekl.cfb.CFB\" start=\"101\" end=\"101\" startBytecode=\"46\" endBytecode=\"46\" sourcefile=\"CFB.java\" sourcepath=\"net/jaekl/cfb/CFB.java\" role=\"SOURCE_REDUNDANT_NULL_CHECK\"/>\n"
                        + "</BugInstance>\n";
 
-       /*
        private static String VO_VOLATILE_INCREMENT = ""
                        + "<BugInstance type=\"VO_VOLATILE_INCREMENT\" priority=\"2\" abbrev=\"VO\" category=\"MT_CORRECTNESS\">"
                        + "<Class classname=\"junit.extensions.ActiveTestSuite\">"
@@ -58,7 +57,6 @@ public class DeltaTest {
                        + "</Field>"
                        + "<SourceLine classname=\"junit.extensions.ActiveTestSuite\" start=\"67\" end=\"67\" startBytecode=\"7\" endBytecode=\"7\" sourcefile=\"ActiveTestSuite.java\" sourcepath=\"junit/extensions/ActiveTestSuite.java\"/>"
                        + "</BugInstance>";
-       */
        
        private static final String DM_NUMBER_CTOR_156 = ""
                        + "<BugInstance type=\"DM_NUMBER_CTOR\" priority=\"2\" abbrev=\"Bx\" category=\"PERFORMANCE\">"
@@ -189,7 +187,8 @@ public class DeltaTest {
        }
 
        @Test
-       public void test_computeDeltas() throws FileNotFoundException, IOException, SAXException {
+       public void test_computeDeltas() throws FileNotFoundException, IOException, SAXException 
+       {
                String[][] bugSpecs = {
                                { DM_DEFAULT_ENCODING, "DM_DEFAULT_ENCODING" },
                                { RCN_REDUNDANT_NULL_CHECK, "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" },
@@ -208,4 +207,29 @@ public class DeltaTest {
                }
        }
 
+       @Test
+       public void test_deltaWithNoPrior() throws FileNotFoundException, IOException, SAXException 
+       {
+               String[][] bugSpecs = {
+                               { DM_DEFAULT_ENCODING, "DM_DEFAULT_ENCODING" },
+                               { RCN_REDUNDANT_NULL_CHECK, "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" },
+                               { VO_VOLATILE_INCREMENT, "VO_VOLATILE_INCREMENT" },
+                               { DM_NUMBER_CTOR_156, "DM_NUMBER_CTOR" },
+                               { DM_NUMBER_CTOR_169, "DM_NUMBER_CTOR" }
+               };
+               
+               final String PROJECT_NAME = "AlphaOne";
+               String secondXml = buildXml(bugSpecs, 0, bugSpecs.length - 1);
+               
+               Analysis second = analysisFromXml(secondXml, PROJECT_NAME, "1.0.1");
+               
+               Delta delta = new Delta(null, second);
+               
+               assertNotNull(delta);
+               for (int i = 0; i < bugSpecs.length; ++i) {
+                       assertFalse(contains(delta.getCommon(), bugSpecs[i][1]));
+                       assertFalse(contains(delta.getFixed(), bugSpecs[i][1]));
+                       assertTrue(contains(delta.getNew(), bugSpecs[i][1]));
+               }
+       }
 }
index b25a3fc0955f394c64fe783c91af77e6334c4454..7734b88da490c43107212665faea0af19a796e1b 100644 (file)
@@ -229,8 +229,7 @@ public class ConnectionMock implements Connection {
 
        @Override
        public PreparedStatement prepareStatement(String sql) throws SQLException {
-               // TODO Auto-generated method stub
-               return null;
+               throw new UnsupportedOperationException("Not yet implemented");
        }
 
        @Override
index bb4675a2ff345fefb3b78827c45a625b0220d396..927f2768a5bc5b0f32fac9f9aba2afbb0d1c59ad 100644 (file)
@@ -25,13 +25,15 @@ import net.jaekl.cfb.util.Util;
 
 public class DbDriverMock extends DbDriver {
 
-       private HashMap<String, TableMock> m_tables;
+       private ArrayList<ConnectionMock> m_cons;
        private HashMap<String, SequenceMock> m_sequences;
+       private HashMap<String, TableMock> m_tables;
        
        public DbDriverMock() {
                super();
-               m_tables = new HashMap<String, TableMock>();
+               m_cons = new ArrayList<ConnectionMock>();
                m_sequences = new HashMap<String, SequenceMock>();
+               m_tables = new HashMap<String, TableMock>();
        }
 
        @Override
@@ -43,7 +45,9 @@ public class DbDriverMock extends DbDriver {
        public Connection connect(String host, int port, String dbName, String user, String pass) 
                throws SQLException 
        {
-               return null;
+               ConnectionMock con = new ConnectionMock();
+               m_cons.add(con);
+               return con;
        }
        
        @Override