oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

1package xlsx_test
2
3import (
4 "encoding/json"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9)
10
11// oracleCorpusPath and oracleExclusionsPath point at the SAME committed
12// files internal/sheets/calc/corpus_test.go reads (corpusPath,
13// exclusionsPath there) — one corpus, cross-checked from two packages.
14// This package cannot import calc's _test.go types (Go test files are
15// not part of a package's importable surface), so the JSON shape is
16// duplicated here rather than shared; keep it in sync with corpus_test.go
17// if formulas.json's wire format ever changes.
18const (
19 oracleCorpusPath = "../calc/testdata/corpus/formulas.json"
20 oracleExclusionsPath = "../calc/testdata/corpus/volatile-excluded.txt"
21)
22
23// oracleCorpusValue mirrors calc's corpusValue (corpus_test.go): only
24// the field named by Kind is meaningful.
25type oracleCorpusValue struct {
26 Kind string `json:"kind"`
27 Num float64 `json:"num,omitempty"`
28 Str string `json:"str,omitempty"`
29 Bool bool `json:"bool,omitempty"`
30 Err string `json:"err,omitempty"`
31}
32
33// oracleCorpusEntry mirrors calc's corpusEntry. Want is carried through
34// for context in failure/log messages, but this harness's actual
35// comparison is our engine's live Eval output against excelize's live
36// CalcCellValue output — Want plays no part in that comparison, unlike
37// TestAgainstReferenceCorpus in the calc package, which checks Eval
38// against Want directly.
39type oracleCorpusEntry struct {
40 Function string `json:"function"`
41 Expr string `json:"expr"`
42 Want oracleCorpusValue `json:"want"`
43}
44
45type oracleCorpusFile struct {
46 Note string `json:"note"`
47 Entries []oracleCorpusEntry `json:"entries"`
48}
49
50// loadOracleCorpus reads and parses the same formulas.json
51// TestAgainstReferenceCorpus (calc package) uses.
52func loadOracleCorpus(t *testing.T) []oracleCorpusEntry {
53 t.Helper()
54 data, err := os.ReadFile(filepath.FromSlash(oracleCorpusPath))
55 if err != nil {
56 t.Fatalf("loadOracleCorpus: %v", err)
57 }
58 var cf oracleCorpusFile
59 if err := json.Unmarshal(data, &cf); err != nil {
60 t.Fatalf("loadOracleCorpus: %v", err)
61 }
62 if len(cf.Entries) == 0 {
63 t.Fatal("loadOracleCorpus: corpus has no entries")
64 }
65 return cf.Entries
66}
67
68// loadOracleExclusions parses the same volatile-excluded.txt
69// TestAgainstReferenceCorpus honors, for the same reason: NOW/TODAY
70// return a different answer on every evaluation (calc's env.Now() is
71// pinned per-pass to a fixed instant; excelize's NOW()/TODAY() read the
72// real wall clock), so no captured pair of answers from the two engines
73// can ever be expected to agree, independent of whether either engine
74// is "right." Skipping here mirrors calc's own reasoning, it does not
75// invent a new one.
76func loadOracleExclusions(t *testing.T) map[string]bool {
77 t.Helper()
78 data, err := os.ReadFile(filepath.FromSlash(oracleExclusionsPath))
79 if err != nil {
80 t.Fatalf("loadOracleExclusions: %v", err)
81 }
82 out := map[string]bool{}
83 for _, line := range strings.Split(string(data), "\n") {
84 line = strings.TrimSpace(line)
85 if line == "" || strings.HasPrefix(line, "#") {
86 continue
87 }
88 out[line] = true
89 }
90 return out
91}
92