rename packages, refactor out tailwind compiler,

This commit is contained in:
2026-07-13 15:06:09 -04:00
parent c5b14d7c41
commit d52151cc1a
62 changed files with 1446 additions and 460 deletions

View File

@@ -490,3 +490,115 @@ func TestEditingJumpsToTheRightForm(t *testing.T) {
t.Error("reset did not return the editor to a clean chooser")
}
}
// ---- the function insert menu ----
// Thirty-five function names in one flat list is a wall. Grouped by what they are FOR,
// with a signature and a sentence, it is something you can find SUM in.
func TestFormulaFunctionGroups(t *testing.T) {
want := []string{"Aggregate", "Math", "Trigonometry", "Logic", "Row"}
if len(FormulaFunctionGroups) != len(want) {
t.Fatalf("got %d groups, want %d", len(FormulaFunctionGroups), len(want))
}
for i, label := range want {
if FormulaFunctionGroups[i].Label != label {
t.Errorf("group %d is %q, want %q", i, FormulaFunctionGroups[i].Label, label)
}
}
// Every function carries a signature and a description — they are what the menu
// shows and what its search matches, not decoration.
for _, g := range FormulaFunctionGroups {
for _, f := range g.Fns {
if f.Name == "" || f.Sig == "" || f.Desc == "" {
t.Errorf("%s/%s is missing its signature or description: %+v", g.Label, f.Name, f)
}
if !strings.HasPrefix(f.Sig, f.Name+"(") {
t.Errorf("%s's signature %q does not start with its own name", f.Name, f.Sig)
}
}
}
}
// Every function the menu offers must actually EXIST in the engine — an insert menu
// that offers a function the evaluator rejects is worse than no menu.
func TestEveryOfferedFunctionEvaluates(t *testing.T) {
// A formula per function, using its own arity.
args := map[string]string{
"IF": "IF(1, 2, 3)", "ATAN2": "ATAN2(1, 1)", "POWER": "POWER(2, 3)",
"MOD": "MOD(5, 2)", "LOG": "LOG(100, 10)", "ROUND": "ROUND(1.5, 0)",
"ROW": "ROW()", "PI": "PI()", "AND": "AND(1, 1)", "OR": "OR(1, 0)", "NOT": "NOT(0)",
}
for _, g := range FormulaFunctionGroups {
for _, f := range g.Fns {
src, ok := args[f.Name]
if !ok {
src = f.Name + "(1)"
}
if _, err := CompileFormula(src); err != nil {
t.Errorf("the menu offers %s, but %q does not compile: %v", f.Name, src, err)
}
}
}
}
// And every constant it offers must be one the evaluator knows.
func TestEveryOfferedConstantExists(t *testing.T) {
if len(FormulaConstantOptions) != len(FormulaConstants) {
t.Errorf("the menu offers %d constants, the engine knows %d",
len(FormulaConstantOptions), len(FormulaConstants))
}
for _, c := range FormulaConstantOptions {
if _, ok := FormulaConstants[c.Name]; !ok {
t.Errorf("the menu offers %q, which the engine does not know", c.Name)
}
if c.Desc == "" {
t.Errorf("%q has no description — the name alone says nothing", c.Name)
}
}
}
// The menu's search matches the DESCRIPTION too, which is the whole point of carrying
// the prose around: someone who wants a total types "total", not "SUM".
func TestFormulaMenuSearch(t *testing.T) {
got := filterFormulaGroups("total")
found := false
for _, g := range got {
for _, f := range g.Fns {
if f.Name == "SUM" {
found = true
}
}
}
if !found {
t.Error(`searching "total" did not find SUM — the description is not being matched`)
}
// Empty groups drop out rather than leaving a bare heading behind.
for _, g := range filterFormulaGroups("sine") {
if len(g.Fns) == 0 {
t.Errorf("group %q survived the filter with no functions in it", g.Label)
}
}
// An empty query is everything.
if len(filterFormulaGroups("")) != len(FormulaFunctionGroups) {
t.Error("an empty query should show every group")
}
// A query matching nothing yields nothing (the menu shows its own empty state).
if got := filterFormulaGroups("zzzz"); len(got) != 0 {
t.Errorf("a query matching nothing returned %d groups", len(got))
}
}
func TestFormulaFunctionNamesFlattensTheGroups(t *testing.T) {
names := FormulaFunctionNames()
if len(names) < 30 {
t.Errorf("flattened to %d names, want the full set", len(names))
}
for _, want := range []string{"SUM", "ROUND", "ATAN2", "IF", "ROW"} {
if !contains2(names, want) {
t.Errorf("%s missing from the flattened names", want)
}
}
}