test: expand dsl/runner coverage and add go-test CI workflow
All checks were successful
go-test / go test (push) Successful in 56s
All checks were successful
go-test / go test (push) Successful in 56s
- Add dsl/matcher_test.go covering ExactMatcher, ContainsMatcher,
RegexMatcher, NumericEpsMatcher, AnyOrderMatcher and NoMatcher —
previously 0% — including epsilon, count mismatch, unparsable
numbers, invalid regex, and splitLines edge cases.
- Add dsl/ast_test.go for the new Test.SetInputFile / SetStdin /
SetOutputFile / SetStdout helpers and Pattern.IsDirMode.
- Add dsl/build_string_test.go covering BuildProfile.String,
WarningLevel.String and BuildConfig.MergeFrom (wrapper, defines
into nil map, defines override existing, nil src).
- Add dsl/merge_test.go driving mergeFiles to 100%: legacy build
fields, duplicate toolchain/build/group from include, binary /
sources / normalize_crlf / trim_trailing_ws propagation, local
overrides of timeout and memory_limit.
- Add dsl/parser_features_test.go for parseTest / parseGroup happy
paths that were missing: file/outFile, env, wrapper, per-test
timeout/memory overrides, non-zero exitCode, scoring partial /
all_or_none and unknown scoring.
- Add dsl/parser_errors_test.go, a 54-case table-driven test that
hits every `expect(...)` error branch in parseGroup and parseTest
(missing LPAREN/RPAREN/LBRACE/RBRACE/ASSIGN, wrong token types on
weight/timeout/memory_limit/scoring/env/wrapper/file/outFile, and
unclosed blocks).
- Add dsl/parser_misc_test.go covering parsePattern dir-mode with
args, unknown pattern field, non-ident in pattern, top-level
binary / sources / normalize_crlf / trim_trailing_ws / bare-int
memory_limit, parseBool invalid ident and non-ident, matcher
without an operator, validateBuilds legacy+structured conflict.
- Add dsl/build_parser_test.go covering every BuildConfig field
(sources, includes, sanitize, link, extra, platforms, compilers,
defines), OS overrides on named builds, nested / duplicate OS
override errors, unknown build / profile / warnings / platform,
missing = on assign-string and assign-string-list, define(...)
error cases, and parseToolchainsBlock (duplicate name, missing
platforms, bad name token, unknown field, unknown compiler class,
binary and class propagation).
- Add dsl/lexer_test.go for Token.String, TokenType.String UNKNOWN
branch, line comments, unterminated string and heredoc, unknown
escape sequence, escape decoding, unexpected character, every
K/M/G/KiB/MiB/GiB size suffix, ms/s/m duration suffixes, negative
integer lexing and float literals.
- Extend runner/result_test.go with Status.String and
TestResult.addFailure (both previously 0%).
- Add .gitea/workflows/go-test.yml running `go vet` and
`go test -race -coverprofile=coverage.out ./...` on push,
pull_request and manual dispatch, uploading coverage.out as an
artifact.
Coverage: dsl 60.5% -> 85%+, runner 29.0% -> 30.5%.
This commit is contained in:
379
dsl/build_parser_test.go
Normal file
379
dsl/build_parser_test.go
Normal file
@@ -0,0 +1,379 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user