1
0
mirror of https://github.com/pbnjay/grate.git synced 2024-12-04 19:45:34 +02:00

fixing and improving tests. allow fuzzier comparisons to cell content

This commit is contained in:
Jeremy Jay 2022-02-23 00:54:59 -05:00
parent f02fd82e53
commit 136244017b
7 changed files with 234 additions and 131 deletions

View File

@ -95,6 +95,15 @@ func (c Cell) FormatNo() uint16 {
return 0
}
// Clone returns the new copy of this Cell.
func (c Cell) Clone() Cell {
c2 := make([]interface{}, len(c))
for i, x := range c {
c2[i] = x
}
return c2
}
///////
var boolStrings = map[string]bool{
@ -304,3 +313,149 @@ func (c *Cell) SetFormatNumber(f uint16) {
(*c)[2] = f
}
}
func (c Cell) Equal(other Cell) bool {
if c.Type() == FloatCell || other.Type() == FloatCell ||
c.Type() == IntegerCell || other.Type() == IntegerCell {
v1, ok := c[0].(float64)
v1x, okx := c[0].(int64)
if okx {
v1 = float64(v1x)
ok = true
}
if !ok {
fmt.Sscanf(fmt.Sprint(c[0]), "%g", &v1)
}
v2, ok := other[0].(float64)
v2x, okx := other[0].(int64)
if okx {
v2 = float64(v2x)
ok = true
}
if !ok {
fmt.Sscanf(fmt.Sprint(c[0]), "%g", &v2)
}
return v1 == v2
}
return c.Less(other) == other.Less(c)
}
func (c Cell) Less(other Cell) bool {
if len(c) == 0 {
return false
}
switch v1 := c[0].(type) {
case nil:
return false
case bool:
// F < T = T
// F < F = F
// T < T = F
// T < F = F
if v1 {
return false
}
// if v2 is truthy, return true
switch v2 := other[0].(type) {
case nil:
return false
case bool:
return v2
case int64:
return v2 != 0
case float64:
return v2 != 0.0
case string:
return boolStrings[v2]
}
case int64:
// v1 < v2
switch v2 := other[0].(type) {
case nil:
return false
case bool:
x := int64(0)
if v2 {
x = 1
}
return v1 < x
case int64:
return v1 < v2
case float64:
if v2 < math.MinInt64 {
return false
}
if v2 > math.MaxInt64 {
return true
}
return float64(v1) < v2
case string:
var x int64
_, err := fmt.Sscanf(v2, "%d", &x)
if err == nil {
return v1 < x
}
return fmt.Sprint(v1) < v2
}
case float64:
switch v2 := other[0].(type) {
case nil:
return false
case bool:
x := float64(0.0)
if v2 {
x = 1.0
}
return v1 < x
case int64:
if v1 < math.MinInt64 {
return true
}
if v1 > math.MaxInt64 {
return false
}
return v1 < float64(v2)
case float64:
return v1 < v2
case string:
var x float64
_, err := fmt.Sscanf(v2, "%g", &x)
if err == nil {
return v1 < x
}
return fmt.Sprint(v1) < v2
}
case string:
//return v1 < fmt.Sprint(other[0])
switch v2 := other[0].(type) {
case nil:
return false
case bool:
return v2 && !boolStrings[v1]
case int64:
var x int64
_, err := fmt.Sscanf(v1, "%d", &x)
if err == nil {
return x < v2
}
return v1 < fmt.Sprint(v2)
case float64:
var x float64
_, err := fmt.Sscanf(v1, "%g", &x)
if err == nil {
return x < v2
}
return v1 < fmt.Sprint(v2)
case string:
return v1 < v2
}
}
panic("unable to compare cells (invalid internal type)")
}

View File

@ -108,6 +108,15 @@ func (s *Sheet) Next() bool {
return true
}
// Raw extracts the raw Cell interfaces underlying the current row.
func (s *Sheet) Raw() []Cell {
rr := make([]Cell, s.NumCols)
for i, cell := range s.Rows[s.CurRow-1] {
rr[i] = cell.Clone()
}
return rr
}
// Strings extracts values from the current record into a list of strings.
func (s *Sheet) Strings() []string {
res := make([]string, s.NumCols)

7
testdata/testing.tsv vendored Normal file
View File

@ -0,0 +1,7 @@
title 1 title 2 title 3 title 4
c c c c
b 2 3 4
b 2 j 4
b 1 2 1
b 4 3 2
1 1 1 1
1 title 1 title 2 title 3 title 4
2 c c c c
3 b 2 3 4
4 b 2 j 4
5 b 1 2 1
6 b 4 3 2
7 1 1 1 1

BIN
testdata/testing.xls vendored Normal file

Binary file not shown.

View File

@ -7,7 +7,7 @@ import (
"testing"
)
func TestManyFiles(t *testing.T) {
func TestAllFiles(t *testing.T) {
err := filepath.Walk("../testdata", func(p string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
@ -17,7 +17,7 @@ func TestManyFiles(t *testing.T) {
}
wb, err := Open(p)
if err != nil {
return nil //err
return err
}
sheets, err := wb.List()
@ -25,7 +25,6 @@ func TestManyFiles(t *testing.T) {
return err
}
for _, s := range sheets {
//log.Println(s)
sheet, err := wb.Get(s)
if err != nil {
return err

View File

@ -210,7 +210,7 @@ func (b *WorkBook) parseSheet(s *boundSheet, ss int) (*commonxl.Sheet, error) {
fno = b.xfs[ixfe]
}
res.Put(rowIndex, colIndex, rval, fno)
//log.Printf("RK spec: %d %d = %s", rowIndex, colIndex, rr.Value.String())
//log.Printf("RK spec: %d %d = %+v", rowIndex, colIndex, rval)
case RecTypeFormula:
formulaRow = binary.LittleEndian.Uint16(r.Data[:2])
@ -302,6 +302,7 @@ func (b *WorkBook) parseSheet(s *boundSheet, ss int) (*commonxl.Sheet, error) {
}
}
res.Set(int(formulaRow), int(formulaCol), fstr)
//log.Printf("String direct: %d %d '%s'", int(formulaRow), int(formulaCol), fstr)
case RecTypeLabelSst:
rowIndex := int(binary.LittleEndian.Uint16(r.Data[:2]))
@ -318,7 +319,7 @@ func (b *WorkBook) parseSheet(s *boundSheet, ss int) (*commonxl.Sheet, error) {
if b.strings[sstIndex] != "" {
res.Put(rowIndex, colIndex, b.strings[sstIndex], fno)
}
//log.Printf("SST spec: %d %d = [%d] %s", rowIndex, colIndex, sstIndex, s.b.strings[sstIndex])
//log.Printf("SST spec: %d %d = [%d] '%s' %d", rowIndex, colIndex, sstIndex, b.strings[sstIndex], fno)
case RecTypeHLink:
firstRow := binary.LittleEndian.Uint16(r.Data[:2])

View File

@ -1,20 +1,53 @@
package xls
import (
"bufio"
"log"
"os"
"strings"
"testing"
"github.com/pbnjay/grate/commonxl"
)
var testFiles = []string{
"../testdata/multi_test.xls",
"../testdata/basic.xls",
"../testdata/basic2.xls",
var testFilePairs = [][]string{
{"../testdata/basic.xls", "../testdata/basic.tsv"},
{"../testdata/testing.xls", "../testdata/testing.tsv"},
// TODO: custom formatter support
//{"../testdata/basic2.xls", "../testdata/basic2.tsv"},
// TODO: datetime and fraction formatter support
//{"../testdata/multi_test.xls", "../testdata/multi_test.tsv"},
}
func TestLoading(t *testing.T) {
for _, fn := range testFiles {
wb, err := Open(fn)
func loadTestData(fn string, ff *commonxl.Formatter) (*commonxl.Sheet, error) {
f, err := os.Open(fn)
if err != nil {
return nil, err
}
xs := &commonxl.Sheet{
Formatter: ff,
}
row := 0
s := bufio.NewScanner(f)
for s.Scan() {
record := strings.Split(s.Text(), "\t")
for i, val := range record {
xs.Put(row, i, val, 0)
}
row++
}
return xs, f.Close()
}
func TestBasic(t *testing.T) {
for _, fnames := range testFilePairs {
var trueData *commonxl.Sheet
log.Println("Testing ", fnames[0])
wb, err := Open(fnames[0])
if err != nil {
t.Fatal(err)
}
@ -23,14 +56,30 @@ func TestLoading(t *testing.T) {
if err != nil {
t.Fatal(err)
}
firstLoad := true
for _, s := range sheets {
sheet, err := wb.Get(s)
if err != nil {
t.Fatal(err)
}
xsheet := sheet.(*commonxl.Sheet)
if firstLoad {
trueData, err = loadTestData(fnames[1], xsheet.Formatter)
if err != nil {
t.Fatal(err)
}
firstLoad = false
}
for sheet.Next() {
sheet.Strings()
for xrow, xdata := range xsheet.Rows {
for xcol, xval := range xdata {
//t.Logf("at %s (%d,%d) expect '%v'", fnames[0], xrow, xcol, trueData.Rows[xrow][xcol])
if !trueData.Rows[xrow][xcol].Equal(xval) {
t.Logf("mismatch at %s (%d,%d): '%v' <> '%v' expected", fnames[0], xrow, xcol,
xval, trueData.Rows[xrow][xcol])
t.Fail()
}
}
}
}
@ -40,120 +89,3 @@ func TestLoading(t *testing.T) {
}
}
}
func TestBasic(t *testing.T) {
trueFile, err := os.ReadFile("../testdata/basic.tsv")
if err != nil {
t.Skip()
}
lines := strings.Split(string(trueFile), "\n")
fn := "../testdata/basic.xls"
wb, err := Open(fn)
if err != nil {
t.Fatal(err)
}
sheets, err := wb.List()
if err != nil {
t.Fatal(err)
}
for _, s := range sheets {
sheet, err := wb.Get(s)
if err != nil {
t.Fatal(err)
}
i := 0
for sheet.Next() {
row := strings.Join(sheet.Strings(), "\t")
if lines[i] != row {
t.Fatalf("line %d mismatch: '%s' <> '%s'", i, row, lines[i])
}
i++
}
}
err = wb.Close()
if err != nil {
t.Fatal(err)
}
}
func TestBasic2(t *testing.T) {
trueFile, err := os.ReadFile("../testdata/basic2.tsv")
if err != nil {
t.Skip()
}
lines := strings.Split(string(trueFile), "\n")
fn := "../testdata/basic2.xls"
wb, err := Open(fn)
if err != nil {
t.Fatal(err)
}
sheets, err := wb.List()
if err != nil {
t.Fatal(err)
}
for _, s := range sheets {
sheet, err := wb.Get(s)
if err != nil {
t.Fatal(err)
}
i := 0
for sheet.Next() {
row := strings.Join(sheet.Strings(), "\t")
if lines[i] != row {
t.Fatalf("line %d mismatch: '%s' <> '%s'", i, row, lines[i])
}
i++
}
}
err = wb.Close()
if err != nil {
t.Fatal(err)
}
}
func TestMulti(t *testing.T) {
trueFile, err := os.ReadFile("../testdata/multi_test.tsv")
if err != nil {
t.Skip()
}
lines := strings.Split(string(trueFile), "\n")
fn := "../testdata/multi_test.xls"
wb, err := Open(fn)
if err != nil {
t.Fatal(err)
}
sheets, err := wb.List()
if err != nil {
t.Fatal(err)
}
for _, s := range sheets {
sheet, err := wb.Get(s)
if err != nil {
t.Fatal(err)
}
i := 0
for sheet.Next() {
row := strings.Join(sheet.Strings(), "\t")
if lines[i] != row {
t.Fatalf("line %d mismatch: '%s' <> '%s'", i, row, lines[i])
}
i++
}
}
err = wb.Close()
if err != nil {
t.Fatal(err)
}
}