package dsl import ( "strings" "testing" ) const buildDefaultsPrefix = ` build_defaults { language = "c" standard = "c11" sources = "*.c" output = "sol" warnings = strict } ` func TestBuildAllFieldsParsed(t *testing.T) { src := ` build_defaults { language = "cpp" standard = "c++17" sources = "a.cpp" "b.cpp" includes = "inc" "inc2" output = "sol" warnings = pedantic wrapper = "timeout" sanitize = "address" "undefined" link = "-lm" extra = "-g" platforms = "linux" "darwin" compilers = "gcc" "clang" define("DEBUG") = "1" define("VERSION") = "2" } build "release" { profile = release } group("g") { weight = 1.0 test("t") { stdout = "" } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse: %v", err) } bd := f.BuildDefaults if bd == nil { t.Fatal("no build_defaults") } if bd.Language != "cpp" || bd.Standard != "c++17" || bd.Output != "sol" { t.Errorf("basic fields wrong: %+v", bd) } if bd.Warnings != WarningsPedantic { t.Errorf("Warnings = %v", bd.Warnings) } if bd.Wrapper != "timeout" { t.Errorf("Wrapper = %q", bd.Wrapper) } if len(bd.Sources) != 2 || len(bd.Includes) != 2 || len(bd.Sanitize) != 2 { t.Errorf("lists: sources=%v includes=%v sanitize=%v", bd.Sources, bd.Includes, bd.Sanitize) } if len(bd.Link) != 1 || len(bd.Extra) != 1 { t.Errorf("link/extra: %v / %v", bd.Link, bd.Extra) } if len(bd.Platforms) != 2 || len(bd.Compilers) != 2 { t.Errorf("platforms/compilers: %v / %v", bd.Platforms, bd.Compilers) } if bd.Defines["DEBUG"] != "1" || bd.Defines["VERSION"] != "2" { t.Errorf("Defines = %v", bd.Defines) } } func TestBuildOSOverrides(t *testing.T) { src := ` build_defaults { language = "c" standard = "c11" sources = "main.c" output = "sol" warnings = strict } build "release" { profile = release linux { extra = "-pthread" } windows { extra = "/MT" } darwin { extra = "-framework CoreFoundation" } } group("g") { weight = 1.0 test("t") { stdout = "" } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse: %v", err) } b := f.Builds[0] if b.Linux == nil || b.Windows == nil || b.Darwin == nil { t.Errorf("OS overrides missing: %+v", b) } } func TestBuildOSNestedForbidden(t *testing.T) { src := buildDefaultsPrefix + ` build "r" { profile = release linux { darwin { extra = "-x" } } } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "nested inside another OS override") { t.Errorf("want nested OS override error, got %v", err) } } func TestBuildDuplicateOSOverride(t *testing.T) { src := buildDefaultsPrefix + ` build "r" { profile = release linux { extra = "-a" } linux { extra = "-b" } } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "duplicate linux override") { t.Errorf("want duplicate linux override, got %v", err) } } func TestBuildUnknownField(t *testing.T) { src := ` build_defaults { bogus = "x" language = "c" standard = "c11" sources = "main.c" output = "sol" warnings = strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "unknown field") { t.Errorf("want unknown field error, got %v", err) } } func TestBuildUnknownProfile(t *testing.T) { src := ` build_defaults { language = "c" standard = "c11" sources = "main.c" output = "sol" warnings = strict } build "weird" { profile = bogus } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "unknown profile") { t.Errorf("want unknown profile error, got %v", err) } } func TestBuildUnknownWarnings(t *testing.T) { src := ` build_defaults { language = "c" standard = "c11" sources = "main.c" output = "sol" warnings = bogus } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "unknown warnings level") { t.Errorf("want unknown warnings error, got %v", err) } } func TestBuildWarningsDefaultAndStrict(t *testing.T) { src := ` build_defaults { language = "c" standard = "c11" sources = "main.c" output = "sol" warnings = default } build "r" { warnings = strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse: %v", err) } if f.BuildDefaults.Warnings != WarningsDefault { t.Errorf("defaults warnings = %v", f.BuildDefaults.Warnings) } if f.Builds[0].Warnings != WarningsStrict { t.Errorf("build warnings = %v", f.Builds[0].Warnings) } } func TestBuildInvalidPlatform(t *testing.T) { src := buildDefaultsPrefix + ` build "r" { profile = release platforms = "bsd" } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "unknown platform") { t.Errorf("want unknown platform error, got %v", err) } } func TestBuildAssignStringMissingAssign(t *testing.T) { src := ` build_defaults { language "c" standard = "c11" sources = "main.c" output = "sol" warnings = strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "expected") { t.Errorf("want expected = error, got %v", err) } } func TestBuildAssignStringListMissingAssign(t *testing.T) { src := ` build_defaults { language = "c" standard = "c11" sources "main.c" output = "sol" warnings = strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "expected") { t.Errorf("want expected = error, got %v", err) } } func TestBuildDefineErrors(t *testing.T) { cases := []string{ `build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict define "K" = "v" }`, `build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict define(K) = "v" }`, `build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict define("K" = "v" }`, `build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict define("K") "v" }`, `build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict define("K") = K }`, } for i, src := range cases { full := src + "\ngroup(\"g\") { weight = 1.0 test(\"t\") { stdout = \"\" } }" if _, _, err := Parse(full); err == nil { t.Errorf("case %d: expected error", i) } } } func TestBuildNonIdentInBlock(t *testing.T) { src := ` build_defaults { "not-an-ident" = "x" } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "unexpected token") { t.Errorf("want unexpected token error, got %v", err) } } func TestToolchainsDuplicateInSameBlock(t *testing.T) { src := ` toolchains { gcc { platforms = "linux" } gcc { platforms = "darwin" } } build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "duplicate toolchain") { t.Errorf("want duplicate toolchain error, got %v", err) } } func TestToolchainsMissingPlatforms(t *testing.T) { src := ` toolchains { gcc { binary = "gcc-13" } } build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "platforms is required") { t.Errorf("want platforms-required error, got %v", err) } } func TestToolchainsBadName(t *testing.T) { src := ` toolchains { 42 { platforms = "linux" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "expected toolchain name") { t.Errorf("want toolchain name error, got %v", err) } } func TestToolchainsUnknownField(t *testing.T) { src := ` toolchains { gcc { platforms = "linux" bogus = "x" } } build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "unknown field") { t.Errorf("want unknown field error, got %v", err) } } func TestToolchainsUnknownClass(t *testing.T) { src := ` toolchains { gcc { platforms = "linux" class = bogus } } build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` _, _, err := Parse(src) if err == nil || !strings.Contains(err.Error(), "unknown compiler class") { t.Errorf("want unknown class error, got %v", err) } } func TestToolchainsClassAndBinary(t *testing.T) { src := ` toolchains { gcc13 { platforms = "linux" binary = "gcc-13" class = gnu } msvc { platforms = "windows" class = msvc } } build_defaults { language="c" standard="c11" sources="x.c" output="s" warnings=strict } group("g") { weight = 1.0 test("t") { stdout = "" } } ` f, _, err := Parse(src) if err != nil { t.Fatalf("parse: %v", err) } if len(f.Toolchains) != 2 { t.Fatalf("toolchains = %d", len(f.Toolchains)) } if f.Toolchains[0].Binary != "gcc-13" || f.Toolchains[0].Class != "gnu" { t.Errorf("gcc13 = %+v", f.Toolchains[0]) } if f.Toolchains[1].Class != "msvc" { t.Errorf("msvc class = %q", f.Toolchains[1].Class) } }