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%.
176 lines
4.2 KiB
Go
176 lines
4.2 KiB
Go
package dsl
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestTokenStringAndUnknownType(t *testing.T) {
|
|
tok := Token{Type: TOKEN_IDENT, Value: "foo", Line: 2, Col: 5}
|
|
s := tok.String()
|
|
if !strings.Contains(s, "IDENT") || !strings.Contains(s, "foo") {
|
|
t.Errorf("Token.String() = %q", s)
|
|
}
|
|
if got := TokenType(999).String(); got != "UNKNOWN" {
|
|
t.Errorf("TokenType(999).String() = %q, want UNKNOWN", got)
|
|
}
|
|
for tt, want := range map[TokenType]string{
|
|
TOKEN_STRING: "STRING",
|
|
TOKEN_FLOAT: "FLOAT",
|
|
TOKEN_INT: "INT",
|
|
TOKEN_DURATION: "DURATION",
|
|
TOKEN_SIZE: "SIZE",
|
|
TOKEN_LBRACE: "{",
|
|
TOKEN_RBRACE: "}",
|
|
TOKEN_LPAREN: "(",
|
|
TOKEN_RPAREN: ")",
|
|
TOKEN_ASSIGN: "=",
|
|
TOKEN_TILDE: "~",
|
|
TOKEN_EOF: "EOF",
|
|
} {
|
|
if got := tt.String(); got != want {
|
|
t.Errorf("TokenType(%d) = %q, want %q", tt, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLexerLineComment(t *testing.T) {
|
|
src := `
|
|
// leading comment
|
|
build "make" // trailing
|
|
group("g") { // inside
|
|
weight = 1.0
|
|
test("t") { stdout = "" }
|
|
}
|
|
`
|
|
if _, _, err := Parse(src); err != nil {
|
|
t.Errorf("parse with comments: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLexerUnterminatedString(t *testing.T) {
|
|
_, _, err := Parse(`build "unterminated`)
|
|
if err == nil || !strings.Contains(err.Error(), "unterminated") {
|
|
t.Errorf("want unterminated string error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLexerUnknownEscape(t *testing.T) {
|
|
_, _, err := Parse(`build "bad\zescape"`)
|
|
if err == nil || !strings.Contains(err.Error(), "unknown escape") {
|
|
t.Errorf("want unknown escape error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLexerEscapeSequences(t *testing.T) {
|
|
src := `build "a\nb\tc\\d\"e"`
|
|
f, _, err := Parse(src + "\ngroup(\"g\") { weight = 1.0 test(\"t\") { stdout = \"\" } }")
|
|
if err != nil {
|
|
t.Fatalf("parse: %v", err)
|
|
}
|
|
if f.Build != "a\nb\tc\\d\"e" {
|
|
t.Errorf("escape sequences = %q", f.Build)
|
|
}
|
|
}
|
|
|
|
func TestLexerUnexpectedCharacter(t *testing.T) {
|
|
_, _, err := Parse("build @invalid")
|
|
if err == nil || !strings.Contains(err.Error(), "unexpected character") {
|
|
t.Errorf("want unexpected character error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLexerUnterminatedHeredoc(t *testing.T) {
|
|
src := "build \"x\"\ngroup(\"g\") { weight = 1.0 test(\"t\") { stdin = \"\"\"\nnever closed\n } }"
|
|
_, _, err := Parse(src)
|
|
if err == nil || !strings.Contains(err.Error(), "unterminated heredoc") {
|
|
t.Errorf("want unterminated heredoc, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLexerSizeSuffixes(t *testing.T) {
|
|
cases := map[string]int64{
|
|
"1024": 1024,
|
|
"1B": 1,
|
|
"1K": 1024,
|
|
"1KB": 1024,
|
|
"1KiB": 1024,
|
|
"1M": 1024 * 1024,
|
|
"1MB": 1024 * 1024,
|
|
"1MiB": 1024 * 1024,
|
|
"1G": 1024 * 1024 * 1024,
|
|
"1GB": 1024 * 1024 * 1024,
|
|
"1GiB": 1024 * 1024 * 1024,
|
|
}
|
|
for literal, want := range cases {
|
|
src := "build \"x\"\nmemory_limit = " + literal + "\ngroup(\"g\") { weight = 1.0 test(\"t\") { stdout = \"\" } }"
|
|
f, _, err := Parse(src)
|
|
if err != nil {
|
|
t.Errorf("parse %q: %v", literal, err)
|
|
continue
|
|
}
|
|
if f.MemoryLimit != want {
|
|
t.Errorf("memory_limit %s = %d, want %d", literal, f.MemoryLimit, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLexerDurationSuffixes(t *testing.T) {
|
|
cases := []string{"5ms", "10s", "2m"}
|
|
for _, d := range cases {
|
|
src := "build \"x\"\ntimeout " + d + "\ngroup(\"g\") { weight = 1.0 test(\"t\") { stdout = \"\" } }"
|
|
if _, _, err := Parse(src); err != nil {
|
|
t.Errorf("parse timeout %s: %v", d, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLexerNegativeInt(t *testing.T) {
|
|
src := `
|
|
build "x"
|
|
group("g") {
|
|
weight = 1.0
|
|
test("t") {
|
|
exitCode = -1
|
|
stdout = ""
|
|
}
|
|
}
|
|
`
|
|
f, _, err := Parse(src)
|
|
if err != nil {
|
|
t.Fatalf("parse: %v", err)
|
|
}
|
|
tst := f.Groups[0].Tests[0]
|
|
if tst.ExitCode == nil || *tst.ExitCode != -1 {
|
|
t.Errorf("ExitCode = %v, want -1", tst.ExitCode)
|
|
}
|
|
}
|
|
|
|
func TestLexerFloatNumber(t *testing.T) {
|
|
src := `
|
|
build "x"
|
|
group("g") {
|
|
weight = 0.75
|
|
test("t") { stdout = "" }
|
|
}
|
|
group("g2") {
|
|
weight = 0.25
|
|
test("t") { stdout = "" }
|
|
}
|
|
`
|
|
f, _, err := Parse(src)
|
|
if err != nil {
|
|
t.Fatalf("parse: %v", err)
|
|
}
|
|
if f.Groups[0].Weight != 0.75 {
|
|
t.Errorf("weight = %v", f.Groups[0].Weight)
|
|
}
|
|
}
|
|
|
|
func TestLexerInvalidSizeUnit(t *testing.T) {
|
|
_, _, err := Parse("build \"x\"\nmemory_limit = 10Z\n")
|
|
if err == nil {
|
|
t.Error("expected error for invalid size unit")
|
|
}
|
|
}
|