adds support for null suppression
[squelch.git] / src / test / java / net / jaekl / squelch / stmt / DescribeTest.java
1 package net.jaekl.squelch.stmt;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertTrue;
6
7 import java.io.ByteArrayOutputStream;
8 import java.io.IOException;
9 import java.io.OutputStreamWriter;
10 import java.io.PrintWriter;
11 import java.nio.charset.StandardCharsets;
12 import java.sql.DatabaseMetaData;
13 import java.sql.SQLException;
14
15 import net.jaekl.squelch.db.DbDriverMock;
16 import net.jaekl.squelch.sql.ConnectionMock;
17 import net.jaekl.squelch.sql.DatabaseMetaDataMock;
18 import net.jaekl.squelch.sql.ResultSetMock;
19 import net.jaekl.squelch.sql.Row;
20
21 import org.junit.Test;
22
23 public class DescribeTest {
24
25         @Test
26         public void testHandles() {
27                 final String[] AFFIRMATIVE = {
28                                 "\\d", "\\d ", " \\d", " \\d ", 
29                                 "describe", "describe ", " describe", " describe ",
30                                 "DESCRIBE", "DESCRIBE ", " DESCRIBE", " DESCRIBE ",
31                                 "descRIbe", "DEscribE ", " DEScribe", " DEscRIbE ",
32                                 "\\d tablename", "\\d tablename ", " \\d tablename", " \\d tableName ",
33                                 "describe tablename", "DESCRIBE tablename ", " DesCrIbE tablename", " DESCribE fred "
34                 };
35                 final String[] NEGATIVE = {
36                                 "\\d\\q", "", null, "    ", "select * from foo", "  select * from foo ",
37                                 "DESCRIBEQ", "describeFOO", " describeJackAndDianne "
38                 };
39
40                 Describe describe = new Describe();
41                 for (String s : AFFIRMATIVE) {
42                         assertTrue("handles " + s, describe.handles(s));
43                 }
44                 for (String s : NEGATIVE) {
45                         assertFalse("does not handle " + s, describe.handles(s));
46                 }
47         }
48
49         @Test
50         public void testDescribeAll_noTables() throws IOException, SQLException 
51         {
52                 DatabaseMetaDataMock dbmdm = new DatabaseMetaDataMock();
53                 DbDriverMock driver = new DbDriverMock();
54                 Describe describe = new Describe();
55                 
56                 try (
57                                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
58                                 PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8));
59                         )
60                 {
61                         describe.describeAll(driver, pw, dbmdm);
62                         pw.close();
63                         baos.close();
64                         String actual = baos.toString();
65                         final String EXPECTED = "???\n";
66                         assertEquals(EXPECTED, actual);
67                 }
68         }
69
70         @Test
71         public void testDescribeTable_noColumns()
72                 throws IOException, SQLException
73         {
74                 DatabaseMetaDataMock dbmdm = new DatabaseMetaDataMock();
75                 DbDriverMock driver = new DbDriverMock();
76                 Describe describe = new Describe();
77                 
78                 try (
79                                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
80                                 PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8));
81                         )
82                 {
83                         describe.describeTable(driver, pw, dbmdm, "%");
84                         pw.close();
85                         baos.close();
86                         String actual = baos.toString();
87                         final String EXPECTED = "??? %\n";
88                         assertEquals(EXPECTED, actual);
89                 }
90         }
91         
92         private DatabaseMetaDataMock construct_runs_dbmdm()
93         {
94                 ResultSetMock rsmCols = new ResultSetMock();
95                 ResultSetMock rsmTables = new ResultSetMock();
96
97                 DatabaseMetaDataMock dbmdm = new DatabaseMetaDataMock();
98                 Row[] rows = {
99                                 new Row(new Object[]{
100                                                 null,           // 1) table_cat
101                                                 "public",       // 2) table schema
102                                                 "runs",         // 3) table name
103                                                 "runid",        // 4) column name
104                                                 Integer.valueOf(4),             // 5) data type
105                                                 "int4",         // 6) type name
106                                                 Integer.valueOf(10),    // 7) column size
107                                                 null,           // 8) buffer length
108                                                 null,           // 9) decimal digits
109                                                 Integer.valueOf(10),    // 10) num_prec_radix
110                                                 Integer.valueOf(DatabaseMetaData.columnNoNulls),        // 11) nullable
111                                                 null,           // 12) remarks
112                                                 null,           // 13) default value for the column
113                                                 Integer.valueOf(0),     // 14) sql_data_type
114                                                 Integer.valueOf(0),     // 15) sql_datetime_sub
115                                                 null,           // 16) char_octet_length
116                                                 Integer.valueOf(1),     // 17) ordinal_position
117                                                 "NO",           // 18) is_nullable
118                                                 null,           // 19) scope_catalog
119                                                 null,           // 20) scope_schema
120                                                 null,           // 21) scope_table
121                                                 null,           // 22) source_data_type
122                                                 "NO",           // 23) is_autoincrement
123                                                 "NO"            // 24) is_generated_column
124                                 }),
125                                 new Row(new Object[]{
126                                                 null,           // 1) table_cat
127                                                 "public",       // 2) table schema
128                                                 "runs",         // 3) table name
129                                                 "projname",     // 4) column name
130                                                 Integer.valueOf(12),    // 5) data type
131                                                 "varchar",      // 6) type name
132                                                 Integer.valueOf(80),    // 7) column size
133                                                 null,           // 8) buffer length
134                                                 null,           // 9) decimal digits
135                                                 Integer.valueOf(10),    // 10) num_prec_radix
136                                                 Integer.valueOf(DatabaseMetaData.columnNoNulls),        // 11) nullable
137                                                 null,           // 12) remarks
138                                                 null,           // 13) default value for the column
139                                                 Integer.valueOf(0),     // 14) sql_data_type
140                                                 Integer.valueOf(0),     // 15) sql_datetime_sub
141                                                 null,           // 16) char_octet_length
142                                                 Integer.valueOf(2),     // 17) ordinal_position
143                                                 "NO",           // 18) is_nullable
144                                                 null,           // 19) scope_catalog
145                                                 null,           // 20) scope_schema
146                                                 null,           // 21) scope_table
147                                                 null,           // 22) source_data_type
148                                                 "NO",           // 23) is_autoincrement
149                                                 "NO"            // 24) is_generated_column
150                                 }),
151                                 new Row(new Object[]{
152                                                 null,           // 1) table_cat
153                                                 "public",       // 2) table schema
154                                                 "runs",         // 3) table name
155                                                 "version",      // 4) column name
156                                                 Integer.valueOf(12),    // 5) data type
157                                                 "varchar",      // 6) type name
158                                                 Integer.valueOf(10),    // 7) column size
159                                                 null,           // 8) buffer length
160                                                 null,           // 9) decimal digits
161                                                 Integer.valueOf(10),    // 10) num_prec_radix
162                                                 Integer.valueOf(DatabaseMetaData.columnNullable),       // 11) nullable
163                                                 null,           // 12) remarks
164                                                 null,           // 13) default value for the column
165                                                 Integer.valueOf(0),     // 14) sql_data_type
166                                                 Integer.valueOf(0),     // 15) sql_datetime_sub
167                                                 null,           // 16) char_octet_length
168                                                 Integer.valueOf(1),     // 17) ordinal_position
169                                                 "YES",          // 18) is_nullable
170                                                 null,           // 19) scope_catalog
171                                                 null,           // 20) scope_schema
172                                                 null,           // 21) scope_table
173                                                 null,           // 22) source_data_type
174                                                 "NO",           // 23) is_autoincrement
175                                                 "NO"            // 24) is_generated_column
176                                 })
177                 };
178                 rsmCols.mock_addRows(rows);
179                 
180                 rows = new Row[] {
181                         new Row(new Object[]{
182                                 null,    // TABLE_CAT String => table catalog (may be null)
183                                 null,    // TABLE_SCHEM String => table schema (may be null)
184                                 "runs",  // TABLE_NAME String => table name
185                                 "TABLE", // TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
186                                 "",     // REMARKS String => explanatory comment on the table
187                                 null,   // TYPE_CAT String => the types catalog (may be null)
188                                 null,   // TYPE_SCHEM String => the types schema (may be null)
189                                 null,   // TYPE_NAME String => type name (may be null)
190                                 null,   // SELF_REFERENCING_COL_NAME String => name of the designated "identifier" column of a typed table (may be null)
191                                 null    // REF_GENERATION String => specifies how values in SELF_REFERENCING_COL_NAME are created. Values are "SYSTEM", "USER", "DERIVED". (may be null) 
192                         })      
193                 };
194                 rsmTables.mock_addRows(rows);
195                 
196                 dbmdm.mock_setColRS(null, null, "runs", null, rsmCols);
197                 dbmdm.mock_setTableRS(null, null, "runs", null, rsmTables);
198                 
199                 return dbmdm;
200         }
201         
202         private String construct_runs_expected() {
203                 return   "TABLE runs\n"
204                    + "+----------+-------------+-----------+\n"
205                    + "|  Column  |    Type     | Modifiers |\n"
206                    + "+----------+-------------+-----------+\n"
207                    + "| runid    | int4(10)    | NOT NULL  |\n"
208                    + "| projname | varchar(80) | NOT NULL  |\n"
209                    + "| version  | varchar(10) | NULL      |\n"
210                    + "+----------+-------------+-----------+\n"
211                    + "3 row(s) returned.\n";
212         }
213
214         @Test
215         public void testDescribeTable_threeColumns()
216                 throws IOException, SQLException
217         {
218                 DatabaseMetaDataMock dbmdm = construct_runs_dbmdm();
219                 DbDriverMock driver = new DbDriverMock();
220                 Describe describe = new Describe();
221                 
222                 try (
223                                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
224                                 PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8));
225                         )
226                 {
227                         describe.describeTable(driver, pw, dbmdm, "runs");
228                         pw.close();
229                         baos.close();
230                         String actual = baos.toString();
231                         String expected = construct_runs_expected();
232                         
233                         assertEquals(expected, actual);
234                 }
235         }
236         
237         @Test
238         public void testExec() throws IOException, SQLException
239         {
240                 final String[] SUCCESSFUL = { 
241                                 "\\d runs", " \\d runs", "\\d runs ", " \\d runs ",
242                                 "DESCRIBE runs", " DescRIBe runs", "describe runs ", " describe runs "
243                 };
244                 String expected = construct_runs_expected();
245                 for (String stmt : SUCCESSFUL) {
246                         String actual = doExec(stmt);
247                         assertEquals("doExec():  " + stmt, expected, actual);
248                 }
249         }
250         
251         public String doExec(String stmt) throws IOException, SQLException
252         {
253                 DatabaseMetaDataMock dbmdm = construct_runs_dbmdm();
254                 DbDriverMock driver = new DbDriverMock();
255                 ConnectionMock cm = new ConnectionMock();
256                 cm.mock_setDatabaseMetaData(dbmdm);
257                 
258                 Describe describe = new Describe();
259
260                 try (
261                                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
262                                 PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8));
263                         )
264                 {
265                         describe.exec(driver, cm, pw, stmt);
266                         pw.close();
267                         baos.close();
268                         String actual = baos.toString();
269                         
270                         return actual;
271                 }
272         }
273 }