go-hep.org/x/hep@v0.38.1/csvutil/csvdriver/driver_test.go (about) 1 // Copyright ©2016 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package csvdriver_test 6 7 import ( 8 "database/sql" 9 "fmt" 10 "os" 11 "reflect" 12 "testing" 13 "time" 14 15 "go-hep.org/x/hep/csvutil/csvdriver" 16 ) 17 18 func testDB(t *testing.T, conn csvdriver.Conn, vars string) { 19 db, err := conn.Open() 20 if err != nil { 21 t.Errorf("%s: error opening CSV file", conn.File) 22 return 23 } 24 defer db.Close() 25 26 tx, err := db.Begin() 27 if err != nil { 28 t.Errorf("%s: error starting tx: %+v", conn.File, err) 29 return 30 } 31 defer func() { 32 _ = tx.Commit() 33 }() 34 35 done := make(chan error) 36 go func() { 37 done <- db.Ping() 38 }() 39 40 select { 41 case <-time.After(2 * time.Second): 42 t.Errorf("%s: ping timeout", conn.File) 43 return 44 case err := <-done: 45 if err != nil { 46 t.Errorf("%s: error pinging db: %+v\n", conn.File, err) 47 return 48 } 49 } 50 51 rows, err := tx.Query("select " + vars + " from csv order by id();") 52 if err != nil { 53 t.Errorf("%s: error querying db: %+v\n", conn.File, err) 54 return 55 } 56 defer rows.Close() 57 58 type dataType struct { 59 i int64 60 f float64 61 s string 62 } 63 64 var got []dataType 65 for rows.Next() { 66 var data dataType 67 err = rows.Scan(&data.i, &data.f, &data.s) 68 if err != nil { 69 t.Errorf("%s: error scanning db: %+v\n", conn.File, err) 70 return 71 } 72 got = append(got, data) 73 } 74 75 err = rows.Close() 76 if err != nil { 77 t.Errorf("%s: error closing rows: %+v\n", conn.File, err) 78 return 79 } 80 81 err = db.Close() 82 if err != nil { 83 t.Errorf("%s: error closing db: %+v\n", conn.File, err) 84 return 85 } 86 87 want := []dataType{ 88 {0, 0, "str-0"}, 89 {1, 1, "str-1"}, 90 {2, 2, "str-2"}, 91 {3, 3, "str-3"}, 92 {4, 4, "str-4"}, 93 {5, 5, "str-5"}, 94 {6, 6, "str-6"}, 95 {7, 7, "str-7"}, 96 {8, 8, "str-8"}, 97 {9, 9, "str-9"}, 98 } 99 100 if !reflect.DeepEqual(got, want) { 101 t.Errorf("%s: got=\n%v\nwant=\n%v\n", conn.File, got, want) 102 return 103 } 104 } 105 106 func TestOpen(t *testing.T) { 107 for _, test := range []struct { 108 c csvdriver.Conn 109 q string 110 }{ 111 { 112 c: csvdriver.Conn{ 113 File: "testdata/simple.csv", 114 Comment: '#', Comma: ';', 115 }, 116 q: "var1, var2, var3", 117 }, 118 { 119 c: csvdriver.Conn{ 120 File: "testdata/simple.csv", 121 Comment: '#', Comma: ';', 122 Names: []string{"v1", "v2", "v3"}, 123 }, 124 q: "v1, v2, v3", 125 }, 126 { 127 c: csvdriver.Conn{ 128 File: "testdata/simple-with-comment.csv", 129 Comment: '#', Comma: ';', 130 }, 131 q: "var1, var2, var3", 132 }, 133 { 134 c: csvdriver.Conn{ 135 File: "testdata/simple-with-comment.csv", 136 Comment: '#', Comma: ';', 137 Names: []string{"v1", "v2", "v3"}, 138 }, 139 q: "v1, v2, v3", 140 }, 141 { 142 c: csvdriver.Conn{ 143 File: "testdata/simple-with-header.csv", 144 Comment: '#', Comma: ';', 145 Header: true, 146 }, 147 q: "i64, f64, str", 148 }, 149 { 150 c: csvdriver.Conn{ 151 File: "testdata/simple-with-header.csv", Comment: '#', Comma: ';', 152 Header: true, 153 Names: []string{"var1", "var2", "var3"}, 154 }, 155 q: "var1, var2, var3", 156 }, 157 } { 158 testDB(t, test.c, test.q) 159 } 160 } 161 162 func TestQL(t *testing.T) { 163 db, err := sql.Open("ql", "memory://out-create-ql.csv") 164 if err != nil { 165 t.Fatalf("error creating CSV-QL file: %+v\n", err) 166 } 167 defer db.Close() 168 169 err = db.Ping() 170 if err != nil { 171 t.Fatalf("error pinging db: %+v\n", err) 172 } 173 174 tx, err := db.Begin() 175 if err != nil { 176 t.Fatalf("error starting transaction: %+v\n", err) 177 } 178 defer func() { 179 _ = tx.Commit() 180 }() 181 182 _, err = tx.Exec("create table csv (var1 int64, var2 float64, var3 string);") 183 if err != nil { 184 t.Fatalf("error creating table: %+v\n", err) 185 } 186 187 for i := range 10 { 188 f := float64(i) 189 s := fmt.Sprintf("str-%d", i) 190 _, err = tx.Exec("insert into csv values($1,$2,$3);", i, f, s) 191 if err != nil { 192 t.Fatalf("error inserting row %d: %+v\n", i+1, err) 193 } 194 } 195 err = tx.Commit() 196 if err != nil { 197 t.Fatalf("error committing transaction: %+v\n", err) 198 } 199 } 200 201 func TestCreate(t *testing.T) { 202 const fname = "testdata/out-create.csv" 203 defer os.Remove(fname) 204 205 db, err := csvdriver.Create(fname) 206 if err != nil { 207 t.Fatalf("error creating CSV file: %+v\n", err) 208 } 209 defer db.Close() 210 211 err = db.Ping() 212 if err != nil { 213 t.Fatalf("error pinging db: %+v\n", err) 214 } 215 216 tx, err := db.Begin() 217 if err != nil { 218 t.Fatalf("error starting transaction: %+v\n", err) 219 } 220 defer func() { 221 _ = tx.Commit() 222 }() 223 224 _, err = tx.Exec("create table csv (var1 int64, var2 float64, var3 string);") 225 if err != nil { 226 t.Fatalf("error creating table: %+v\n", err) 227 } 228 229 for i := range 10 { 230 f := float64(i) 231 s := fmt.Sprintf("str-%d", i) 232 _, err = tx.Exec("insert into csv values($1,$2,$3);", i, f, s) 233 if err != nil { 234 t.Fatalf("error inserting row %d: %+v\n", i+1, err) 235 } 236 } 237 err = tx.Commit() 238 if err != nil { 239 t.Fatalf("error committing transaction: %+v\n", err) 240 } 241 } 242 243 func TestCreateRollback(t *testing.T) { 244 const fname = "testdata/out-create-rollback.csv" 245 defer os.Remove(fname) 246 247 db, err := csvdriver.Create(fname) 248 if err != nil { 249 t.Fatalf("error creating CSV file: %+v\n", err) 250 } 251 defer db.Close() 252 253 err = db.Ping() 254 if err != nil { 255 t.Fatalf("error pinging db: %+v\n", err) 256 } 257 258 tx, err := db.Begin() 259 if err != nil { 260 t.Fatalf("error starting transaction: %+v\n", err) 261 } 262 defer func() { 263 _ = tx.Commit() 264 }() 265 266 _, err = tx.Exec("create table csv (var1 int64, var2 float64, var3 string);") 267 if err != nil { 268 t.Fatalf("error creating table: %+v\n", err) 269 } 270 271 for i := range 10 { 272 f := float64(i) 273 s := fmt.Sprintf("str-%d", i) 274 _, err = tx.Exec("insert into csv values($1,$2,$3);", i, f, s) 275 if err != nil { 276 t.Fatalf("error inserting row %d: %+v\n", i+1, err) 277 } 278 } 279 280 err = tx.Rollback() 281 if err != nil { 282 t.Fatalf("error committing transaction: %+v\n", err) 283 } 284 285 err = db.Close() 286 if err != nil { 287 t.Fatal(err) 288 } 289 290 got, err := os.ReadFile(fname) 291 if err != nil { 292 t.Fatal(err) 293 } 294 295 if len(got) != 0 { 296 t.Fatalf("non-empty file:\n%q\n", string(got)) 297 } 298 } 299 300 func TestOpenDriver(t *testing.T) { 301 for _, fname := range []string{ 302 "https://codeberg.org/go-hep/hep/raw/branch/main/csvutil/csvdriver/testdata/types.csv", 303 "testdata/types.csv", 304 } { 305 t.Run(fname, func(t *testing.T) { 306 307 c, err := csvdriver.Open(fname) 308 if err != nil { 309 t.Fatal(err) 310 } 311 312 stmt, err := c.Prepare("select var1 from csv;") 313 if err != nil { 314 t.Fatal(err) 315 } 316 defer stmt.Close() 317 318 rows, err := stmt.Query() 319 if err != nil { 320 t.Fatal(err) 321 } 322 defer rows.Close() 323 324 v, err := rows.Columns() 325 if err != nil { 326 t.Fatal(err) 327 } 328 if got, want := v, []string{"var1"}; !reflect.DeepEqual(got, want) { 329 t.Fatalf("got=%v, want=%v", got, want) 330 } 331 332 types, err := rows.ColumnTypes() 333 if err != nil { 334 t.Fatal(err) 335 } 336 if got, want := types[0].Name(), "var1"; got != want { 337 t.Fatalf("got=%q, want=%q", got, want) 338 } 339 340 err = rows.Close() 341 if err != nil { 342 t.Fatalf("error closing rows: %+v\n", err) 343 } 344 }) 345 } 346 }