001    package com.mockrunner.jdbc;
002    
003    import com.mockrunner.mock.jdbc.MockResultSet;
004    
005    /**
006     * A <code>ResultSetFactory</code> implementation which will produce 
007     * <code>MockResultSet</code> instances based on information given as 
008     * <code>String</code> arrays.
009     * 
010     * <p>
011     * <code>StringValuesTable</code> and <code>ArrayResultSetFactory</code> can 
012     * provide easy set up of unit test fixtures and assertion of outcomes with the
013     * same data structures, without any need for external sources of test data:
014     * </p>
015     * 
016     * <p>
017     * <pre>
018     *  private static final String _SQL_SELECT_ALL_EMPLOYEES = 
019     *      "SELECT * FROM employee";
020     *  private StringValuesTable <b>_employeeQueryResults</b>;
021     *  ArrayResultSetFactory <b>_arrayResultSetFactory</b>;
022     *  private Employee[] _employees;
023     *  
024     *  protected void setUp() throws Exception {
025     *    super.setUp();
026     *    <b>_employeeQueryResults</b> = new StringValuesTable(
027     *        "employeeQueryResults", 
028     *        new String[] {
029     *            "id", "lastname", "firstname",
030     *        }, 
031     *        new String[][] {
032     *            new String[] {"1", "gibbons", "peter"},
033     *            new String[] {"2", "lumbergh", "bill"},
034     *            new String[] {"3", "waddams", "milton"},
035     *        }
036     *    );
037     *    _employees = new Employee[3] {
038     *        new Employee(
039     *            <b>_employeeQueryResults.getItem(1, "id")</b>,
040     *            <b>_employeeQueryResults.getItem(1, "lastname")</b>,
041     *            <b>_employeeQueryResults.getItem(1, "firstname")</b>,
042     *        ),
043     *        ...
044     *    };
045     *    ...
046     *  }
047     *    
048     *  public void testGetEmployees() throws Exception {
049     *    PreparedStatementResultSetHandler preparedStatementResultSetHandler = 
050     *        getPreparedStatementResultSetHandler();
051     *    <b>_arrayResultSetFactory</b> = 
052     *        new ArrayResultSetFactory(<b>_employeeQueryResults</b>);
053     *    MockResultSet resultSet = 
054     *        preparedStatementResultSetHandler.createResultSet(
055     *            <b>_employeeQueryResults.getName()</b>, 
056     *            <b>arrayResultSetFactory</b>);
057     *    preparedStatementResultSetHandler.prepareResultSet(
058     *        _SQL_SELECT_ALL_EMPLOYEES, resultSet);
059     *        
060     *    // execute query, perhaps calling method on an EmployeeDAO...
061     *    
062     *    assertEquals(
063     *        <b>_employeeQueryResults.getNumberOfRows()</b>, 
064     *        resultsList.size());
065     *    for (int i = 0; i < _employees.length; i++) {
066     *       assertTrue(resultsList.contains(_employees[i]));
067     *    }
068     *    MockResultSet mockResultSet = 
069     *        preparedStatementResultSetHandler.getResultSet(
070     *            SQL_SELECT_ALL_EMPLOYEES);
071     *    int rows = mockResultSet.getRowCount();
072     *    for (int row = 1; row <= rows; row++) {
073     *      verifyResultSetRow(
074     *          <b>_employeeQueryResults.getName()</b>, 
075     *          row, <b>_employeeQueryResults.getRow(row)</b>);
076     *    }
077     *    verifySQLStatementExecuted(_SQL_SELECT_ALL_EMPLOYEES);
078     *    verifyAllResultSetsClosed();
079     *    verifyAllStatementsClosed();
080     *    verifyConnectionClosed();     
081     *  }
082     * </pre>
083     * </p>
084    * 
085     * @author Erick G. Reid
086     */
087    public class ArrayResultSetFactory implements ResultSetFactory
088    {
089        private String[] columnNames = new String[0];
090        private String[][] stringMatrix = new String[0][0];
091    
092        /**
093         * Creates a new <code>ArrayResultSetFactory</code> that will produce
094         * result sets based on information in the given
095         * <code>StringValuesTable</code>.
096         * 
097         * @param stringValuesTable the <code>StringValuesTable</code> to use. This argument
098         *                          cannot be <code>null</code>.
099         */
100        public ArrayResultSetFactory(StringValuesTable stringValuesTable)
101        {
102            if (stringValuesTable != null)
103            {
104                this.stringMatrix = stringValuesTable.getStringMatrix();
105                this.columnNames = stringValuesTable.getColumnNames();
106                return;
107            }
108            throw new IllegalArgumentException("the string table cannot be null");
109        }
110    
111        /**
112         * Creates a new <code>ArrayResultSetFactory</code> with the given matrix
113         * for data representation.
114         * 
115         * @param stringMatrix the data representation for the result sets this factory will
116         *                     produce. This argument cannot be <code>null</code>, must
117         *                     not contain any null values, and each array in the matrix must
118         *                     contain the same number of elements as the first (<code>stringMatrix[0].length == stringMatrix[n].length</code>
119         *                     for any given valid row number, <code>n</code>). Further,
120         *                     this matrix must, at a minimum represent <code>1</code> row
121         *                     and <code>1</code> column of items (<code>stringMatrix.length >= 1</code>,
122         *                     and <code>stringMatrix[0].length >= 1</code>).
123         */
124        public ArrayResultSetFactory(String[][] stringMatrix)
125        {
126            this.stringMatrix = StringValuesTable.verifyStringMatrix(stringMatrix);
127        }
128    
129        /**
130         * Creates a new <code>ArrayResultSetFactory</code> with the given set of
131         * column names and the given matrix for data representation.
132         * 
133         * @param columnNames the column names for the result sets this factory will
134         *                    produce. This argument may be <code>null</code> if no column
135         *                    names are desired, but if a non-<code>null</code> array
136         *                    reference is given, the array cannot contain any
137         *                    <code>null</code> nor duplicate elements, and must have the
138         *                    same number of elements as there are columns in the given
139         *                    string matrix (<code>stringMatrix[n]</code> for any given
140         *                    valid row number, <code>n</code>).
141         * @param stringMatrix the data representation for the result sets this factory will
142         *                     produce. This argument cannot be <code>null</code>, must
143         *                     not contain any null values, and each array in the matrix must
144         *                     contain the same number of elements as the first (<code>stringMatrix[0].length == stringMatrix[n].length</code>
145         *                     for any given valid row number, <code>n</code>). Further,
146         *                     this matrix must, at a minimum represent <code>1</code> row
147         *                     and <code>1</code> column of items (<code>stringMatrix.length >= 1</code>,
148         *                     and <code>stringMatrix[0].length >= 1</code>).
149         */
150        public ArrayResultSetFactory(String[] columnNames, String[][] stringMatrix)
151        {
152            this.stringMatrix = StringValuesTable.verifyStringMatrix(stringMatrix);
153            if (columnNames != null)
154            {
155                this.columnNames = StringValuesTable.verifyColumnNames(columnNames, stringMatrix);
156            }
157        }
158    
159        /**
160         * Returns a <code>MockResultSet</code> with the given ID, containing
161         * values based on the elements given at construction.
162         * 
163         * @param id the ID for the result set. This argument cannot be
164         *           <code>null</code>.
165         */
166        public MockResultSet create(String id)
167        {
168            if (id != null)
169            {
170                MockResultSet resultSet = new MockResultSet(id);
171                if (columnNames != null)
172                {
173                    for (int ii = 0; ii < columnNames.length; ii++)
174                    {
175                        resultSet.addColumn(columnNames[ii]);
176                    }
177                }
178                for (int jj = 0; jj < stringMatrix.length; jj++)
179                {
180                    resultSet.addRow(stringMatrix[jj]);
181                }
182                return resultSet;
183            }
184            throw new IllegalArgumentException("the result set ID cannot be null");
185        }
186    }