github.com/mithrandie/csvq@v1.18.1/lib/query/table_path_test.go (about) 1 package query 2 3 import ( 4 "context" 5 "reflect" 6 "testing" 7 8 "github.com/mithrandie/csvq/lib/parser" 9 ) 10 11 var parseTableNameTests = []struct { 12 Table parser.Table 13 Result string 14 Error string 15 }{ 16 { 17 Table: parser.Table{ 18 Object: parser.Identifier{Literal: "table.csv"}, 19 As: parser.Token{Token: parser.AS, Literal: "as"}, 20 Alias: parser.Identifier{Literal: "alias"}, 21 }, 22 Result: "alias", 23 }, 24 { 25 Table: parser.Table{ 26 Object: parser.Identifier{Literal: "/path/to/table.csv"}, 27 }, 28 Result: "table", 29 }, 30 { 31 Table: parser.Table{ 32 Object: parser.Stdin{}, 33 }, 34 Result: "STDIN", 35 }, 36 { 37 Table: parser.Table{ 38 Object: parser.Subquery{ 39 Query: parser.SelectQuery{ 40 SelectEntity: parser.SelectEntity{ 41 SelectClause: parser.SelectClause{ 42 Fields: []parser.QueryExpression{ 43 parser.NewIntegerValueFromString("1"), 44 }, 45 }, 46 FromClause: parser.FromClause{ 47 Tables: []parser.QueryExpression{parser.Dual{}}, 48 }, 49 }, 50 }, 51 }, 52 }, 53 Result: "", 54 }, 55 { 56 Table: parser.Table{ 57 Object: parser.FormatSpecifiedFunction{ 58 Type: parser.Token{Token: parser.FIXED, Literal: "fixed"}, 59 FormatElement: parser.NewStringValue("[1, 2, 3]"), 60 Path: parser.Identifier{Literal: "fixed_length.dat", Quoted: true}, 61 Args: nil, 62 }, 63 }, 64 Result: "fixed_length", 65 }, 66 { 67 Table: parser.Table{ 68 Object: parser.TableFunction{ 69 Name: "file", 70 Args: []parser.QueryExpression{parser.NewStringValue("table.csv")}, 71 }, 72 }, 73 Result: "table", 74 }, 75 { 76 Table: parser.Table{ 77 Object: parser.TableFunction{ 78 Name: "file", 79 }, 80 }, 81 Error: "function FILE takes exactly 1 argument", 82 }, 83 } 84 85 func TestParseTableName(t *testing.T) { 86 ctx := context.Background() 87 scope := NewReferenceScope(TestTx) 88 89 for _, v := range parseTableNameTests { 90 name, err := ParseTableName(ctx, scope, v.Table) 91 92 if err != nil { 93 if len(v.Error) < 1 { 94 t.Errorf("%s: unexpected error %q", v.Table.String(), err) 95 } else if err.Error() != v.Error { 96 t.Errorf("%s: error %q, want error %q", v.Table.String(), err.Error(), v.Error) 97 } 98 continue 99 } 100 if 0 < len(v.Error) { 101 t.Errorf("%s: no error, want error %q", v.Table.String(), v.Error) 102 continue 103 } 104 105 if name.Literal != v.Result { 106 t.Errorf("%s: \n result = %q,\n expect = %q", v.Table.String(), name.Literal, v.Result) 107 } 108 } 109 } 110 111 var convertTableFunctionTests = []struct { 112 Name string 113 TableFunction parser.TableFunction 114 Result parser.QueryExpression 115 Error string 116 }{ 117 { 118 Name: "Convert FILE function", 119 TableFunction: parser.TableFunction{ 120 Name: "file", 121 Args: []parser.QueryExpression{ 122 parser.NewStringValue("./table.csv"), 123 }, 124 }, 125 Result: parser.Identifier{ 126 Literal: "./table.csv", 127 }, 128 }, 129 { 130 Name: "Argument Length Error in FILE function", 131 TableFunction: parser.TableFunction{ 132 Name: "file", 133 Args: []parser.QueryExpression{ 134 parser.NewStringValue("./table.csv"), 135 parser.NewStringValue("./table.csv"), 136 }, 137 }, 138 Error: "function FILE takes exactly 1 argument", 139 }, 140 { 141 Name: "First argument must be a string in FILE function", 142 TableFunction: parser.TableFunction{ 143 Name: "file", 144 Args: []parser.QueryExpression{ 145 parser.NewNullValue(), 146 }, 147 }, 148 Error: "the first argument must be a string for function FILE", 149 }, 150 { 151 Name: "Convert INLINE function", 152 TableFunction: parser.TableFunction{ 153 Name: "inline", 154 Args: []parser.QueryExpression{ 155 parser.NewStringValue("./table.csv"), 156 }, 157 }, 158 Result: parser.Identifier{ 159 Literal: "./table.csv", 160 }, 161 }, 162 { 163 Name: "Convert URL function", 164 TableFunction: parser.TableFunction{ 165 Name: "url", 166 Args: []parser.QueryExpression{ 167 parser.NewStringValue("https://example.com"), 168 }, 169 }, 170 Result: parser.Url{ 171 Raw: "https://example.com", 172 }, 173 }, 174 { 175 Name: "First argument must be a string in URL function", 176 TableFunction: parser.TableFunction{ 177 Name: "url", 178 Args: []parser.QueryExpression{ 179 parser.NewNullValue(), 180 }, 181 }, 182 Error: "the first argument must be a string for function URL", 183 }, 184 { 185 Name: "Convert DATA function", 186 TableFunction: parser.TableFunction{ 187 Name: "data", 188 Args: []parser.QueryExpression{ 189 parser.NewStringValue("1,a\n2,b"), 190 }, 191 }, 192 Result: DataObject{ 193 Raw: "1,a\n2,b", 194 }, 195 }, 196 { 197 Name: "First argument must be a string in DATA function", 198 TableFunction: parser.TableFunction{ 199 Name: "data", 200 Args: []parser.QueryExpression{ 201 parser.NewNullValue(), 202 }, 203 }, 204 Error: "the first argument must be a string for function DATA", 205 }, 206 { 207 Name: "Invalid Function Name Error", 208 TableFunction: parser.TableFunction{ 209 Name: "invalid", 210 Args: []parser.QueryExpression{ 211 parser.NewStringValue("1,a\n2,b"), 212 }, 213 }, 214 Error: "function INVALID does not exist", 215 }, 216 } 217 218 func TestConvertTableFunction(t *testing.T) { 219 ctx := context.Background() 220 scope := NewReferenceScope(TestTx) 221 222 for _, v := range convertTableFunctionTests { 223 expr, err := ConvertTableFunction(ctx, scope, v.TableFunction) 224 225 if err != nil { 226 if len(v.Error) < 1 { 227 t.Errorf("%s: unexpected error %q", v.Name, err) 228 } else if err.Error() != v.Error { 229 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 230 } 231 continue 232 } 233 if 0 < len(v.Error) { 234 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 235 continue 236 } 237 238 if !reflect.DeepEqual(expr, v.Result) { 239 t.Errorf("%s: \n result = %v,\n expect = %v", v.Name, expr, v.Result) 240 } 241 } 242 } 243 244 var convertUrlExprTests = []struct { 245 Name string 246 Url parser.Url 247 Result parser.QueryExpression 248 Error string 249 }{ 250 { 251 Name: "Convert URL to HttpObject", 252 Url: parser.Url{ 253 Raw: "https://example.com/おなかすいた/csv", 254 }, 255 Result: HttpObject{ 256 URL: "https://example.com/%E3%81%8A%E3%81%AA%E3%81%8B%E3%81%99%E3%81%84%E3%81%9F/csv", 257 }, 258 }, 259 { 260 Name: "Convert Absolute File Path to Identifier", 261 Url: parser.Url{ 262 Raw: "file:///home/my dir/data/foo.csv", 263 }, 264 Result: parser.Identifier{ 265 Literal: "/home/my dir/data/foo.csv", 266 }, 267 }, 268 { 269 Name: "Convert Absolute File Path with URL Encoding to Identifier", 270 Url: parser.Url{ 271 Raw: "file:///home/my%20dir/data/foo.csv", 272 }, 273 Result: parser.Identifier{ 274 Literal: "/home/my dir/data/foo.csv", 275 }, 276 }, 277 { 278 Name: "Convert Relative File Path to Identifier", 279 Url: parser.Url{ 280 Raw: "file:./data/foo.csv", 281 }, 282 Result: parser.Identifier{ 283 Literal: "./data/foo.csv", 284 }, 285 }, 286 { 287 Name: "Unsupported URL Scheme", 288 Url: parser.Url{ 289 Raw: "invalid:./data/foo.csv", 290 }, 291 Error: "url scheme invalid is not supported", 292 }, 293 } 294 295 func TestConvertUrlExpr(t *testing.T) { 296 for _, v := range convertUrlExprTests { 297 expr, err := ConvertUrlExpr(v.Url) 298 299 if err != nil { 300 if len(v.Error) < 1 { 301 t.Errorf("%s: unexpected error %q", v.Name, err) 302 } else if err.Error() != v.Error { 303 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 304 } 305 continue 306 } 307 if 0 < len(v.Error) { 308 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 309 continue 310 } 311 312 if !reflect.DeepEqual(expr, v.Result) { 313 t.Errorf("%s: \n result = %v,\n expect = %v", v.Name, expr, v.Result) 314 } 315 } 316 }