go-hep.org/x/hep@v0.38.1/csvutil/csv_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 csvutil_test 6 7 import ( 8 "fmt" 9 "io" 10 "testing" 11 12 "go-hep.org/x/hep/csvutil" 13 "go-hep.org/x/hep/internal/diff" 14 ) 15 16 func TestCSVReaderScanArgs(t *testing.T) { 17 fname := "testdata/simple.csv" 18 tbl, err := csvutil.Open(fname) 19 if err != nil { 20 t.Errorf("could not open %s: %+v\n", fname, err) 21 } 22 defer tbl.Close() 23 tbl.Reader.Comma = ';' 24 tbl.Reader.Comment = '#' 25 26 rows, err := tbl.ReadRows(0, 10) 27 if err != nil { 28 t.Errorf("could read rows [0, 10): %+v\n", err) 29 } 30 defer rows.Close() 31 32 irow := 0 33 for rows.Next() { 34 var ( 35 i int 36 f float64 37 s string 38 ) 39 err = rows.Scan(&i, &f, &s) 40 if err != nil { 41 t.Errorf("error reading row %d: %+v\n", irow, err) 42 } 43 exp := fmt.Sprintf("%d;%d;str-%d", irow, irow, irow) 44 got := fmt.Sprintf("%v;%v;%v", i, f, s) 45 if exp != got { 46 t.Errorf("error reading row %d\nexp=%q\ngot=%q\n", 47 irow, exp, got, 48 ) 49 } 50 irow++ 51 } 52 53 err = rows.Err() 54 if err != nil { 55 t.Errorf("error iterating over rows: %+v\n", err) 56 } 57 } 58 59 func TestCSVReaderScanStruct(t *testing.T) { 60 fname := "testdata/simple.csv" 61 tbl, err := csvutil.Open(fname) 62 if err != nil { 63 t.Errorf("could not open %s: %+v\n", fname, err) 64 } 65 defer tbl.Close() 66 tbl.Reader.Comma = ';' 67 tbl.Reader.Comment = '#' 68 69 rows, err := tbl.ReadRows(0, 10) 70 if err != nil { 71 t.Errorf("could read rows [0, 10): %+v\n", err) 72 } 73 defer rows.Close() 74 75 irow := 0 76 for rows.Next() { 77 data := struct { 78 I int 79 F float64 80 S string 81 }{} 82 err = rows.Scan(&data) 83 if err != nil { 84 t.Errorf("error reading row %d: %+v\n", irow, err) 85 } 86 exp := fmt.Sprintf("%d;%d;str-%d", irow, irow, irow) 87 got := fmt.Sprintf("%v;%v;%v", data.I, data.F, data.S) 88 if exp != got { 89 t.Errorf("error reading row %d\nexp=%q\ngot=%q\n", 90 irow, exp, got, 91 ) 92 } 93 irow++ 94 } 95 96 err = rows.Err() 97 if err != nil { 98 t.Errorf("error iterating over rows: %+v\n", err) 99 } 100 } 101 102 func TestCSVReaderScanSmallRead(t *testing.T) { 103 fname := "testdata/simple.csv" 104 tbl, err := csvutil.Open(fname) 105 if err != nil { 106 t.Errorf("could not open %s: %+v\n", fname, err) 107 } 108 defer tbl.Close() 109 tbl.Reader.Comma = ';' 110 tbl.Reader.Comment = '#' 111 112 rows, err := tbl.ReadRows(0, 2) 113 if err != nil { 114 t.Errorf("could read rows [0, 2): %+v\n", err) 115 } 116 defer rows.Close() 117 118 irow := 0 119 for rows.Next() { 120 data := struct { 121 I int 122 F float64 123 S string 124 }{} 125 err = rows.Scan(&data) 126 if err != nil { 127 t.Errorf("error reading row %d: %+v\n", irow, err) 128 } 129 exp := fmt.Sprintf("%d;%d;str-%d", irow, irow, irow) 130 got := fmt.Sprintf("%v;%v;%v", data.I, data.F, data.S) 131 if exp != got { 132 t.Errorf("error reading row %d\nexp=%q\ngot=%q\n", 133 irow, exp, got, 134 ) 135 } 136 irow++ 137 } 138 139 err = rows.Err() 140 if err != nil { 141 t.Errorf("error iterating over rows: %+v\n", err) 142 } 143 } 144 145 func TestCSVReaderInvalidScan(t *testing.T) { 146 fname := "testdata/simple.csv" 147 tbl, err := csvutil.Open(fname) 148 if err != nil { 149 t.Errorf("could not open %s: %+v\n", fname, err) 150 } 151 defer tbl.Close() 152 tbl.Reader.Comma = ';' 153 tbl.Reader.Comment = '#' 154 155 rows, err := tbl.ReadRows(0, -1) 156 if err != nil { 157 t.Errorf("could read rows [0, -1): %+v\n", err) 158 } 159 defer rows.Close() 160 161 if !rows.Next() { 162 t.Fatalf("could not get data") 163 } 164 165 err = rows.Scan() 166 if err == nil { 167 t.Errorf("expected an error") 168 } 169 170 err = rows.Err() 171 if err == nil { 172 t.Fatalf("expected a sticky error") 173 } 174 } 175 176 func TestCSVReaderScanEOF(t *testing.T) { 177 fname := "testdata/simple.csv" 178 tbl, err := csvutil.Open(fname) 179 if err != nil { 180 t.Errorf("could not open %s: %+v\n", fname, err) 181 } 182 defer tbl.Close() 183 tbl.Reader.Comma = ';' 184 tbl.Reader.Comment = '#' 185 186 rows, err := tbl.ReadRows(0, 12) 187 if err != nil { 188 t.Errorf("could read rows [0, 12): %+v\n", err) 189 } 190 defer rows.Close() 191 192 irow := 0 193 for rows.Next() { 194 data := struct { 195 I int 196 F float64 197 S string 198 }{} 199 err = rows.Scan(&data) 200 if err != nil { 201 if irow == 10 { 202 break 203 } 204 t.Errorf("error reading row %d: %+v\n", irow, err) 205 } 206 exp := fmt.Sprintf("%d;%d;str-%d", irow, irow, irow) 207 got := fmt.Sprintf("%v;%v;%v", data.I, data.F, data.S) 208 if exp != got { 209 t.Errorf("error reading row %d\nexp=%q\ngot=%q\n", 210 irow, exp, got, 211 ) 212 } 213 irow++ 214 } 215 216 if irow != 10 { 217 t.Errorf("error. expected irow==10. got=%v\n", irow) 218 } 219 220 err = rows.Err() 221 if err != io.EOF { 222 t.Errorf("error: expected io.EOF. got=%+v\n", err) 223 } 224 } 225 226 func TestCSVReaderScanUntilEOF(t *testing.T) { 227 fname := "testdata/simple.csv" 228 tbl, err := csvutil.Open(fname) 229 if err != nil { 230 t.Errorf("could not open %s: %+v\n", fname, err) 231 } 232 defer tbl.Close() 233 tbl.Reader.Comma = ';' 234 tbl.Reader.Comment = '#' 235 236 rows, err := tbl.ReadRows(0, -1) 237 if err != nil { 238 t.Errorf("could read rows [0, -1): %+v\n", err) 239 } 240 defer rows.Close() 241 242 irow := 0 243 for rows.Next() { 244 data := struct { 245 I int 246 F float64 247 S string 248 }{} 249 err = rows.Scan(&data) 250 if err != nil { 251 if err == io.EOF { 252 break 253 } 254 t.Errorf("error reading row %d: %+v\n", irow, err) 255 } 256 exp := fmt.Sprintf("%d;%d;str-%d", irow, irow, irow) 257 got := fmt.Sprintf("%v;%v;%v", data.I, data.F, data.S) 258 if exp != got { 259 t.Errorf("error reading row %d\nexp=%q\ngot=%q\n", 260 irow, exp, got, 261 ) 262 } 263 irow++ 264 } 265 266 err = rows.Err() 267 if err != io.EOF { 268 t.Errorf("error: expected io.EOF. got=%+v\n", err) 269 } 270 } 271 272 func TestCSVReaderScanArgsSubSample(t *testing.T) { 273 fname := "testdata/simple.csv" 274 tbl, err := csvutil.Open(fname) 275 if err != nil { 276 t.Errorf("could not open %s: %+v\n", fname, err) 277 } 278 defer tbl.Close() 279 tbl.Reader.Comma = ';' 280 tbl.Reader.Comment = '#' 281 282 rows, err := tbl.ReadRows(2, 10) 283 if err != nil { 284 t.Errorf("could read rows [2, 10): %+v\n", err) 285 } 286 defer rows.Close() 287 288 irow := 2 289 for rows.Next() { 290 var ( 291 i int 292 f float64 293 s string 294 ) 295 err = rows.Scan(&i, &f, &s) 296 if err != nil { 297 t.Errorf("error reading row %d: %+v\n", irow, err) 298 } 299 exp := fmt.Sprintf("%d;%d;str-%d", irow, irow, irow) 300 got := fmt.Sprintf("%v;%v;%v", i, f, s) 301 if exp != got { 302 t.Errorf("error reading row %d\nexp=%q\ngot=%q\n", 303 irow, exp, got, 304 ) 305 } 306 irow++ 307 } 308 309 err = rows.Err() 310 if err != nil { 311 t.Errorf("error iterating over rows: %+v\n", err) 312 } 313 314 if irow-2 != 8 { 315 t.Errorf("error: got %d rows. expected 8\n", irow-2) 316 } 317 } 318 319 func TestCSVWriterArgs(t *testing.T) { 320 fname := "testdata/out-args.csv" 321 tbl, err := csvutil.Create(fname) 322 if err != nil { 323 t.Errorf("could not create %s: %+v\n", fname, err) 324 } 325 defer tbl.Close() 326 tbl.Writer.Comma = ';' 327 328 err = tbl.WriteHeader("## a simple set of data: int64;float64;string;slice\n") 329 if err != nil { 330 t.Errorf("error writing header: %+v\n", err) 331 } 332 333 for i := range 10 { 334 var ( 335 f = float64(i) 336 s = fmt.Sprintf("str-%d", i) 337 l = []int{1, 2, 3, 4} 338 ) 339 err = tbl.WriteRow(i, f, s, l) 340 if err != nil { 341 t.Errorf("error writing row %d: %+v\n", i, err) 342 break 343 } 344 } 345 346 err = tbl.Close() 347 if err != nil { 348 t.Errorf("error closing table: %+v\n", err) 349 } 350 351 err = diff.Files("testdata/write-results.csv", fname) 352 if err != nil { 353 t.Errorf("files differ: %+v\n", err) 354 } 355 } 356 357 func TestCSVWriterStruct(t *testing.T) { 358 fname := "testdata/out-struct.csv" 359 tbl, err := csvutil.Create(fname) 360 if err != nil { 361 t.Errorf("could not create %s: %+v\n", fname, err) 362 } 363 defer tbl.Close() 364 tbl.Writer.Comma = ';' 365 366 // test WriteHeader w/o a trailing newline 367 err = tbl.WriteHeader("## a simple set of data: int64;float64;string;slice") 368 if err != nil { 369 t.Errorf("error writing header: %+v\n", err) 370 } 371 372 for i := range 10 { 373 data := struct { 374 I int 375 F float64 376 S string 377 L []int 378 }{ 379 I: i, 380 F: float64(i), 381 S: fmt.Sprintf("str-%d", i), 382 L: []int{1, 2, 3, 4}, 383 } 384 err = tbl.WriteRow(data) 385 if err != nil { 386 t.Errorf("error writing row %d: %+v\n", i, err) 387 break 388 } 389 } 390 391 err = tbl.Close() 392 if err != nil { 393 t.Errorf("error closing table: %+v\n", err) 394 } 395 396 err = diff.Files("testdata/write-results.csv", fname) 397 if err != nil { 398 t.Errorf("files differ: %+v\n", err) 399 } 400 } 401 402 func TestCSVWriterArgsSlice(t *testing.T) { 403 fname := "testdata/out-args-slice.csv" 404 tbl, err := csvutil.Create(fname) 405 if err != nil { 406 t.Fatalf("could not create %s: %+v", fname, err) 407 } 408 defer tbl.Close() 409 tbl.Writer.Comma = ',' 410 411 err = tbl.WriteHeader("## more complicated slices: [][]int{}, [][]string{}, []string{}, float64\n") 412 if err != nil { 413 t.Fatalf("error writing header: %+v", err) 414 } 415 416 for i := range 10 { 417 var ( 418 lii = [][]int{{1, 2, 3}, {2, 3, 4}, {7, 8, 15}} 419 lss = [][]string{{"foo", "bar", "baz"}, {"abc", "def", "ghi"}, {"qwerty"}} 420 ls = []string{"abc", "def", "ghi"} 421 f = float64(i) 422 ) 423 err = tbl.WriteRow(lii, lss, ls, f) 424 if err != nil { 425 t.Fatalf("error writing row %d: %+v", i, err) 426 } 427 } 428 429 err = tbl.Close() 430 if err != nil { 431 t.Fatalf("error closing table: %+v", err) 432 } 433 434 err = diff.Files("testdata/write-results-slice.csv", fname) 435 if err != nil { 436 t.Fatalf("files differ: %+v", err) 437 } 438 } 439 440 func TestCSVAppend(t *testing.T) { 441 fname := "testdata/append-test.csv" 442 tbl, err := csvutil.Create(fname) 443 if err != nil { 444 t.Fatal(err) 445 } 446 defer tbl.Close() 447 448 tbl.Writer.Comma = ';' 449 450 // test WriteHeader w/o a trailing newline 451 err = tbl.WriteHeader("## a simple set of data: int64;float64;string") 452 if err != nil { 453 t.Errorf("error writing header: %+v\n", err) 454 } 455 456 for i := range 10 { 457 data := struct { 458 I int 459 F float64 460 S string 461 }{ 462 I: i, 463 F: float64(i), 464 S: fmt.Sprintf("str-%d", i), 465 } 466 err = tbl.WriteRow(data) 467 if err != nil { 468 t.Errorf("error writing row %d: %+v\n", i, err) 469 break 470 } 471 } 472 473 err = tbl.Close() 474 if err != nil { 475 t.Errorf("error closing table: %+v\n", err) 476 } 477 478 // re-open to append 479 tbl, err = csvutil.Append(fname) 480 if err != nil { 481 t.Fatal(err) 482 } 483 defer tbl.Close() 484 485 tbl.Writer.Comma = ';' 486 for i := 10; i < 20; i++ { 487 data := struct { 488 I int 489 F float64 490 S string 491 }{ 492 I: i, 493 F: float64(i), 494 S: fmt.Sprintf("str-%d", i), 495 } 496 err = tbl.WriteRow(data) 497 if err != nil { 498 t.Errorf("error writing row %d: %+v\n", i, err) 499 break 500 } 501 } 502 503 err = tbl.Close() 504 if err != nil { 505 t.Fatal(err) 506 } 507 508 err = diff.Files("testdata/append.csv", fname) 509 if err != nil { 510 t.Errorf("files differ: %+v\n", err) 511 } 512 } 513 514 func TestCSVReaderTypes(t *testing.T) { 515 fname := "testdata/types.csv" 516 tbl, err := csvutil.Open(fname) 517 if err != nil { 518 t.Errorf("could not open %s: %+v\n", fname, err) 519 } 520 defer tbl.Close() 521 tbl.Reader.Comma = ';' 522 tbl.Reader.Comment = '#' 523 524 rows, err := tbl.ReadRows(0, 2) 525 if err != nil { 526 t.Errorf("could read rows [0, 2): %+v\n", err) 527 } 528 defer rows.Close() 529 530 const nfields = 14 531 type Data struct { 532 Bool bool 533 Int int 534 Int8 int8 535 Int16 int16 536 Int32 int32 537 Int64 int64 538 UInt uint 539 UInt8 uint8 540 UInt16 uint16 541 UInt32 uint32 542 UInt64 uint64 543 F32 float32 544 F64 float64 545 Str string 546 } 547 548 wants := []Data{ 549 {true, +1, -1, -1, -1, -1, +1, +1, +1, +1, +1, 1.1, 1.1, "str-1"}, 550 {false, -2, -2, -2, -2, -2, +2, +2, +2, +2, +2, 2.2, 2.2, "str-2"}, 551 } 552 irow := 0 553 for rows.Next() { 554 want := wants[irow] 555 { 556 var got Data 557 err = rows.Scan(&got.Bool, &got.Int, &got.Int8, &got.Int16, &got.Int32, &got.Int64, &got.UInt, &got.UInt8, &got.UInt16, &got.UInt32, &got.UInt64, &got.F32, &got.F64, &got.Str) 558 if err != nil { 559 t.Errorf("error reading row %d: %+v\n", irow, err) 560 } 561 if want != got { 562 t.Errorf("error reading row %d\ngot= %#v\nwant=%#v\n", 563 irow, got, want, 564 ) 565 } 566 if got, want := rows.NumFields(), nfields; got != want { 567 t.Errorf("invalid number of fields. got=%d. want=%d", got, want) 568 569 } 570 if got, want := len(rows.Fields()), nfields; got != want { 571 t.Errorf("invalid number of fields. got=%d. want=%d", got, want) 572 573 } 574 } 575 { 576 var got Data 577 err = rows.Scan(&got) 578 if err != nil { 579 t.Errorf("error reading row %d: %+v\n", irow, err) 580 } 581 if want != got { 582 t.Errorf("error reading row %d\ngot= %#v\nwant=%#v\n", 583 irow, got, want, 584 ) 585 } 586 if got, want := rows.NumFields(), nfields; got != want { 587 t.Errorf("invalid number of fields. got=%d. want=%d", got, want) 588 } 589 if got, want := len(rows.Fields()), nfields; got != want { 590 t.Errorf("invalid number of fields. got=%d. want=%d", got, want) 591 } 592 } 593 irow++ 594 } 595 596 err = rows.Err() 597 if err != nil { 598 t.Errorf("error iterating over rows: %+v\n", err) 599 } 600 } 601 602 func TestCSVWriterTypes(t *testing.T) { 603 fname := "testdata/out-types.csv" 604 tbl, err := csvutil.Create(fname) 605 if err != nil { 606 t.Errorf("could not create %s: %+v\n", fname, err) 607 } 608 defer tbl.Close() 609 tbl.Writer.Comma = ';' 610 611 // test WriteHeader w/o a trailing newline 612 err = tbl.WriteHeader("## supported types: bool;int;int8;int16;int32;int64;uint;uint8;uint16;uint32;uint64;float32;float64;string") 613 if err != nil { 614 t.Errorf("error writing header: %+v\n", err) 615 } 616 617 type Data struct { 618 Bool bool 619 Int int 620 Int8 int8 621 Int16 int16 622 Int32 int32 623 Int64 int64 624 UInt uint 625 UInt8 uint8 626 UInt16 uint16 627 UInt32 uint32 628 UInt64 uint64 629 F32 float32 630 F64 float64 631 Str string 632 } 633 634 wants := []Data{ 635 {true, +1, -1, -1, -1, -1, +1, +1, +1, +1, +1, 1.1, 1.1, "str-1"}, 636 {false, -2, -2, -2, -2, -2, +2, +2, +2, +2, +2, 2.2, 2.2, "str-2"}, 637 } 638 for i := range wants { 639 err = tbl.WriteRow(wants[i]) 640 if err != nil { 641 t.Errorf("error writing row %d: %+v\n", i, err) 642 break 643 } 644 } 645 646 err = tbl.Close() 647 if err != nil { 648 t.Errorf("error closing table: %+v\n", err) 649 } 650 651 err = diff.Files("testdata/types.csv.ref", fname) 652 if err != nil { 653 t.Errorf("files differ: %+v\n", err) 654 } 655 }