refactor: modernize stdlib usage and move matchers into dsl
All checks were successful
build-dsl-smoke / Build judge (push) Successful in 16s
build-dsl-smoke / debug / clang / linux (push) Successful in 6s
build-dsl-smoke / debug / gcc / linux (push) Successful in 7s
build-dsl-smoke / release / clang / linux (push) Successful in 8s
build-dsl-smoke / release / gcc / linux (push) Successful in 9s
build-dsl-smoke / sanitized / gcc / linux (push) Successful in 6s
build-dsl-smoke / sanitized / clang / linux (push) Successful in 9s
build-dsl-smoke / debug-valgrind / gcc / linux (push) Successful in 15s
build-dsl-smoke / debug / clang / windows (push) Successful in 15s
build-dsl-smoke / debug / msvc / windows (push) Successful in 19s
build-dsl-smoke / release / clang / windows (push) Successful in 18s
build-dsl-smoke / release / msvc / windows (push) Successful in 18s
build-dsl-smoke / SUMMARY (push) Successful in 4s
All checks were successful
build-dsl-smoke / Build judge (push) Successful in 16s
build-dsl-smoke / debug / clang / linux (push) Successful in 6s
build-dsl-smoke / debug / gcc / linux (push) Successful in 7s
build-dsl-smoke / release / clang / linux (push) Successful in 8s
build-dsl-smoke / release / gcc / linux (push) Successful in 9s
build-dsl-smoke / sanitized / gcc / linux (push) Successful in 6s
build-dsl-smoke / sanitized / clang / linux (push) Successful in 9s
build-dsl-smoke / debug-valgrind / gcc / linux (push) Successful in 15s
build-dsl-smoke / debug / clang / windows (push) Successful in 15s
build-dsl-smoke / debug / msvc / windows (push) Successful in 19s
build-dsl-smoke / release / clang / windows (push) Successful in 18s
build-dsl-smoke / release / msvc / windows (push) Successful in 18s
build-dsl-smoke / SUMMARY (push) Successful in 4s
- Move Matcher types and matching logic from runner/matcher.go into the dsl package as methods on the Matcher types. Runner now calls t.Stdout.Match(label, actual) instead of type-switching via a package-level applyMatcher helper. - Replace custom contains/containsString helpers with slices.Contains in dsl/build.go and runner/compiler.go. - Use maps.Copy instead of manual map copy in BuildConfig.MergeFrom. - Adopt strings.SplitSeq, strings.CutPrefix and the `for range N` loop form in runner/limiter_linux.go. - Ignore example/imdb build artifact.
This commit is contained in:
43
dsl/ast.go
43
dsl/ast.go
@@ -1,6 +1,8 @@
|
||||
package dsl
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
Build string
|
||||
@@ -74,42 +76,3 @@ type Test struct {
|
||||
Stderr Matcher
|
||||
OutFiles map[string]string
|
||||
}
|
||||
|
||||
type Matcher interface {
|
||||
matcherNode()
|
||||
}
|
||||
|
||||
type ExactMatcher struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (ExactMatcher) matcherNode() {}
|
||||
|
||||
type ContainsMatcher struct {
|
||||
Substr string
|
||||
}
|
||||
|
||||
func (ContainsMatcher) matcherNode() {}
|
||||
|
||||
type RegexMatcher struct {
|
||||
Pattern string
|
||||
}
|
||||
|
||||
func (RegexMatcher) matcherNode() {}
|
||||
|
||||
type NumericEpsMatcher struct {
|
||||
Epsilon float64
|
||||
Value string
|
||||
}
|
||||
|
||||
func (NumericEpsMatcher) matcherNode() {}
|
||||
|
||||
type AnyOrderMatcher struct {
|
||||
Lines []string
|
||||
}
|
||||
|
||||
func (AnyOrderMatcher) matcherNode() {}
|
||||
|
||||
type NoMatcher struct{}
|
||||
|
||||
func (NoMatcher) matcherNode() {}
|
||||
|
||||
22
dsl/build.go
22
dsl/build.go
@@ -1,5 +1,10 @@
|
||||
package dsl
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type BuildProfile int
|
||||
|
||||
const (
|
||||
@@ -105,9 +110,7 @@ func (dst *BuildConfig) MergeFrom(src *BuildConfig) {
|
||||
if dst.Defines == nil {
|
||||
dst.Defines = map[string]string{}
|
||||
}
|
||||
for k, v := range src.Defines {
|
||||
dst.Defines[k] = v
|
||||
}
|
||||
maps.Copy(dst.Defines, src.Defines)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,24 +135,15 @@ func (b *BuildConfig) Resolve(defaults *BuildConfig, os string) BuildConfig {
|
||||
}
|
||||
|
||||
func (b *BuildConfig) AppliesTo(os, compiler string) bool {
|
||||
if len(b.Platforms) > 0 && !contains(b.Platforms, os) {
|
||||
if len(b.Platforms) > 0 && !slices.Contains(b.Platforms, os) {
|
||||
return false
|
||||
}
|
||||
if len(b.Compilers) > 0 && !contains(b.Compilers, compiler) {
|
||||
if len(b.Compilers) > 0 && !slices.Contains(b.Compilers, compiler) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func contains(xs []string, x string) bool {
|
||||
for _, v := range xs {
|
||||
if v == x {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ToolchainSpec struct {
|
||||
Name string
|
||||
Platforms []string
|
||||
|
||||
@@ -371,8 +371,6 @@ func (l *Lexer) readNumberOrDuration(line, col int) (Token, error) {
|
||||
return Token{TOKEN_INT, buf.String(), line, col}, nil
|
||||
}
|
||||
|
||||
// tryReadSizeSuffix reads memory size suffixes: B, K, KB, KiB, M, MB, MiB, G, GB, GiB.
|
||||
// Units are case-sensitive uppercase to avoid collision with duration "m" (minutes).
|
||||
func (l *Lexer) tryReadSizeSuffix() string {
|
||||
ch, ok := l.peek()
|
||||
if !ok {
|
||||
|
||||
168
dsl/matcher.go
Normal file
168
dsl/matcher.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package dsl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TODO: maybe move to ast.go
|
||||
type Matcher interface {
|
||||
matcherNode()
|
||||
|
||||
Match(label, actual string) []string
|
||||
}
|
||||
|
||||
type ExactMatcher struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (ExactMatcher) matcherNode() {}
|
||||
|
||||
// TODO: think about pointer receivers
|
||||
func (m ExactMatcher) Match(label, actual string) []string {
|
||||
if actual != m.Value {
|
||||
return []string{fmt.Sprintf(
|
||||
"%s mismatch:\n expected: %q\n actual: %q",
|
||||
label, m.Value, actual,
|
||||
)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ContainsMatcher struct {
|
||||
Substr string
|
||||
}
|
||||
|
||||
func (ContainsMatcher) matcherNode() {}
|
||||
|
||||
func (m ContainsMatcher) Match(label, actual string) []string {
|
||||
if !strings.Contains(actual, m.Substr) {
|
||||
return []string{fmt.Sprintf(
|
||||
"%s: expected to contain %q, got %q",
|
||||
label, m.Substr, actual,
|
||||
)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RegexMatcher struct {
|
||||
Pattern string
|
||||
}
|
||||
|
||||
func (RegexMatcher) matcherNode() {}
|
||||
|
||||
func (m RegexMatcher) Match(label, actual string) []string {
|
||||
re, err := regexp.Compile(m.Pattern)
|
||||
if err != nil {
|
||||
return []string{fmt.Sprintf("%s: invalid regex %q: %v", label, m.Pattern, err)}
|
||||
}
|
||||
|
||||
if !re.MatchString(actual) {
|
||||
return []string{fmt.Sprintf(
|
||||
"%s: %q does not match regex %q",
|
||||
label, actual, m.Pattern,
|
||||
)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NumericEpsMatcher struct {
|
||||
Epsilon float64
|
||||
Value string
|
||||
}
|
||||
|
||||
func (NumericEpsMatcher) matcherNode() {}
|
||||
|
||||
func parseNumbers(s string) ([]float64, error) {
|
||||
fields := strings.Fields(s)
|
||||
nums := make([]float64, 0, len(fields))
|
||||
for _, f := range fields {
|
||||
n, err := strconv.ParseFloat(f, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("not a number: %q", f)
|
||||
}
|
||||
nums = append(nums, n)
|
||||
}
|
||||
return nums, nil
|
||||
}
|
||||
|
||||
func (m NumericEpsMatcher) Match(label, actual string) []string {
|
||||
expectedNums, err := parseNumbers(m.Value)
|
||||
if err != nil {
|
||||
return []string{fmt.Sprintf("%s: cannot parse expected numbers %q: %v", label, m.Value, err)}
|
||||
}
|
||||
actualNums, err := parseNumbers(actual)
|
||||
if err != nil {
|
||||
return []string{fmt.Sprintf("%s: cannot parse actual numbers %q: %v", label, actual, err)}
|
||||
}
|
||||
if len(expectedNums) != len(actualNums) {
|
||||
return []string{fmt.Sprintf(
|
||||
"%s: expected %d numbers, got %d (expected=%q, actual=%q)",
|
||||
label, len(expectedNums), len(actualNums), m.Value, actual,
|
||||
)}
|
||||
}
|
||||
var errs []string
|
||||
for i, exp := range expectedNums {
|
||||
act := actualNums[i]
|
||||
if math.Abs(exp-act) > m.Epsilon {
|
||||
errs = append(errs, fmt.Sprintf(
|
||||
"%s: number[%d] expected %.10g ± %.10g, got %.10g",
|
||||
label, i, exp, m.Epsilon, act,
|
||||
))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
type AnyOrderMatcher struct {
|
||||
Lines []string
|
||||
}
|
||||
|
||||
func (AnyOrderMatcher) matcherNode() {}
|
||||
|
||||
func splitLines(s string) []string {
|
||||
s = strings.TrimRight(s, "\n")
|
||||
if s == "" {
|
||||
return []string{}
|
||||
}
|
||||
return strings.Split(s, "\n")
|
||||
}
|
||||
|
||||
func (m AnyOrderMatcher) Match(label, actual string) []string {
|
||||
actualLines := splitLines(actual)
|
||||
expectedLines := make([]string, len(m.Lines))
|
||||
copy(expectedLines, m.Lines)
|
||||
|
||||
sort.Strings(actualLines)
|
||||
sort.Strings(expectedLines)
|
||||
|
||||
if len(actualLines) != len(expectedLines) {
|
||||
return []string{fmt.Sprintf(
|
||||
"%s anyOrder: expected %d lines, got %d",
|
||||
label, len(expectedLines), len(actualLines),
|
||||
)}
|
||||
}
|
||||
|
||||
var errs []string
|
||||
for i := range expectedLines {
|
||||
if actualLines[i] != expectedLines[i] {
|
||||
errs = append(errs, fmt.Sprintf(
|
||||
"%s anyOrder: line mismatch: expected %q, got %q",
|
||||
label, expectedLines[i], actualLines[i],
|
||||
))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
type NoMatcher struct{}
|
||||
|
||||
func (NoMatcher) matcherNode() {}
|
||||
|
||||
func (NoMatcher) Match(label, actual string) []string {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user