package dsl import ( "testing" "time" ) func TestParseBasic(t *testing.T) { src := ` build "go build -o solution ." timeout 10s group("basic") { weight = 0.4 test("stdin stdout") { stdin = "5\n1 3 2 5 4\n" stdout = "1 2 3 4 5\n" } test("args") { args = "--count" "3" exitCode = 0 stdout contains "foo" } } group("files") { weight = 0.6 timeout = 5s pattern { input = "testdata/*/input.txt" output = "testdata/*/output.txt" } } ` f, warns, err := Parse(src) if err != nil { t.Fatalf("parse error: %v", err) } if len(warns) > 0 { t.Logf("warnings: %v", warns) } if f.Build != "go build -o solution ." { t.Errorf("wrong build: %q", f.Build) } if f.Timeout != 10*time.Second { t.Errorf("wrong timeout: %v", f.Timeout) } if len(f.Groups) != 2 { t.Fatalf("expected 2 groups, got %d", len(f.Groups)) } g0 := f.Groups[0] if g0.Name != "basic" { t.Errorf("wrong group name: %q", g0.Name) } if g0.Weight != 0.4 { t.Errorf("wrong weight: %v", g0.Weight) } if len(g0.Tests) != 2 { t.Fatalf("expected 2 tests, got %d", len(g0.Tests)) } t0 := g0.Tests[0] if t0.Name != "stdin stdout" { t.Errorf("wrong test name: %q", t0.Name) } if t0.Stdin == nil || *t0.Stdin != "5\n1 3 2 5 4\n" { t.Errorf("wrong stdin: %v", t0.Stdin) } exact, ok := t0.Stdout.(ExactMatcher) if !ok { t.Errorf("expected ExactMatcher, got %T", t0.Stdout) } else if exact.Value != "1 2 3 4 5\n" { t.Errorf("wrong stdout: %q", exact.Value) } t1 := g0.Tests[1] if len(t1.Args) != 2 || t1.Args[0] != "--count" || t1.Args[1] != "3" { t.Errorf("wrong args: %v", t1.Args) } if _, ok := t1.Stdout.(ContainsMatcher); !ok { t.Errorf("expected ContainsMatcher, got %T", t1.Stdout) } g1 := f.Groups[1] if g1.Pattern == nil { t.Fatal("expected pattern in group files") } if g1.Pattern.InputGlob != "testdata/*/input.txt" { t.Errorf("wrong input glob: %q", g1.Pattern.InputGlob) } if g1.Timeout != 5*time.Second { t.Errorf("wrong group timeout: %v", g1.Timeout) } } func TestWeightWarning(t *testing.T) { src := ` build "go build ." group("a") { weight = 0.3 test("x") { stdin = "" stdout = "" } } group("b") { weight = 0.3 test("y") { stdin = "" stdout = "" } } ` _, warns, err := Parse(src) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(warns) == 0 { t.Error("expected weight warning, got none") } t.Logf("warn: %v", warns) } func TestHeredoc(t *testing.T) { src := ` build "go build ." group("g") { weight = 1.0 test("heredoc") { stdin = """ hello world """ stdout = """ HELLO WORLD """ } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse error: %v", err) } test := f.Groups[0].Tests[0] if *test.Stdin != "hello\nworld" { t.Errorf("wrong stdin: %q", *test.Stdin) } exact := test.Stdout.(ExactMatcher) if exact.Value != "HELLO\nWORLD" { t.Errorf("wrong stdout: %q", exact.Value) } } func TestMatchers(t *testing.T) { src := ` build "go build ." group("matchers") { weight = 1.0 test("regex") { stdin = "ping\n" stdout matches "pong.*" } test("numeric") { stdin = "1 3\n" stdout ~ 0.001 of "0.333" } test("any order") { stdin = "data\n" stdout anyOrder { "line1" "line2" "line3" } } test("stderr contains") { args = "--invalid" exitCode = 1 stderr contains "invalid flag" } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse error: %v", err) } tests := f.Groups[0].Tests if _, ok := tests[0].Stdout.(RegexMatcher); !ok { t.Errorf("test 0: expected RegexMatcher, got %T", tests[0].Stdout) } num, ok := tests[1].Stdout.(NumericEpsMatcher) if !ok { t.Errorf("test 1: expected NumericEpsMatcher, got %T", tests[1].Stdout) } else if num.Epsilon != 0.001 { t.Errorf("test 1: wrong epsilon %v", num.Epsilon) } if _, ok := tests[2].Stdout.(AnyOrderMatcher); !ok { t.Errorf("test 2: expected AnyOrderMatcher, got %T", tests[2].Stdout) } if _, ok := tests[3].Stderr.(ContainsMatcher); !ok { t.Errorf("test 3: expected ContainsMatcher on stderr, got %T", tests[3].Stderr) } if *tests[3].ExitCode != 1 { t.Errorf("test 3: expected exitCode 1, got %v", *tests[3].ExitCode) } }