package dsl import ( "strings" "testing" ) func TestParsePatternDirsMode(t *testing.T) { src := ` build "make" group("g") { weight = 1.0 pattern { dirs = "tests/*" input = "in.txt" output = "out.txt" args = "--case" "{name}" } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse: %v", err) } pat := f.Groups[0].Pattern if pat == nil { t.Fatal("no pattern") } if pat.DirsGlob != "tests/*" { t.Errorf("DirsGlob = %q", pat.DirsGlob) } if pat.InputFile != "in.txt" || pat.OutputFile != "out.txt" { t.Errorf("InputFile/OutputFile = %q/%q", pat.InputFile, pat.OutputFile) } if len(pat.Args) != 2 || pat.Args[0] != "--case" || pat.Args[1] != "{name}" { t.Errorf("Args = %v", pat.Args) } } func TestParsePatternUnknownField(t *testing.T) { src := ` build "make" group("g") { weight = 1.0 pattern { bogus = "x" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "unknown pattern field") { t.Errorf("want unknown pattern field error, got %v", err) } } func TestParsePatternNonIdent(t *testing.T) { src := ` build "make" group("g") { weight = 1.0 pattern { "x" = "y" } } ` _, _, err := Parse(src) if err == nil { t.Error("expected error on non-ident in pattern") } } func TestParseNormalizeCRLFAndTrimWS(t *testing.T) { src := ` build "make" normalize_crlf = true trim_trailing_ws = false group("g") { weight = 1.0 test("t") { stdout = "" } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse: %v", err) } if !f.NormalizeCRLF { t.Error("NormalizeCRLF should be true") } if f.TrimTrailingWS { t.Error("TrimTrailingWS should be false") } } func TestParseBinaryAndSources(t *testing.T) { src := ` build "make" binary = "sol" sources = "main.c" group("g") { weight = 1.0 test("t") { stdout = "" } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse: %v", err) } if f.Binary != "sol" { t.Errorf("Binary = %q", f.Binary) } if f.Sources != "main.c" { t.Errorf("Sources = %q", f.Sources) } } func TestParseMemoryLimitBareInt(t *testing.T) { src := ` build "make" memory_limit = 1024 group("g") { weight = 1.0 test("t") { stdout = "" } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse: %v", err) } if f.MemoryLimit != 1024 { t.Errorf("MemoryLimit = %d, want 1024", f.MemoryLimit) } } func TestParseBoolInvalidIdent(t *testing.T) { _, _, err := Parse("build \"make\"\nnormalize_crlf = maybe\n") if err == nil || !strings.Contains(err.Error(), "true/false") { t.Errorf("want true/false error, got %v", err) } } func TestParseBoolNonIdent(t *testing.T) { _, _, err := Parse("build \"make\"\nnormalize_crlf = \"true\"\n") if err == nil || !strings.Contains(err.Error(), "true/false") { t.Errorf("want true/false error, got %v", err) } } func TestParseTopLevelNonIdent(t *testing.T) { _, _, err := Parse(`"stray"`) if err == nil || !strings.Contains(err.Error(), "unexpected token") { t.Errorf("want unexpected token error, got %v", err) } } func TestParseMatcherOrAssignNoMatcher(t *testing.T) { src := ` build "make" group("g") { weight = 1.0 test("t") { stdout 42 } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "expected matcher") { t.Errorf("want matcher error, got %v", err) } } func TestParseStringListEmpty(t *testing.T) { src := ` build "make" group("g") { weight = 1.0 test("t") { args = stdout = "" } } ` _, _, err := Parse(src) if err == nil { t.Error("expected error on empty string list") } } func TestParseFileMissing(t *testing.T) { _, _, err := ParseFile("/nonexistent/judge-test-does-not-exist.jdg") if err == nil { t.Error("expected error on missing file") } } func TestValidateBuildsMixedLegacyAndStructured(t *testing.T) { src := ` build "legacy shell" build_defaults { language = "c" standard = "c11" sources = "*.c" output = "sol" warnings = strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "cannot mix legacy") { t.Errorf("want mix-legacy error, got %v", err) } }