summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--adapters/gtest/adapter.go107
-rw-r--r--adapters/gtest/config.go50
-rw-r--r--adapters/gtest/results.go42
-rw-r--r--cmd/planr/main.go13
-rw-r--r--cmd/planr/sub/cli.go122
-rw-r--r--cmd/planr/sub/evaluate.go40
-rw-r--r--config.go42
-rw-r--r--fs.go15
-rw-r--r--go.mod1
-rw-r--r--go.sum9
-rw-r--r--runner.go20
-rw-r--r--testcase.go15
12 files changed, 354 insertions, 122 deletions
diff --git a/adapters/gtest/adapter.go b/adapters/gtest/adapter.go
index 600c956..f4fde27 100644
--- a/adapters/gtest/adapter.go
+++ b/adapters/gtest/adapter.go
@@ -2,14 +2,16 @@ package gtest
import (
"context"
+ "errors"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
- "time"
"path"
- "errors"
+ "sync"
+ "time"
+
"golang.flu0r1ne.net/planr"
)
@@ -25,11 +27,6 @@ func mkUnit(tc *planr.TestCase) cmakeUnit {
};
}
-func chdir(dir string) {
- if err := os.Chdir(dir); err != nil {
- log.Fatal(err)
- }
-}
type GtestAdapter struct {}
@@ -48,7 +45,6 @@ func (adapter *GtestAdapter) Build(tcs []*planr.TestCase) {
units := make([]cmakeUnit, 0)
for _, tc := range tcs {
- fmt.Printf("[R] Building %s (%s)\n", tc.Cname, tc.Path)
cfg := tc.AdapterConfig().(*GtestConfig)
cfg.ensureSatisfied(tc.Path)
@@ -56,19 +52,17 @@ func (adapter *GtestAdapter) Build(tcs []*planr.TestCase) {
}
genCmake(cmakeFile, units)
-
- chdir(buildDir)
+
planr.RunCmd("cmake", "-S", ".", "-B", ".")
}
-type ResultFromId map[string] planr.TestResult
+type ResultFromId map[string] Result
func (adapter *GtestAdapter) execTests(cnames []string) ResultFromId {
buildDir := adapter.Config().Dir()
lut := make(ResultFromId, 0)
for _, exe := range cnames {
- fmt.Printf("[R] Evaluating %s\n", exe)
exePath := path.Join(buildDir, exe)
@@ -84,34 +78,44 @@ func (adapter *GtestAdapter) execTests(cnames []string) ResultFromId {
defer cancel()
defer os.Remove(f.Name())
- exitFail := false
- if err := cmd.Run(); err != nil {
+ out, err := cmd.CombinedOutput()
+ if err != nil {
var exiterr *exec.ExitError
- if errors.As(err, &exiterr) && exiterr.ExitCode() == 1{
- exitFail = true
- } else {
+ if !errors.As(err, &exiterr) {
log.Printf("%v\n", err)
os.Exit(exiterr.ExitCode())
}
}
- if exitFail {
- fmt.Printf("")
+ results, err := decodeResults(f)
+
+ if err != nil {
+ log.Printf("Could not collect results from %s: %v", exe, err)
+ continue
}
- for _, r := range decodeResults(f) {
- lut[exe + "." + r.id] = r.result
+ for _, r := range results {
+ r.testOutput = string(out)
+ lut[exe + "." + r.id] = r
}
}
return lut
}
+// An executable may contain more than one test
+// Gather all executables and deduplicate them
func exes(tcs []*planr.TestCase) []string {
set := make(map[string] bool, 0)
for _, tc := range tcs {
+ // Tests which have encountered a failure
+ // may not have an executable
+ if tc.Result.Status != planr.PASSING {
+ continue
+ }
+
if(!set[tc.Cname]) {
set[tc.Cname] = true
}
@@ -130,17 +134,66 @@ func id(tc *planr.TestCase) string {
return tc.Cname + "." + *cfg.Suite + "." + *cfg.Name
}
-func (adapter *GtestAdapter) Evaluate(tcs []*planr.TestCase) {
- buildDir := adapter.Config().Dir()
- chdir(buildDir)
+func compile(wg * sync.WaitGroup, tc *planr.TestCase) {
+ defer wg.Done()
+
+ cmd := exec.Command("make", tc.Cname)
+ out, err := cmd.CombinedOutput()
+ tc.Result = new(planr.TestResult)
+
+ // Don't treat command failure as anything but a build failure
+ if err != nil{
+ var exiterr *exec.ExitError
+ if errors.As(err, &exiterr) && exiterr.ExitCode() == 0 {
+ log.Fatal(err)
+ }
+
+ tc.Result.Status = planr.COMPILATION_FAILURE
+ }
- planr.RunCmd("make", "-k")
+ tc.Result.DebugOutput = string(out)
+}
+
+// ./planr eval 0.93s user 0.16s system 100% cpu 1.089 total
+func (adapter *GtestAdapter) Evaluate(tcs []*planr.TestCase) {
+ var wg sync.WaitGroup
+ for _, tc := range tcs {
+ wg.Add(1)
+ go compile(&wg, tc)
+ }
+ wg.Wait()
files := exes(tcs)
resultById := adapter.execTests(files)
for _, tc := range tcs {
- result := resultById[id(tc)]
- tc.Result = &result
+ result, ok := resultById[id(tc)]
+
+ // compilation failure
+ if !ok {
+ fmt.Printf("CAN'T FIND %s: status %d\n", tc.Cname, tc.Result.Status)
+
+ if tc.Result.Status == planr.PASSING {
+ cfg := tc.AdapterConfig().(*GtestConfig)
+
+ log.Printf(
+ "Could not find testcase %s with name=\"%s\" and suite=\"%s\". Does such a test exist in the test source?",
+ tc.Cname,
+ *cfg.Name,
+ *cfg.Suite,
+ )
+
+ tc.Result.Status = planr.COMPILATION_FAILURE
+ tc.Result.DebugOutput += fmt.Sprintf("planr: Did not find testcase %s in any test executable\n", id(tc))
+ }
+
+ continue
+ }
+
+ if !result.pass {
+ tc.Result.Status = planr.RUNTIME_FAILURE
+ }
+
+ tc.Result.TestOutput = result.testOutput
}
}
diff --git a/adapters/gtest/config.go b/adapters/gtest/config.go
index 6a6c8bf..cb5ba75 100644
--- a/adapters/gtest/config.go
+++ b/adapters/gtest/config.go
@@ -8,23 +8,23 @@ import (
)
type GtestDefaults struct {
- Name *string
- Suite *string
- Testfile *string
- Test_root *string
- Srcs *[]string
- Srcs_root *string
+ Name *string
+ Suite *string
+ Testfile *string
+ Test_root *string
+ Srcs *[]string
+ Srcs_root *string
}
func (child *GtestDefaults) Inherit(p interface{}) {
parent := p.(*GtestDefaults)
- if(child.Name == nil) { child.Name = parent.Name }
- if(child.Suite == nil) { child.Suite = parent.Suite }
- if(child.Testfile == nil) { child.Testfile = parent.Testfile }
- if(child.Test_root == nil) { child.Test_root = parent.Test_root }
- if(child.Srcs == nil) { child.Srcs = parent.Srcs }
- if(child.Srcs_root == nil) { child.Srcs_root = parent.Srcs_root }
+ if(child.Name == nil) { child.Name = parent.Name }
+ if(child.Suite == nil) { child.Suite = parent.Suite }
+ if(child.Testfile == nil) { child.Testfile = parent.Testfile }
+ if(child.Test_root == nil) { child.Test_root = parent.Test_root }
+ if(child.Srcs == nil) { child.Srcs = parent.Srcs }
+ if(child.Srcs_root == nil) { child.Srcs_root = parent.Srcs_root }
}
@@ -73,24 +73,22 @@ func (cfg GtestConfig) srcList() string {
return srcList
}
-func primitiveDecode(primitive toml.Primitive, config interface{}) {
- if err := toml.PrimitiveDecode(primitive, config); err != nil {
- log.Fatal(err)
- }
-}
-
-func ParseConfig(prim toml.Primitive) planr.InheritableConfig {
+func ParseConfig(prim toml.Primitive) (planr.InheritableConfig, error) {
config := GtestConfig{}
-
- primitiveDecode(prim, &config)
-
- return &config
+
+ if err := toml.PrimitiveDecode(prim, &config); err != nil {
+ return nil, err
+ }
+
+ return &config, nil
}
-func ParseDefaultConfig(prim toml.Primitive) planr.InheritableConfig {
+func ParseDefaultConfig(prim toml.Primitive) (planr.InheritableConfig, error) {
config := GtestDefaults{}
- primitiveDecode(prim, &config)
+ if err := toml.PrimitiveDecode(prim, &config); err != nil {
+ return nil, err
+ }
- return &config
+ return &config, nil
}
diff --git a/adapters/gtest/results.go b/adapters/gtest/results.go
index 88e4069..14f5d1d 100644
--- a/adapters/gtest/results.go
+++ b/adapters/gtest/results.go
@@ -4,10 +4,7 @@ import (
"bytes"
"encoding/json"
"io"
- "log"
"time"
-
- "golang.flu0r1ne.net/planr"
)
type gFailure struct {
@@ -48,36 +45,51 @@ type gResults struct {
}
type Result struct {
- id string
- result planr.TestResult
+ id string
+ pass bool
+ failureMsg string
+ testOutput string
+}
+
+func failureMsg(failures []gFailure) string {
+ failure_msg := ""
+
+ for _, failure := range failures {
+ failure_msg += failure.Failure + "\n"
+ }
+
+ return failure_msg
}
-func decodeResults(r io.Reader) []Result {
+func decodeResults(r io.Reader) ([]Result, error) {
+ decoded := make([]Result, 0)
+
var results gResults
buf := bytes.Buffer{}
if _, err := buf.ReadFrom(r); err != nil {
- log.Fatal(err)
+ return decoded, err
}
if err := json.Unmarshal(buf.Bytes(), &results); err != nil {
- log.Fatal(err)
+ return decoded, err
}
- decoded := make([]Result, 0)
for _, suite := range results.Testsuites {
for _, test := range suite.Testsuite {
n := len(test.Failures)
- decoded = append(decoded, Result{
+
+ res := Result {
id: suite.Name + "." + test.Name,
- result: planr.TestResult {
- Pass: n == 0,
- },
- })
+ pass: n == 0,
+ failureMsg: failureMsg(test.Failures),
+ }
+
+ decoded = append(decoded, res)
}
}
- return decoded
+ return decoded, nil
}
diff --git a/cmd/planr/main.go b/cmd/planr/main.go
index c65edb1..54c3d60 100644
--- a/cmd/planr/main.go
+++ b/cmd/planr/main.go
@@ -1,14 +1,16 @@
package main
import (
- "os"
- "io"
"fmt"
+ "io"
+ "log"
+ "os"
+
"golang.flu0r1ne.net/planr/cmd/planr/sub"
)
const (
- VERSION = "0.0.1"
+ VERSION = "0.0.2"
)
func printUsage(w io.Writer) {
@@ -26,6 +28,9 @@ func dieUsage() {
func main() {
+ log.SetFlags(log.Llongfile | log.Lmsgprefix)
+ log.SetPrefix("planr: ")
+
if len(os.Args) < 2 {
dieUsage()
}
@@ -38,7 +43,7 @@ func main() {
fmt.Printf("%s\n", VERSION)
case "build":
sub.Build(subargs)
- case "evaluate":
+ case "evaluate","eval":
sub.Evaluate(subargs)
case "help", "-h", "-help", "--help":
printUsage(os.Stdout)
diff --git a/cmd/planr/sub/cli.go b/cmd/planr/sub/cli.go
new file mode 100644
index 0000000..0e6a942
--- /dev/null
+++ b/cmd/planr/sub/cli.go
@@ -0,0 +1,122 @@
+package sub
+
+import (
+ "github.com/fatih/color"
+ "golang.flu0r1ne.net/planr"
+ "fmt"
+ "strings"
+)
+
+var (
+ col_pass = color.New(color.FgGreen)
+ col_fail = color.New(color.FgRed)
+ col_title = color.New(color.FgHiWhite)
+ col_label = color.New(color.FgCyan)
+);
+
+func tcTitle(tc planr.TestCase) string {
+ title := tc.Cname
+
+ if tc.Config.Title != nil {
+ title = *tc.Config.Title
+ }
+
+ return title
+}
+
+func tcStatus(tc planr.TestCase) string {
+ status := "SILENT"
+
+ if tc.Result != nil {
+ if tc.Result.Status == planr.PASSING {
+ status = "PASS"
+ } else {
+ status = "FAIL"
+ }
+ }
+
+ return status
+}
+
+func pprintLabeled(label, value string) {
+ col_label.Printf(" %s: ", label)
+ fmt.Println(value)
+}
+
+const (
+ FENCE_WIDTH = 78
+)
+
+func pprintFenced(title, value string) {
+ wingWidth := FENCE_WIDTH - len(title) - 2
+ wing := strings.Repeat("-", wingWidth / 2)
+ fence := strings.Repeat("-", FENCE_WIDTH)
+
+ fmt.Printf(" %s %s %s\n", wing, title, wing)
+
+ fmt.Print(" " + strings.ReplaceAll(value, "\n", "\n "))
+
+ fmt.Println(fence)
+}
+
+func tcStatusLine(tc planr.TestCase) {
+ title := tcTitle(tc)
+ status := tcStatus(tc)
+
+ if status == "PASS" {
+ col_pass.Printf("[%s] ", status);
+ } else {
+ col_fail.Printf("[%s] ", status);
+ }
+
+ col_title.Println(title);
+}
+
+func tcPprint(tc planr.TestCase) {
+ tcStatusLine(tc)
+
+ pprintLabeled("id", tc.Cname)
+
+ if tc.Config.Points != nil {
+ points := fmt.Sprintf("%.1f", *tc.Config.Points)
+ pprintLabeled("points", points)
+ }
+
+ if tc.Config.Description != nil {
+ pprintLabeled("description", *tc.Config.Description)
+ }
+
+ res := tc.Result
+
+ if res.Status == planr.COMPILATION_FAILURE {
+
+ if res.DebugOutput != "" {
+ fmt.Println()
+ pprintFenced("compilation output", tc.Result.DebugOutput);
+ } else {
+ fmt.Println("WARN: No debug output provided")
+ }
+
+ } else if res.Status == planr.RUNTIME_FAILURE {
+
+ if tc.Result.TestOutput != "" {
+ fmt.Println()
+ pprintFenced("test output", tc.Result.TestOutput);
+ }
+
+ }
+
+ fmt.Println()
+}
+
+func printResults(passed, tc_total int, earned, points_total float64) {
+ col_title.Println("Final Results:")
+
+ pprintLabeled("passed", fmt.Sprintf("%d/%d", passed, tc_total));
+
+ percent := earned / points_total * 100
+
+ pprintLabeled("score", fmt.Sprintf(
+ "%.2f/%.2f ~= %.1f%%", earned, points_total, percent,
+ ));
+}
diff --git a/cmd/planr/sub/evaluate.go b/cmd/planr/sub/evaluate.go
index 1174b3f..8ce4d81 100644
--- a/cmd/planr/sub/evaluate.go
+++ b/cmd/planr/sub/evaluate.go
@@ -1,7 +1,6 @@
package sub
import (
- "fmt"
"golang.flu0r1ne.net/planr"
)
@@ -10,43 +9,30 @@ func Evaluate(params []string) {
tcs := Runner().Evaluate(rd)
- fmt.Printf("\n\nREPORT:\n=======\n\n")
-
earned := 0.0
total := 0.0
+ passed := 0
for _, tc := range tcs {
cfg := tc.Config
-
- name := tc.Cname
- if cfg.Title != nil {
- name = *cfg.Title
- }
- var points float64 = 0.0
if cfg.Points != nil {
- points = float64(*cfg.Points)
- }
+ points := float64(*cfg.Points)
+
+ total += points
- status := "SILENT"
- if tc.Result != nil {
- if tc.Result.Pass {
- status = "PASS"
+ if tc.Result.Status == planr.PASSING {
earned += points
- } else {
- status = "FAIL"
+ passed++
}
}
- total += points
-
- fmt.Printf("[%s] %s (%f)\n", status, name, points)
-
- if cfg.Description != nil {
- fmt.Printf("> %s\n", *cfg.Description)
- }
-
- fmt.Println()
+ tcPprint(tc)
}
- fmt.Printf("Score: %f (%f%%)\n", earned, (earned / total) * 100)
+ printResults(
+ passed,
+ len(tcs),
+ earned,
+ total,
+ );
}
diff --git a/config.go b/config.go
index 6efa90d..bc0fa6a 100644
--- a/config.go
+++ b/config.go
@@ -1,7 +1,6 @@
package planr
import (
- // "fmt"
"log"
"github.com/BurntSushi/toml"
)
@@ -41,7 +40,7 @@ type InheritableConfig interface {
// A parser function takes a blob of TOML and decodes it into
// configuration relevant to an adapter
-type TomlParser func (toml.Primitive) InheritableConfig
+type TomlParser func (toml.Primitive) (InheritableConfig, error)
// The name under which an adapter registers corresponds
// to a table under the super-table adapters. All corresponding
@@ -134,7 +133,10 @@ func (child *Defaults) Inherit(p interface{}) {
// according to methods registered with the runner
// Once parsed, they are stored alongside the registered name to determine
// which adapter will receive the configuration
-func (defaults *Defaults) decodeAdapters(adapters []AdapterConfig, asDefault bool) {
+func (defaults *Defaults) decodeAdapters(
+ adapters []AdapterConfig,
+ asDefault bool,
+) error {
defaults.configs_ = &adapters
defaults.adapters_ = make(map[string]InheritableConfig)
@@ -144,40 +146,54 @@ func (defaults *Defaults) decodeAdapters(adapters []AdapterConfig, asDefault boo
if exists {
var parsed InheritableConfig
+ var err error
if asDefault {
- parsed = config.ParseDefaultConfig(primitive)
+ parsed, err = config.ParseDefaultConfig(primitive)
} else {
- parsed = config.ParseConfig(primitive)
+ parsed, err = config.ParseConfig(primitive)
+ }
+
+ if err != nil {
+ return err
}
defaults.adapters_[config.Name] = parsed
}
}
}
+
+ return nil
}
// Decode defaults.toml
-func DecodeDefaults(path string, adapterCfg []AdapterConfig) Defaults {
+func DecodeDefaults(path string, adapterCfg []AdapterConfig) (Defaults, error) {
defaults := Defaults { }
+
+
if _, err := toml.DecodeFile(path, &defaults); err != nil {
- log.Fatal(err)
+ return defaults, err
+ }
+
+ if err := defaults.decodeAdapters(adapterCfg, true); err != nil {
+ return defaults, err
}
- defaults.decodeAdapters(adapterCfg, true)
- return defaults
+ return defaults, nil
}
// Decode an individual unit
-func DecodeConfig(path string, adapterCfg []AdapterConfig) TestCaseConfig {
+func DecodeConfig(path string, adapterCfg []AdapterConfig) (TestCaseConfig, error) {
config := TestCaseConfig { }
if _, err := toml.DecodeFile(path, &config); err != nil {
- log.Fatal(err)
+ return config, nil
}
- config.decodeAdapters(adapterCfg, false)
+ if err := config.decodeAdapters(adapterCfg, false); err != nil {
+ return config, err
+ }
- return config
+ return config, nil
}
diff --git a/fs.go b/fs.go
index bd27cf8..86de16b 100644
--- a/fs.go
+++ b/fs.go
@@ -208,11 +208,15 @@ func collectFromDir(
// Process defaults for this directory if a defaults.toml is found
defaultsPath := path.Join(dir, DEFAULTS)
if info, err := os.Stat(defaultsPath); err == nil && !info.IsDir() {
- d := DecodeDefaults(defaultsPath, cfgs)
+ d, err := DecodeDefaults(defaultsPath, cfgs)
+
+ if err != nil {
+ log.Fatalf("Error encounter in %s: %v\n", defaultsPath, err);
+ }
// inherit the properties not defined in this defaults
if defaults != nil {
- d.Inherit(defaults)
+ d.Inherit(*defaults)
}
defaults = &d
@@ -240,7 +244,12 @@ func collectFromDir(
}
// Decode a unit
- config := DecodeConfig(child, cfgs)
+ config, err := DecodeConfig(child, cfgs)
+
+ if err != nil {
+ log.Fatalf("Error encountered in %s: %v", child, config)
+ }
+
config.Inherit(*defaults)
tc := TestCase {
diff --git a/go.mod b/go.mod
index 5de0411..4f1d784 100644
--- a/go.mod
+++ b/go.mod
@@ -4,4 +4,5 @@ go 1.16
require (
github.com/BurntSushi/toml v0.3.1
+ github.com/fatih/color v1.12.0 // indirect
)
diff --git a/go.sum b/go.sum
index fca8c3e..5516695 100644
--- a/go.sum
+++ b/go.sum
@@ -1,4 +1,13 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
+github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w=
github.com/jinzhu/copier v0.3.2/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
+github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/runner.go b/runner.go
index 96bcd19..3bee17a 100644
--- a/runner.go
+++ b/runner.go
@@ -1,6 +1,9 @@
package planr
-import "fmt"
+import (
+ "log"
+ "os"
+)
type Runner struct {
adapters []Adapter
@@ -40,6 +43,14 @@ func (r Runner) checkConfig(tcs []TestCase) {
}
}
+func cdBuild(adapter Adapter) {
+ dir := adapter.Config().Dir()
+
+ if err := os.Chdir(dir); err != nil {
+ log.Fatal(err)
+ }
+}
+
func (r Runner) build(tcs []TestCase) {
r.checkConfig(tcs)
@@ -47,8 +58,8 @@ func (r Runner) build(tcs []TestCase) {
for _, adapter := range r.adapters {
nm := adapter.Config().Name
-
- fmt.Printf("[R] Building adapter \"%s\"\n", nm)
+ cdBuild(adapter)
+
adapter.Build(tcTab[nm])
}
}
@@ -67,11 +78,10 @@ func (r Runner) evaluate(tcs []TestCase) {
for _, adapter := range r.adapters {
nm := adapter.Config().Name
+ cdBuild(adapter)
- fmt.Printf("[R] Evaluating adapter \"%s\"\n", nm)
adapter.Evaluate(tcTab[nm])
}
-
}
func (r Runner) Evaluate(root string) []TestCase {
diff --git a/testcase.go b/testcase.go
index 989838c..8506b84 100644
--- a/testcase.go
+++ b/testcase.go
@@ -1,8 +1,18 @@
package planr
+type TestStatus uint
+
+const (
+ PASSING TestStatus = iota
+ COMPILATION_FAILURE
+ RUNTIME_FAILURE
+)
+
type TestResult struct {
- Id string
- Pass bool
+ Id string
+ Status TestStatus
+ DebugOutput string
+ TestOutput string
}
type TestCase struct {
@@ -18,6 +28,7 @@ type TestCase struct {
Config TestCaseConfig
Result *TestResult
+
}
func (tc TestCase) AdapterConfig() InheritableConfig {