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:
parent
f02fd82e53
commit
136244017b
155
commonxl/cell.go
155
commonxl/cell.go
@ -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)")
|
||||
}
|
||||
|
@ -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
7
testdata/testing.tsv
vendored
Normal 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
|
|
BIN
testdata/testing.xls
vendored
Normal file
BIN
testdata/testing.xls
vendored
Normal file
Binary file not shown.
@ -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
|
||||
|
@ -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])
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user