Files
judge/dsl/parser_test.go
2026-04-05 18:20:42 +03:00

218 lines
4.4 KiB
Go

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)
}
}