Work toward improving solidity. Add a few more unit tests, and some toString()
authorChris Jaekl <cejaekl@yahoo.com>
Sun, 27 Dec 2015 13:13:17 +0000 (22:13 +0900)
committerChris Jaekl <cejaekl@yahoo.com>
Sun, 27 Dec 2015 13:13:17 +0000 (22:13 +0900)
methods that make debugging variable dumps more useful.

prod/net/jaekl/cfb/analyze/Analysis.java
prod/net/jaekl/cfb/db/Condition.java
prod/net/jaekl/cfb/db/Row.java
prod/net/jaekl/cfb/util/Util.java
prod/net/jaekl/cfb/xml/BugCollection.java
test/net/jaekl/cfb/db/TableMock.java
test/net/jaekl/cfb/db/driver/DbDriverMock.java
test/net/jaekl/cfb/store/DbStoreTest.java [new file with mode: 0644]
test/net/jaekl/cfb/util/UtilTest.java [new file with mode: 0644]

index 81f4b89bad189a0722e89a2c28d3ebdd99d9636f..d720184b22326325ba3706df619a3c9d7e6a61de 100644 (file)
@@ -31,6 +31,7 @@ public class Analysis {
                m_buildNumber = buildNumber;
                m_start = new Date().getTime();
                m_end = 0;
+               m_bugCollection = new BugCollection();
        }
        
        public BugCollection getBugCollection() { return m_bugCollection; }
index 98bd5f26f165c24b29f3c317a2c772c56aaea87e..75bfe2955eed3d632f01e94b2181443fe0d46838 100644 (file)
@@ -30,4 +30,9 @@ public class Condition {
        public Column getColumn() { return m_column; }
        public Object getValue() { return m_value; }
        public Operation getOperation() { return m_operation; }
+       
+       @Override
+       public String toString() {
+               return ("(" + m_column.getName() + " " + m_operation + " " + m_value + ")");
+       }
 }
index 35bf1215c28da38aac5b237b815e5e6c8d5136c0..2200aa1def770bde6b4a75fa3039e2ab9cdcc7b1 100644 (file)
@@ -14,6 +14,10 @@ public class Row {
        public int getNumColumns() { return m_columns.length; }
        public Column getColumn(int idx) { return m_columns[idx]; }
        
+       public Object getValue(int index) {
+               return m_values[index];
+       }
+       
        public String getString(int index) throws TypeMismatchException {
                checkType(index, Column.Type.VARCHAR);
                return (String)m_values[index];
@@ -43,6 +47,20 @@ public class Row {
                return (java.util.Date)m_values[index];
        }
        
+       @Override
+       public String toString() 
+       {
+               StringBuilder sb = new StringBuilder("[");
+               for (int idx = 0; idx < m_columns.length; ++idx) {
+                       if (idx > 0) {
+                               sb.append(", ");
+                       }
+                       sb.append("" + m_columns[idx].getName() + "=" + m_values[idx]);
+               }
+               sb.append("]");
+               return sb.toString();
+       }
+       
        protected void checkType(int index, Column.Type type) throws TypeMismatchException {
                Column column = m_columns[index];
                Column.Type columnType = column.getType();
index 309e20dde6e74fd672074cde15ad87aa041a6803..d1e79bdaa0742c45bb763c302d7404aaa6d44216 100644 (file)
@@ -4,14 +4,38 @@ package net.jaekl.cfb.util;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.util.Iterator;
+import java.util.List;
 
 public class Util {
-       public static String stringify(Throwable thr) 
+       // Returns true iff. a and b contain equal items in the same order
+       public static boolean listsAreEqual(List<?> a, List<?> b)
        {
-               StringWriter sw = new StringWriter();
-               PrintWriter pw = new PrintWriter(sw);
-               thr.printStackTrace(pw);
-               return sw.toString();
+               if ((null == a) || (null == b)) {
+                       return (a == b);
+               }
+               
+               if (0 == a.size()) {
+                       return (0 == b.size());
+               }
+               
+               if (a.size() != b.size()) {
+                       return false;
+               }
+               
+               Iterator<?> iterA = a.iterator();
+               Iterator<?> iterB = b.iterator();
+               
+               while (iterA.hasNext()) {
+                       Object elemA = iterA.next();
+                       Object elemB = iterB.next();
+                       
+                       if (! objsAreEqual(elemA, elemB)) {
+                               return false;
+                       }
+               }
+               
+               return true;
        }
        
        // Test for equality, while taking care to avoid 
@@ -34,4 +58,14 @@ public class Util {
                }
                return obj.hashCode();
        }
+       
+       // Convert a Throwable to the string representation 
+       // that is generated by printStackTrace().
+       public static String stringify(Throwable thr) 
+       {
+               StringWriter sw = new StringWriter();
+               PrintWriter pw = new PrintWriter(sw);
+               thr.printStackTrace(pw);
+               return sw.toString();
+       }       
 }
index 98ea93b422446de826716cbcce8f0da8511a3518..0ce05ecaa888a18455c07db4e401e47fd4de4e13 100644 (file)
@@ -5,6 +5,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import net.jaekl.cfb.util.Util;
 import net.jaekl.qd.xml.ParseResult;
 import net.jaekl.qd.xml.XmlParseException;
 
@@ -52,4 +53,16 @@ public class BugCollection extends ParseResult {
                }
        }
 
+       @Override
+       public boolean equals(Object obj) {
+               if (null == obj) {
+                       return false;
+               }
+               if (! (obj instanceof BugCollection)) {
+                       return false;
+               }
+               BugCollection other = (BugCollection)obj;
+               
+               return Util.listsAreEqual(this.m_bugs, other.m_bugs);
+       }
 }
index 1c91115b9fb07e26dd6f985348afd7619c95174f..54fb2d0a20bee7f2d93dd7cf79e86cd371fc5ee8 100644 (file)
@@ -1,7 +1,6 @@
 package net.jaekl.cfb.db;
 
 import java.util.ArrayList;
-
 import static org.junit.Assert.*;
 
 public class TableMock extends Table {
@@ -17,7 +16,7 @@ public class TableMock extends Table {
                this(table.m_name, table.m_columns.toArray(new Column[table.m_columns.size()]));
        }
        
-       protected ArrayList<Row> mock_getRows() { return m_rows; }
+       public ArrayList<Row> mock_getRows() { return m_rows; }
 
        public boolean mock_hasColumn(Column expectedCol) {
                for (Column col : m_columns) {
@@ -39,4 +38,15 @@ public class TableMock extends Table {
                }
                m_rows.add(row);
        }
+       
+       @Override
+       public String toString()
+       {
+               StringBuilder sb = new StringBuilder("" + getName() + "={\n");
+               for (Row row : m_rows) {
+                       sb.append("" + row + "\n");
+               }
+               sb.append("}");
+               return sb.toString();
+       }
 }
index 75813b929e937d5065d289a983dbbfc363ad907c..86ae18c1785bcbbd454ba425573bdae0eb330a14 100644 (file)
@@ -8,6 +8,7 @@ import static org.junit.Assert.assertTrue;
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 
@@ -19,6 +20,7 @@ import net.jaekl.cfb.db.SequenceMock;
 import net.jaekl.cfb.db.Sort;
 import net.jaekl.cfb.db.Table;
 import net.jaekl.cfb.db.TableMock;
+import net.jaekl.cfb.db.TypeMismatchException;
 
 public class DbDriverMock extends DbDriver {
 
@@ -104,8 +106,109 @@ public class DbDriverMock extends DbDriver {
                assertNotNull(columns);
                assertNotNull(tables);
                
-               // TODO:  produce sensible output
-               return new ArrayList<Row>();
+               if (1 != tables.length) {
+                       throw new UnsupportedOperationException("DbDriverMock does not (yet) implement table joins");
+               }
+               
+               Table schemaTable = tables[0];
+               TableMock table = m_tables.get(schemaTable.getName());
+               if (null == table) {
+                       throw new SQLException("Could not find table \"" + schemaTable.getName() + "\" in schema.");
+               }
+               
+               ArrayList<Row> rows = table.mock_getRows();
+               if (null != conditions) {
+                       ArrayList<Row> filteredRows = new ArrayList<Row>();
+                       for (Row row : rows) {
+                               boolean match = true;
+                               for (Condition condition : conditions) {
+                                       try {
+                                               if (!conditionSatisfied(condition, row)) {
+                                                       match = false;
+                                               }
+                                       }
+                                       catch (TypeMismatchException exc) {
+                                               throw new SQLException(exc);
+                                       }
+                               }
+                               if (match) {
+                                       filteredRows.add(row);
+                               }
+                       }
+                       rows = filteredRows;
+               }
+               
+               ArrayList<Row> result = new ArrayList<Row>();
+               
+               // Now, convert the rows from select(*) to select(specified columns)
+               for (Row row : rows) {
+                       Object[] values = new Object[columns.length];
+                       
+                       for (int outIdx = 0; outIdx < columns.length; ++outIdx) {
+                               for (int inIdx = 0; inIdx < row.getNumColumns(); ++inIdx) {
+                                       if (row.getColumn(inIdx).getName().equals(columns[outIdx].getName())) {
+                                               values[outIdx] = row.getValue(inIdx);
+                                       }
+                               }
+                       }
+                       result.add(new Row(columns, values));
+               }
+               
+               return result;
+       }
+       
+       private boolean aLessThanB(Object a, Object b) 
+       {
+               if ((null == a) || (null == b)) {
+                       return false;
+               }
+               
+               if (a instanceof Number) {
+                       if (! (b instanceof Number)) {
+                               throw new UnsupportedOperationException("Incompatible types");
+                       }
+                       Number first = (Number)a;
+                       Number second = (Number)b;
+                       return first.doubleValue() < second.doubleValue();
+               }
+               
+               if (a instanceof Date) {
+                       if (! (b instanceof Date)) {
+                               throw new UnsupportedOperationException("Incompatible types");
+                       }
+                       Date first = (Date)a;
+                       Date second = (Date)b;
+                       int comp = first.compareTo(second);
+                       boolean result = (comp < 0);
+                       
+                       return (result);
+               }
+               
+               throw new UnsupportedOperationException("Incompatible types");
+       }
+       
+       private boolean conditionSatisfied(Condition condition, Row row) throws TypeMismatchException, SQLException
+       {
+               for (int idx = 0; idx < row.getNumColumns(); ++idx) {
+                       Column col = row.getColumn(idx);
+                       if (condition.getColumn().equals(col)) {
+                               switch(condition.getOperation()) {
+                               case EQUAL:
+                                       return (condition.getValue().equals(row.getValue(idx)));
+                               case GREATER_THAN:
+                                       return (aLessThanB(condition.getValue(), row.getValue(idx)));
+                               case LESS_THAN:
+                                       return (aLessThanB(row.getValue(idx), condition.getValue()));
+                               case NOT_NULL:
+                                       return (null != row.getValue(idx));
+                               case NULL:
+                                       return (null == row.getValue(idx));
+                               default:
+                                       throw new UnsupportedOperationException("This condition operation is not supported by DbDriverMock");
+                               }
+                       }
+               }
+               throw new SQLException("Could not locate column \"" + condition.getColumn().getName() + "\" in TableMock.");
        }
        
        // Returns the number of rows inserted
diff --git a/test/net/jaekl/cfb/store/DbStoreTest.java b/test/net/jaekl/cfb/store/DbStoreTest.java
new file mode 100644 (file)
index 0000000..c4e2668
--- /dev/null
@@ -0,0 +1,163 @@
+package net.jaekl.cfb.store;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.sql.SQLException;
+import java.util.Date;
+
+import net.jaekl.cfb.analyze.Analysis;
+import net.jaekl.cfb.analyze.MessageMap;
+import net.jaekl.cfb.db.CfbSchema;
+import net.jaekl.cfb.db.TypeMismatchException;
+import net.jaekl.cfb.db.driver.ConnectionMock;
+import net.jaekl.cfb.db.driver.DbDriverMock;
+import net.jaekl.cfb.xml.MessagesXmlData;
+import net.jaekl.cfb.xml.messages.MessageCollection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class DbStoreTest {
+       private DbStore m_store;
+       
+       @Before
+       public void setUp() throws SQLException, FileNotFoundException, UnsupportedEncodingException, IOException, SAXException 
+       {
+               MessageMap msgMap = new MessageMap();
+               msgMap.parse(new InputSource(new ByteArrayInputStream(MessagesXmlData.XML.getBytes("UTF-8"))));
+               
+               DbDriverMock driver = new DbDriverMock();
+               CfbSchema schema = new CfbSchema(driver);
+               ConnectionMock con = new ConnectionMock();
+
+               schema.setMessageMap(msgMap);
+               schema.ensureDbInitialized(con);                
+
+               MessageCollection msgColl = new MessageCollection();
+               m_store = new DbStore(con, driver, msgColl);
+       }
+
+       @Test
+       public void testGetPrior_withNoEntries() throws SQLException, TypeMismatchException {
+               // First test:  getPrior(null) should return null
+               Analysis actual = m_store.getPrior(null);
+               assertNull(actual);
+               
+               // Second test:  getPrior(current) with no data in the DB should return null
+               String projName = "ProjectName";
+               String version = "1.2.3";
+               Date start = new Date(1234567890);
+               Date end = new Date(1234567900);
+               Analysis current = new Analysis(projName, version);
+               current.setStart(start);
+               current.setEnd(end);
+               actual = m_store.getPrior(current);
+               assertNull(actual);
+       }
+
+       @Test
+       public void testPut_thenGetPrior() throws SQLException, TypeMismatchException {
+               String projName = "ProjectName";
+               String firstVersion = "1.0.1";
+               Date firstStart = new Date(100);
+               Date firstEnd = new Date(200);
+               Analysis firstAnalysis = new Analysis(projName, firstVersion);
+               firstAnalysis.setStart(firstStart);
+               firstAnalysis.setEnd(firstEnd);
+               
+               boolean result = m_store.put(firstAnalysis);
+               assertTrue(result);
+               
+               String secondVersion = "1.0.2";
+               Date secondStart = new Date(2300);
+               Date secondEnd = new Date(2400);
+               Analysis secondAnalysis = new Analysis(projName, secondVersion);
+               secondAnalysis.setStart(secondStart);
+               secondAnalysis.setEnd(secondEnd);
+               
+               Analysis priorAnalysis = m_store.getPrior(secondAnalysis);
+               assertNotNull(priorAnalysis);
+               assertEquals(firstAnalysis.getProjectName(), priorAnalysis.getProjectName());
+               assertEquals(firstAnalysis.getBuildNumber(), priorAnalysis.getBuildNumber());
+               assertEquals(firstAnalysis.getStart(), priorAnalysis.getStart());
+               assertEquals(firstAnalysis.getEnd(), priorAnalysis.getEnd());
+               assertEquals(firstAnalysis.getBugCollection(), priorAnalysis.getBugCollection());
+       }
+/*
+       @Test
+       public void testGetBugType() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetCategoryName() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetLoc() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetLocId() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testFindLocId() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testStoreLoc() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetVarIdBugInstance() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetVar() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetVarIdLocalVariable() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testFindVarId() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testStoreVar() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetPriorId() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetAnalysis() {
+               fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetBugCollection() {
+               fail("Not yet implemented");
+       }
+*/
+}
diff --git a/test/net/jaekl/cfb/util/UtilTest.java b/test/net/jaekl/cfb/util/UtilTest.java
new file mode 100644 (file)
index 0000000..beaa926
--- /dev/null
@@ -0,0 +1,69 @@
+package net.jaekl.cfb.util;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+public class UtilTest {
+       @Test
+       public void testListsAreEqual()
+       {
+               Object[][][] equal = {
+                               {
+                                       null,
+                                       null
+                               },
+                               {
+                                       { "one", "two", "three" },
+                                       { "one", "two", "three" }
+                               },
+                               {
+                                       { Integer.valueOf(1), Integer.valueOf(2048), Integer.valueOf(3) },
+                                       { Integer.valueOf(1), Integer.valueOf(2048), Integer.valueOf(3) }
+                               }
+               };
+               Object[][][] unequal = {
+                               {
+                                       null,
+                                       { "one", "two", "three" }
+                               },
+                               {
+                                       { "1", "1", "2" },
+                                       { "1", "2", "1" }
+                               },
+                               {
+                                       { "1", "1", "2" },
+                                       { "1", "2", "2" }
+                               },
+                               {
+                                       { "1", "1", "2" },
+                                       { "1", "2" }
+                               },
+                               {
+                                       { "1", "2", "3" },
+                                       { Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3) }
+                               },
+                               {
+                                       { Integer.valueOf(1), Integer.valueOf(2048), Integer.valueOf(3) },
+                                       { Integer.valueOf(1), Integer.valueOf(2048), Long.valueOf(3) }
+                               }
+               };
+
+               for (Object[][] lists : equal) {
+                       List<?> a = (null == lists[0]) ? null : Arrays.asList(lists[0]);
+                       List<?> b = (null == lists[1]) ? null : Arrays.asList(lists[1]);
+                       boolean result = Util.listsAreEqual(a, b);
+                       assertTrue(result);
+               }
+               
+               for (Object[][] lists : unequal) {
+                       List<?> a = (null == lists[0]) ? null : Arrays.asList(lists[0]);
+                       List<?> b = (null == lists[1]) ? null : Arrays.asList(lists[1]);
+                       boolean result = Util.listsAreEqual(a, b);
+                       assertFalse(result);
+               }
+       }
+}