1package fileio23import (4 "context"5 "database/sql"6 "encoding/binary"7 "path/filepath"8 "testing"910 "github.com/parquet-go/parquet-go"1112 "src.rest/cat/012/internal/sheet"13)1415// TestSQLiteDeclaredFormats checks the formats a SQLite source's16// columns show in, from their declared types.17func TestSQLiteDeclaredFormats(t *testing.T) {18 name := filepath.Join(t.TempDir(), "typed.sqlite")19 db, err := sql.Open("sqlite", name)20 if err != nil {21 t.Fatal(err)22 }23 _, err = db.Exec(`CREATE TABLE t (n INTEGER, price DECIMAL(10,2), rate NUMERIC(8, 4), plain NUMERIC, paid MONEY,24 day DATE, at DATETIME, stamp TIMESTAMP, clock TIME, note TEXT)`)25 db.Close()26 if err != nil {27 t.Fatal(err)28 }29 src, err := OpenSource(context.Background(), SourceSpec{Path: name, TempDir: t.TempDir()})30 if err != nil {31 t.Fatal(err)32 }33 defer src.Close()34 want := []SourceColumn{35 {Name: "n", Numeric: true},36 {Name: "price", Format: sheet.Format{Kind: sheet.FmtNumber, Decimals: 2}, Numeric: true},37 {Name: "rate", Format: sheet.Format{Kind: sheet.FmtNumber, Decimals: 4}, Numeric: true},38 {Name: "plain", Numeric: true},39 {Name: "paid", Format: sheet.Format{Kind: sheet.FmtCurrency, Decimals: 2}, Numeric: true},40 {Name: "day", Format: sheet.Format{Kind: sheet.FmtDate}, Numeric: true},41 {Name: "at", Format: sheet.Format{Kind: sheet.FmtDateTime}, Numeric: true},42 {Name: "stamp", Format: sheet.Format{Kind: sheet.FmtDateTime}, Numeric: true},43 {Name: "clock", Format: sheet.Format{Kind: sheet.FmtTime}, Numeric: true},44 {Name: "note"},45 }46 got := src.Columns()47 if len(got) != len(want) {48 t.Fatalf("columns %+v", got)49 }50 for i := range want {51 if got[i] != want[i] {52 t.Errorf("column %d: %+v, want %+v", i, got[i], want[i])53 }54 }55}5657// TestParquetInterval checks an INTERVAL's 12 bytes read as days: months58// of 30 days, days, and milliseconds.59func TestParquetInterval(t *testing.T) {60 b := make([]byte, 12)61 binary.LittleEndian.PutUint32(b, 1)62 binary.LittleEndian.PutUint32(b[4:], 2)63 binary.LittleEndian.PutUint32(b[8:], 43_200_000)64 d, ok := interval(parquet.FixedLenByteArrayValue(b))65 if !ok || d != 32.5 {66 t.Errorf("interval %v %v, want 32.5 days", d, ok)67 }68 if _, ok := interval(parquet.ByteArrayValue([]byte{1, 2})); ok {69 t.Error("read 2 bytes as an interval")70 }71 c := parquetColumn{kind: parquet.FixedLenByteArray, interval: true}72 if lc, ok := parquetValue(parquet.FixedLenByteArrayValue(b), c); !ok || lc.F.Kind != sheet.FmtDuration || lc.V.Num != 32.5 {73 t.Errorf("an interval's cell: %+v", lc)74 }75 if f, num := parquetFormat(c); f.Kind != sheet.FmtDuration || !num {76 t.Errorf("an interval column shows in %+v", f)77 }78}