1/*
2 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package test.rowset;
24
25import java.io.InputStream;
26import java.io.Reader;
27import java.io.StringBufferInputStream;
28import java.io.StringReader;
29import java.math.BigDecimal;
30import java.sql.Array;
31import java.sql.Blob;
32import java.sql.Clob;
33import java.sql.Date;
34import java.sql.Ref;
35import java.sql.SQLException;
36import java.sql.Time;
37import java.sql.Timestamp;
38import java.sql.Types;
39import java.time.LocalDate;
40import java.time.LocalDateTime;
41import java.time.LocalTime;
42import java.util.Calendar;
43import javax.sql.RowSet;
44import javax.sql.rowset.serial.SerialArray;
45import javax.sql.rowset.serial.SerialBlob;
46import javax.sql.rowset.serial.SerialClob;
47import javax.sql.rowset.serial.SerialRef;
48import static org.testng.Assert.*;
49import org.testng.annotations.DataProvider;
50import org.testng.annotations.Test;
51import util.StubArray;
52import util.StubBaseRowSet;
53import util.StubBlob;
54import util.StubClob;
55import util.StubRef;
56import util.TestRowSetListener;
57
58public class BaseRowSetTests extends CommonRowSetTests {
59
60    private StubBaseRowSet brs;
61
62    @Override
63    protected RowSet newInstance() throws SQLException {
64        return new StubBaseRowSet();
65    }
66
67    /*
68     * Create a RowSetListener and validate that notifyCursorMoved is called
69     */
70    @Test(dataProvider = "rowSetType")
71    public void baseRowSetTest0000(StubBaseRowSet rs) throws Exception {
72        TestRowSetListener rsl = new TestRowSetListener();
73        rs.addRowSetListener(rsl);
74        rs.notifyCursorMoved();
75        assertTrue(rsl.isNotified(TestRowSetListener.CURSOR_MOVED));
76    }
77
78    /*
79     * Create a RowSetListener and validate that notifyRowChanged is called
80     */
81    @Test(dataProvider = "rowSetType")
82    public void baseRowSetTest0001(StubBaseRowSet rs) throws Exception {
83        TestRowSetListener rsl = new TestRowSetListener();
84        rs.addRowSetListener(rsl);
85        rs.notifyRowChanged();
86        assertTrue(rsl.isNotified(TestRowSetListener.ROW_CHANGED));
87    }
88
89    /*
90     * Create a RowSetListener and validate that notifyRowSetChanged is called
91     */
92    @Test(dataProvider = "rowSetType")
93    public void baseRowSetTest0002(StubBaseRowSet rs) throws Exception {
94        TestRowSetListener rsl = new TestRowSetListener();
95        rs.addRowSetListener(rsl);
96        rs.notifyRowSetChanged();
97        assertTrue(rsl.isNotified(TestRowSetListener.ROWSET_CHANGED));
98    }
99
100    /*
101     * Create multiple RowSetListeners and validate that notifyRowSetChanged
102     * is called on all listeners
103     */
104    @Test(dataProvider = "rowSetType")
105    public void baseRowSetTest0003(StubBaseRowSet rs) throws Exception {
106        TestRowSetListener rsl = new TestRowSetListener();
107        TestRowSetListener rsl2 = new TestRowSetListener();
108        rs.addRowSetListener(rsl);
109        rs.addRowSetListener(rsl2);
110        rs.notifyRowSetChanged();
111        assertTrue(rsl.isNotified(TestRowSetListener.ROWSET_CHANGED));
112        assertTrue(rsl2.isNotified(TestRowSetListener.ROWSET_CHANGED));
113    }
114
115    /*
116     * Create multiple RowSetListeners and validate that notifyRowChanged
117     * is called on all listeners
118     */
119    @Test(dataProvider = "rowSetType")
120    public void baseRowSetTest0004(StubBaseRowSet rs) throws Exception {
121        TestRowSetListener rsl = new TestRowSetListener();
122        TestRowSetListener rsl2 = new TestRowSetListener();
123        rs.addRowSetListener(rsl);
124        rs.addRowSetListener(rsl2);
125        rs.notifyRowChanged();
126        assertTrue(rsl.isNotified(TestRowSetListener.ROW_CHANGED));
127        assertTrue(rsl2.isNotified(TestRowSetListener.ROW_CHANGED));
128    }
129
130    /*
131     * Create multiple RowSetListeners and validate that notifyCursorMoved
132     * is called on all listeners
133     */
134    @Test(dataProvider = "rowSetType")
135    public void baseRowSetTest0005(StubBaseRowSet rs) throws Exception {
136        TestRowSetListener rsl = new TestRowSetListener();
137        TestRowSetListener rsl2 = new TestRowSetListener();
138        rs.addRowSetListener(rsl);
139        rs.addRowSetListener(rsl2);
140        rs.notifyCursorMoved();
141        assertTrue(rsl.isNotified(TestRowSetListener.CURSOR_MOVED));
142        assertTrue(rsl2.isNotified(TestRowSetListener.CURSOR_MOVED));
143    }
144
145    /*
146     * Create a RowSetListener and validate that notifyRowSetChanged,
147     * notifyRowChanged() and notifyCursorMoved are called
148     */
149    @Test(dataProvider = "rowSetType")
150    public void baseRowSetTest0006(StubBaseRowSet rs) throws Exception {
151        TestRowSetListener rsl = new TestRowSetListener();
152        rs.addRowSetListener(rsl);
153        rs.notifyRowSetChanged();
154        rs.notifyRowChanged();
155        rs.notifyCursorMoved();
156        assertTrue(rsl.isNotified(
157                TestRowSetListener.CURSOR_MOVED | TestRowSetListener.ROWSET_CHANGED
158                | TestRowSetListener.ROW_CHANGED));
159    }
160
161
162    /*
163     * Create multiple RowSetListeners and validate that notifyRowSetChanged,
164     * notifyRowChanged() and notifyCursorMoved are called on all listeners
165     */
166    @Test(dataProvider = "rowSetType")
167    public void baseRowSetTest0007(StubBaseRowSet rs) throws Exception {
168        TestRowSetListener rsl = new TestRowSetListener();
169        TestRowSetListener rsl2 = new TestRowSetListener();
170        rs.addRowSetListener(rsl);
171        rs.addRowSetListener(rsl2);
172        rs.notifyRowSetChanged();
173        rs.notifyRowChanged();
174        rs.notifyCursorMoved();
175        assertTrue(rsl.isNotified(
176                TestRowSetListener.CURSOR_MOVED | TestRowSetListener.ROWSET_CHANGED
177                | TestRowSetListener.ROW_CHANGED));
178        assertTrue(rsl2.isNotified(
179                TestRowSetListener.CURSOR_MOVED | TestRowSetListener.ROWSET_CHANGED
180                | TestRowSetListener.ROW_CHANGED));
181    }
182
183    /*
184     * Create a RowSetListener and validate that notifyRowSetChanged is called,
185     * remove the listener, invoke notifyRowSetChanged again and verify the
186     * listner is not called
187     */
188    @Test(dataProvider = "rowSetType")
189    public void baseRowSetTest0008(StubBaseRowSet rs) throws Exception {
190        TestRowSetListener rsl = new TestRowSetListener();
191        rs.addRowSetListener(rsl);
192        rs.notifyRowSetChanged();
193        assertTrue(rsl.isNotified(TestRowSetListener.ROWSET_CHANGED));
194        // Clear the flag indicating the listener has been called
195        rsl.resetFlag();
196        rs.removeRowSetListener(rsl);
197        rs.notifyRowSetChanged();
198        assertFalse(rsl.isNotified(TestRowSetListener.ROWSET_CHANGED));
199    }
200
201    /*
202     * Set the base parameters and validate that the value set is
203     * the correct type and value
204     */
205    @Test(dataProvider = "testBaseParameters")
206    public void baseRowSetTest0009(int pos, Object o) throws Exception {
207        assertTrue(getParam(pos, o).getClass().isInstance(o));
208        assertTrue(o.equals(getParam(pos, o)));
209    }
210
211    /*
212     * Set the complex parameters and validate that the value set is
213     * the correct type
214     */
215    @Test(dataProvider = "testAdvancedParameters")
216    public void baseRowSetTest0010(int pos, Object o) throws Exception {
217        assertTrue(getParam(pos, o).getClass().isInstance(o));
218    }
219
220    /*
221     * Validate setNull specifying the supported type values
222     */
223    @Test(dataProvider = "jdbcTypes")
224    public void baseRowSetTest0011(Integer type) throws Exception {
225        brs = new StubBaseRowSet();
226        brs.setNull(1, type);
227        assertTrue(checkNullParam(1, type, null));
228    }
229
230    /*
231     * Validate setNull specifying the supported type values and that
232     * typeName is set internally
233     */
234    @Test(dataProvider = "jdbcTypes")
235    public void baseRowSetTest0012(Integer type) throws Exception {
236        brs = new StubBaseRowSet();
237        brs.setNull(1, type, "SUPERHERO");
238        assertTrue(checkNullParam(1, type, "SUPERHERO"));
239    }
240
241    /*
242     *  Validate that setDate sets the specified Calendar internally
243     */
244    @Test()
245    public void baseRowSetTest0013() throws Exception {
246        Calendar cal = Calendar.getInstance();
247        brs = new StubBaseRowSet();
248        brs.setDate(1, Date.valueOf(LocalDate.now()), cal);
249        assertTrue(checkCalendarParam(1, cal));
250    }
251
252    /*
253     *  Validate that setTime sets the specified Calendar internally
254     */
255    @Test()
256    public void baseRowSetTest0014() throws Exception {
257        Calendar cal = Calendar.getInstance();
258        brs = new StubBaseRowSet();
259        brs.setTime(1, Time.valueOf(LocalTime.now()), cal);
260        assertTrue(checkCalendarParam(1, cal));
261    }
262
263    /*
264     *  Validate that setTimestamp sets the specified Calendar internally
265     */
266    @Test()
267    public void baseRowSetTest0015() throws Exception {
268        Calendar cal = Calendar.getInstance();
269        brs = new StubBaseRowSet();
270        brs.setTimestamp(1, Timestamp.valueOf(LocalDateTime.now()), cal);
271        assertTrue(checkCalendarParam(1, cal));
272    }
273
274    /*
275     * Validate that initParams() initializes the parameters
276     */
277    @Test(dataProvider = "rowSetType")
278    public void baseRowSetTest0016(StubBaseRowSet rs) throws Exception {
279        rs.setInt(1, 1);
280        rs.initParams();
281        assertTrue(rs.getParams().length == 0);
282    }
283
284
285    /*
286     * DataProvider used to set parameters for basic types that are supported
287     */
288    @DataProvider(name = "testBaseParameters")
289    private Object[][] testBaseParameters() throws SQLException {
290        Integer aInt = 1;
291        Long aLong = Long.MAX_VALUE;
292        Short aShort = Short.MIN_VALUE;
293        BigDecimal bd = BigDecimal.ONE;
294        Double aDouble = Double.MAX_VALUE;
295        Date aDate = Date.valueOf(LocalDate.now());
296        Time aTime = Time.valueOf(LocalTime.now());
297        Timestamp aTimeStamp = Timestamp.valueOf(LocalDateTime.now());
298        Calendar cal = Calendar.getInstance();
299        Boolean aBoolean = true;
300        Float aFloat = 1.5f;
301        Byte aByte = 1;
302        brs = new StubBaseRowSet();
303
304        brs.setInt(1, aInt);
305        brs.setString(2, query);
306        brs.setLong(3, aLong);
307        brs.setBoolean(4, aBoolean);
308        brs.setShort(5, aShort);
309        brs.setDouble(6, aDouble);
310        brs.setBigDecimal(7, bd);
311        brs.setFloat(8, aFloat);
312        brs.setByte(9, aByte);
313        brs.setDate(10, aDate);
314        brs.setTime(11, aTime);
315        brs.setTimestamp(12, aTimeStamp);
316        brs.setDate(13, aDate, cal);
317        brs.setTime(14, aTime, cal);
318        brs.setTimestamp(15, aTimeStamp);
319        brs.setObject(16, query);
320        brs.setObject(17, query, Types.CHAR);
321        brs.setObject(18, query, Types.CHAR, 0);
322
323        return new Object[][]{
324            {1, aInt},
325            {2, query},
326            {3, aLong},
327            {4, aBoolean},
328            {5, aShort},
329            {6, aDouble},
330            {7, bd},
331            {8, aFloat},
332            {9, aByte},
333            {10, aDate},
334            {11, aTime},
335            {12, aTimeStamp},
336            {13, aDate},
337            {14, aTime},
338            {15, aTimeStamp},
339            {16, query},
340            {17, query},
341            {18, query}
342
343        };
344    }
345
346    /*
347     * DataProvider used to set advanced parameters for types that are supported
348     */
349    @DataProvider(name = "testAdvancedParameters")
350    private Object[][] testAdvancedParameters() throws SQLException {
351
352        byte[] bytes = new byte[10];
353        Ref aRef = new SerialRef(new StubRef("INTEGER", query));
354        Array aArray = new SerialArray(new StubArray("INTEGER", new Object[1]));
355        Blob aBlob = new SerialBlob(new StubBlob());
356        Clob aClob = new SerialClob(new StubClob());
357        Reader rdr = new StringReader(query);
358        InputStream is = new StringBufferInputStream(query);;
359        brs = new StubBaseRowSet();
360        brs.setBytes(1, bytes);
361        brs.setAsciiStream(2, is, query.length());
362        brs.setRef(3, aRef);
363        brs.setArray(4, aArray);
364        brs.setBlob(5, aBlob);
365        brs.setClob(6, aClob);
366        brs.setBinaryStream(7, is, query.length());
367        brs.setUnicodeStream(8, is, query.length());
368        brs.setCharacterStream(9, rdr, query.length());
369
370        return new Object[][]{
371            {1, bytes},
372            {2, is},
373            {3, aRef},
374            {4, aArray},
375            {5, aBlob},
376            {6, aClob},
377            {7, is},
378            {8, is},
379            {9, rdr}
380        };
381    }
382
383    /*
384     *  Method that returns the specified parameter instance that was set via setXXX
385     *  Note non-basic types are stored as an Object[] where the 1st element
386     *  is the object instnace
387     */
388    @SuppressWarnings("unchecked")
389    private <T> T getParam(int pos, T o) throws SQLException {
390        Object[] params = brs.getParams();
391        if (params[pos - 1] instanceof Object[]) {
392            Object[] param = (Object[]) params[pos - 1];
393            return (T) param[0];
394        } else {
395            return (T) params[pos - 1];
396        }
397    }
398
399    /*
400     * Utility method to validate parameters when the param is an Object[]
401     */
402    private boolean checkParam(int pos, int type, Object val) throws SQLException {
403        boolean result = false;
404        Object[] params = brs.getParams();
405        if (params[pos - 1] instanceof Object[]) {
406            Object[] param = (Object[]) params[pos - 1];
407
408            if (param[0] == null) {
409                // setNull was used
410                if (param.length == 2 && (Integer) param[1] == type) {
411                    result = true;
412                } else {
413                    if (param.length == 3 && (Integer) param[1] == type
414                            && val.equals(param[2])) {
415                        result = true;
416                    }
417                }
418
419            } else if (param[0] instanceof java.util.Date) {
420                // setDate/Time/Timestamp with a Calendar object
421                if (param[1] instanceof Calendar && val.equals(param[1])) {
422                    result = true;
423                }
424            }
425        }
426        return result;
427    }
428
429    /*
430     * Wrapper method for validating that a null was set and the appropriate
431     * type and typeName if applicable
432     */
433    private boolean checkNullParam(int pos, int type, String typeName) throws SQLException {
434        return checkParam(pos, type, typeName);
435    }
436
437    /*
438     *  Wrapper method for validating that a Calander was set
439     */
440    private boolean checkCalendarParam(int pos, Calendar cal) throws SQLException {
441        // 2nd param is ignored when instanceof java.util.Date
442        return checkParam(pos, Types.DATE, cal);
443    }
444}
445