Skip to content

Commit

Permalink
Merge pull request #15 from semperos/ari-test
Browse files Browse the repository at this point in the history
Ari test
  • Loading branch information
semperos authored Sep 13, 2024
2 parents 555b9af + 8504605 commit 407f4f3
Show file tree
Hide file tree
Showing 21 changed files with 184 additions and 79 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ jobs:
go-version: stable
- name: test
run: |
go test -v -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.txt ./...
./script/test
41 changes: 41 additions & 0 deletions ari.goal
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/ Shape
istbl:{and["d"=@x;&/"s"=@'!x;&/{(@'x)¿"ANSI"}x;&/(*ls)=ls:#'x]} / is x a dictionary-as-table
reshape:{((*/x)#y){(-y)$x}/|1_x} / Implementation by anaseto, shared on Matrix
shape:{-1_#:'*:\x} / Implementation by John Earnest, shared on k-tree
depths:{[ind;l]?[(@l)~"A";,/o[ind+1]'l; (@l)¿"NSI";(#l)#ind; ind-1]} / list depths
/ Output formats
md.tbl:{[t;fmt] / helper
k:!t; v:(..?[(@x)¿"nN";p.fmt$x;$'x])'.t; w:(-1+""#k)|(|/-1+""#)'v
(k;v):(-w)!'´(k;v); "|"+("|\n|"/,/"|"/(k;"-"*w;+v))+"|"}
Expand Down Expand Up @@ -31,4 +33,43 @@ ltx.lst:{[l;fmt] / helper
sprintf.ltx:{[x;fmt]?[istbl x;ltx.tbl[x;fmt]; (@x)¿"ANSI";ltx.lst[x;fmt]; "n"=@x;fmt$x; $x]} / LaTeX output
csv.tbl:{(*'x)!(1_'x)} / table from csv parsing, assumes header
json.tbl:{ks:!*x; vs:@[;ks]'x; ks!+vs} / table from parsing json array of like objects
/ Test Framework
tt.suite:"global"; tt.suitestate:..[es:();fs:();ps:();ss:()]; tt.state:..[global:tt.suitestate]
tt.st:tt.state; tt.ffast:0; tt.clear:{tt.st::tt.state}
tt.record:{[k;f;r] / key in test state; function tested; return value
suite:@[.;"FILE";:[;tt.suite]]
or[suite¿!tt.st;tt.st[suite]:tt.suitestate] / ensure starting suite state
?["ps"~k;(m:"\n"/" "+=r"msg"
d:..[f:p.f;p:p.r;msg:"function panicked with:\n$p.m"]
tt.st[suite]:@[tt.st[suite];"ps";..x,p.d])
"es"~k;(d:..[f:p.f;e:p.r;msg:"function returned error: $p.r\n $p.f"]
tt.st[suite]:@[tt.st[suite];"es";..x,p.d])
"fs"~k;(d:..[f:p.f;r:p.r;msg:"function returned $p.r instead of 1\n $p.f"]
tt.st[suite]:@[tt.st[suite];"fs";..x,p.d])
"ss"~k;(d:..[f:p.f]; tt.st[suite]:@[tt.st[suite];"ss";..x,p.d])
:error"tt.record k must be one of ps, es, fs, ss, but received $k"]}
tt.tf:{[f]
r:rt.try[f;0;{pmsg:x"msg";f:y; error[..[f:p.f;msg:p.pmsg;pnc:1]]}[;f]]
?["e"~@r;?[("d"[email protected])and(.r)..pnc;tt.record["ps";f;r];tt.record["es";f;r]]
1~r;tt.record["ss";f;r]
tt.record["fs";f;r]]
r}
tt.t:{?[("f"~@x);:tt.tf@x;error"tt.t expects f, received %s: %v"$(@x;x)]}
tt.fs:{sfx:"test.ari""test.goal"; pfx:"**/*""*"; fs:,/glob',/pfx+`sfx}
tt.file:{orig:@[.;"FILE";0]; ::["FILE";x]; ?[tt.ffast; 'eval 'read x;eval 'read x]; ::["FILE";or[orig;tt.suite]]; x}
tt.chkall:{
fs:tt.fs 0; rs:tt.file'fs; es:"e"=@'rs
?[|/es
[errors:(..p.es)#rs; files:(..p.es)#fs; error[(,"msg")!,"\n"/(files+": ")+(..msg)'errors]]
rs]}
tt.saymsg:{say " "+x"msg"}
tt.repsut:{[suite]
(ss;fs;es;ps):tt.st[suite][!"ss fs es ps"];(css;cfs;ces;cps):#'(ss;fs;es;ps)
bad:~+/(cfs;ces;cps); or[bad;say qq/Suite "$suite" has problems:/]
and[cfs;tt.saymsg'fs]; and[ces;tt.saymsg'es]; and[cps;tt.saymsg'ps]
s:qq/Suite "$suite" $css succeeded, $cfs failed, $ces errored, $cps panicked/
?[and[tt.suite~suite;+/#'tt.st[tt.suite]];say s; ~tt.suite~suite;say s;0]}
tt.report:{
tt.repsut'!tt.st; (tes;tfs;tps;tss):+/#''. .'tt.st; say "Total $tss succeeded, $tfs failed, $tes errored, $tps panicked"
and[|//@[;!"es fs ps"]'#''tt.st;error["Tests failed."]]}
1
48 changes: 36 additions & 12 deletions cmd/ari/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ const (
const (
cliModeGoalPrompt = " "
cliModeGoalNextPrompt = " "
cliModeSQLReadOnlyPrompt = "sql> "
cliModeSQLReadOnlyPrompt = "sql) "
cliModeSQLReadOnlyNextPrompt = " > "
cliModeSQLReadWritePrompt = "sql!> "
cliModeSQLReadWritePrompt = "sql!) "
cliModeSQLReadWriteNextPrompt = " > "
)

Expand Down Expand Up @@ -81,6 +81,7 @@ func (cliSystem *CliSystem) switchMode(cliMode cliMode, args []string) error {

func (cliSystem *CliSystem) switchModeToGoal() error {
cliSystem.cliMode = cliModeGoal
cliSystem.prompt = cliModeGoalPrompt
if !cliSystem.rawREPL {
cliSystem.cliEditor.Prompt = cliModeGoalPrompt
cliSystem.cliEditor.NextPrompt = cliModeGoalNextPrompt
Expand Down Expand Up @@ -114,6 +115,7 @@ func (cliSystem *CliSystem) switchModeToSQLReadOnly(args []string) error {
}
}
cliSystem.cliMode = cliModeSQLReadOnly
cliSystem.prompt = cliModeSQLReadOnlyPrompt
if !cliSystem.rawREPL {
cliSystem.cliEditor.CheckInputComplete = modeSQLCheckInputComplete
cliSystem.cliEditor.AutoComplete = cliSystem.autoCompleter.sqlAutoCompleteFn()
Expand Down Expand Up @@ -141,6 +143,7 @@ func (cliSystem *CliSystem) switchModeToSQLReadWrite(args []string) error {
}
}
cliSystem.cliMode = cliModeSQLReadOnly
cliSystem.prompt = cliModeSQLReadWritePrompt
if !cliSystem.rawREPL {
cliSystem.cliEditor.CheckInputComplete = modeSQLCheckInputComplete
cliSystem.cliEditor.AutoComplete = cliSystem.autoCompleter.sqlAutoCompleteFn()
Expand Down Expand Up @@ -243,6 +246,12 @@ func ariMain(cmd *cobra.Command, args []string) int {
// MUST PRECEDE EXECUTE/REPL
goalFilesToLoad := viper.GetStringSlice("load")
for _, f := range goalFilesToLoad {
var path string
path, err = filepath.Abs(f)
if err != nil {
fmt.Fprintf(os.Stderr, "File to load %s is not recognized as a path on your system: %v", f, err)
}
ariContext.GoalContext.AssignGlobal("FILE", goal.NewS(path))
_, err = runScript(&mainCliSystem, f)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load file %q with error: %v", f, err)
Expand All @@ -261,10 +270,17 @@ func ariMain(cmd *cobra.Command, args []string) int {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
return 1
}
//nolint:nestif // separate returns in each if
if programToExecute != "" {
goalV, errr := runCommand(&mainCliSystem, programToExecute)
if errr != nil {
fmt.Fprintf(os.Stderr, "Failed to execute program:\n%q\n with error:\n%v\n", programToExecute, err)
var goalV goal.V
goalV, err = runCommand(&mainCliSystem, programToExecute)
if goalV.IsError() {
ee := newExitError(ariContext.GoalContext, goalV.Error())
formatREPLError(ee)
return ee.Code
}
if err != nil {
fmt.Fprintf(os.Stderr, "Program panicked with: %v\n \n%q\n", err, programToExecute)
return 1
}
// Support -e/--execute along with a file argument.
Expand All @@ -284,8 +300,9 @@ func ariMain(cmd *cobra.Command, args []string) int {
fmt.Fprintf(os.Stderr, "File %q is not recognized as a path on your system: %v", f, err)
}
ariContext.GoalContext.AssignGlobal("FILE", goal.NewS(path))
goalV, errr := runScript(&mainCliSystem, f)
if errr != nil {
var goalV goal.V
goalV, err = runScript(&mainCliSystem, f)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to run file %q with error: %v", f, err)
return 1
}
Expand Down Expand Up @@ -493,7 +510,7 @@ func (e *ExitError) Error() string {
// newExitError produces an *ExitError from a Goal error value.
//
// Adapted from Goal's implementation.
func newExitError(ctx *goal.Context, e *goal.Error) error {
func newExitError(ctx *goal.Context, e *goal.Error) *ExitError {
ee := &ExitError{Msg: e.Msg(ctx)}
if d, ok := e.Value().BV().(*goal.D); ok {
if v, ok := d.Get(goal.NewS("code")); ok {
Expand Down Expand Up @@ -576,27 +593,34 @@ func detectAriPrint(goalContext *goal.Context) func(goal.V) {
}

func (cliSystem *CliSystem) replEvalSQLReadOnly(line string) {
_, err := cliSystem.sqlQuery(line, nil)
goalV, err := cliSystem.sqlQuery(line, nil)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to run SQL query %q\nDatabase Error:%s\n", line, err)
} else {
return
}
if cliSystem.outputFormat == outputFormatGoal {
_, err := cliSystem.ariContext.GoalContext.Eval(`fmt.tbl[sql.p;*#'sql.p;#sql.p;"%.1f"]`)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to print SQL query results via Goal evaluation: %v\n", err)
}
return
}
printInOutputFormat(cliSystem.ariContext.GoalContext, cliSystem.outputFormat, goalV)
}

func (cliSystem *CliSystem) replEvalSQLReadWrite(line string) {
_, err := cliSystem.sqlExec(line, nil)
goalV, err := cliSystem.sqlExec(line, nil)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to run SQL query %q\nDatabase Error:%s\n", line, err)
} else {
return
}
if cliSystem.outputFormat == outputFormatGoal {
_, err := cliSystem.ariContext.GoalContext.Eval(`fmt.tbl[sql.p;*#'sql.p;#sql.p;"%.1f"]`)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to print SQL exec results via Goal evaluation: %v\n", err)
}
}
printInOutputFormat(cliSystem.ariContext.GoalContext, cliSystem.outputFormat, goalV)
}

func (cliSystem *CliSystem) replEvalSystemCommand(line string) error {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.21
toolchain go1.22.0

require (
codeberg.org/anaseto/goal v0.43.1-0.20240904143145-df99d8e0051b
codeberg.org/anaseto/goal v0.43.1-0.20240910104443-7553fb1f7fe3
github.com/charmbracelet/lipgloss v0.13.0
github.com/go-resty/resty/v2 v2.14.0
github.com/jarcoal/httpmock v1.3.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
codeberg.org/anaseto/goal v0.43.1-0.20240904143145-df99d8e0051b h1:P3prjSjmz8wYHT4iTg3ZYivbcpaHmL7G5KrW37Xqx04=
codeberg.org/anaseto/goal v0.43.1-0.20240904143145-df99d8e0051b/go.mod h1:oipi4mkQiwXW9Td2IxNhuMV0Ewq4obs6EvkqpyZ6qMs=
codeberg.org/anaseto/goal v0.43.1-0.20240910104443-7553fb1f7fe3 h1:BSx4JTolD3SLv8kzBxNlg3qWbikchp99xsj6H6tYH7c=
codeberg.org/anaseto/goal v0.43.1-0.20240910104443-7553fb1f7fe3/go.mod h1:oipi4mkQiwXW9Td2IxNhuMV0Ewq4obs6EvkqpyZ6qMs=
github.com/apache/arrow/go/v17 v17.0.0 h1:RRR2bdqKcdbss9Gxy2NS/hK8i4LDMh23L6BbkN5+F54=
github.com/apache/arrow/go/v17 v17.0.0/go.mod h1:jR7QHkODl15PfYyjM2nU+yTLScZ/qfj7OSUZmJ8putc=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
Expand Down
32 changes: 32 additions & 0 deletions goal.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
_ "embed"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"

Expand Down Expand Up @@ -99,6 +100,7 @@ func printV(ctx *goal.Context, x goal.V) error {
}
}

// Implements help dyad.
func VFHelpFn(help Help) func(goalContext *goal.Context, args []goal.V) goal.V {
return func(goalContext *goal.Context, args []goal.V) goal.V {
x := args[len(args)-1]
Expand Down Expand Up @@ -220,6 +222,34 @@ func helpTriadic(help Help, x goal.V, args []goal.V) goal.V {
return goal.NewI(1)
}

// Implements glob monad.
func VFGlob(_ *goal.Context, args []goal.V) goal.V {
x := args[len(args)-1]
globPatternS, ok := x.BV().(goal.S)
if !ok {
return panicType("glob s", "s", x)
}
match, err := filepath.Glob(string(globPatternS))
if err != nil {
return goal.NewPanicError(err)
}
return goal.NewAS(match)
}

// Implements abspath monad.
func VFAbsPath(_ *goal.Context, args []goal.V) goal.V {
x := args[len(args)-1]
globPatternS, ok := x.BV().(goal.S)
if !ok {
return panicType("abspath s", "s", x)
}
path, err := filepath.Abs(string(globPatternS))
if err != nil {
return goal.NewPanicError(err)
}
return goal.NewS(path)
}

// Go <> Goal helpers

func stringMapFromGoalDict(d *goal.D) (map[string]string, error) {
Expand Down Expand Up @@ -273,6 +303,8 @@ func goalRegisterVariadics(ariContext *Context, goalContext *goal.Context, help
gos.Import(goalContext, "")
// Ari
// Monads
goalContext.RegisterMonad("abspath", VFAbsPath)
goalContext.RegisterMonad("glob", VFGlob)
goalContext.RegisterMonad("sql.close", VFSqlClose)
goalContext.RegisterMonad("sql.open", VFSqlOpen)
goalContext.RegisterMonad("time.now", VFTimeNow)
Expand Down
30 changes: 9 additions & 21 deletions goal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
)

func TestGoalOk(t *testing.T) {
t.Parallel()
// t.Parallel() // go test reports data race
tests := map[string]struct {
input string
result string
Expand Down Expand Up @@ -57,7 +57,7 @@ func TestGoalOk(t *testing.T) {
t.Fatalf("error creating ari Context: %v", err)
}
t.Run(name, func(t *testing.T) {
t.Parallel()
// t.Parallel() // go test reports data race
goalV, err := goalCtx.Eval(test.input)
if err != nil {
t.Fatalf("Context.GoalContext.Eval(%q) returned an error: %v", test.input, err)
Expand All @@ -71,7 +71,7 @@ func TestGoalOk(t *testing.T) {
}

func TestGoalError(t *testing.T) {
t.Parallel()
// t.Parallel() // go test reports data race
tests := map[string]struct {
input string
errMsg string
Expand All @@ -89,7 +89,7 @@ func TestGoalError(t *testing.T) {
t.Fatalf("error creating ari Context: %v", err)
}
t.Run(name, func(t *testing.T) {
t.Parallel()
// t.Parallel() // go test reports data race
goalV, err := goalCtx.Eval(test.input)
if err == nil {
t.Fatalf("Context.GoalContext.Eval(%q) should return an error, but instead returned: %v",
Expand Down Expand Up @@ -118,7 +118,7 @@ type matchTest struct {

// Adapted from Goal implementation.
func getMatchTests(glob string) ([]matchTest, error) {
d := os.DirFS("testing/")
d := os.DirFS("testing/via-go/")
fnames, err := fs.Glob(d, glob)
if err != nil {
return nil, err
Expand Down Expand Up @@ -192,15 +192,11 @@ func TestEval(t *testing.T) {
if err != nil {
t.Fatalf("getMatchTests: %v", err)
}
smts, err := getScriptMatchTests("*.goal")
if err != nil {
t.Fatalf("getScriptMatchTests: %v", err)
}
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("failed to get current working directory: %v", err)
}
for _, mt := range append(mts, smts...) {
for _, mt := range mts {
if mt.Fname == "errors.goal" {
continue
}
Expand Down Expand Up @@ -229,17 +225,9 @@ func TestEval(t *testing.T) {
defer httpmock.DeactivateAndReset()
registerHTTPMocks()

if mt.IsScript {
ariContextLeft.GoalContext.AssignGlobal("ARGS", goal.NewAS([]string{mt.Fname}))
err = os.Chdir(cwd + "/testing/scripts")
if err != nil {
t.Fatalf("failed to chdir to 'testing/scripts': %v", err)
}
} else {
err = os.Chdir(cwd + "/testing")
if err != nil {
t.Fatalf("failed to chdir to 'testing': %v", err)
}
err = os.Chdir(cwd + "/testing/via-go/")
if err != nil {
t.Fatalf("failed to chdir to 'testing/via-go': %v", err)
}
err = ariContextLeft.GoalContext.Compile(mt.Left, "", "")
ps := ariContextLeft.GoalContext.String()
Expand Down
5 changes: 5 additions & 0 deletions script/ari-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env sh

set -e

ari -e " 'tt.chkall 0; tt.report 0"
5 changes: 5 additions & 0 deletions script/install
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env sh

set -e

go install ./cmd/ari
4 changes: 4 additions & 0 deletions script/test
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#!/usr/bin/env sh

set -e

go test -v -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.txt ./...
go install ./cmd/ari
./script/ari-test
4 changes: 2 additions & 2 deletions sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ func sqlQMonadic(x goal.V, sqlDatabase *SQLDatabase, goalContext *goal.Context)
}
var err error
if sqlDatabase.DB == nil || !sqlDatabase.IsOpen {
fmt.Fprintf(os.Stdout, "Opening database %q\n", sqlDatabase.DataSource)
// fmt.Fprintf(os.Stdout, "Opening database %q\n", sqlDatabase.DataSource)
err = sqlDatabase.Open()
if err != nil {
return goal.NewPanicError(err)
Expand Down Expand Up @@ -307,7 +307,7 @@ func sqlExecMonadic(x goal.V, sqlDatabase *SQLDatabase, goalContext *goal.Contex
}
var err error
if sqlDatabase.DB == nil || !sqlDatabase.IsOpen {
fmt.Fprintf(os.Stdout, "Opening database %q\n", sqlDatabase.DataSource)
// fmt.Fprintf(os.Stdout, "Opening database %q\n", sqlDatabase.DataSource)
err = sqlDatabase.Open()
if err != nil {
return goal.NewPanicError(err)
Expand Down
1 change: 1 addition & 0 deletions testing/ari-test.goal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tt.t{1<#glob"*.md"}
1 change: 1 addition & 0 deletions testing/error-test.goal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tt.t {42=@[{http.xyz};0;{42}]}
1 change: 0 additions & 1 deletion testing/errors.goal

This file was deleted.

Loading

0 comments on commit 407f4f3

Please sign in to comment.