diff options
| author | Flu0r1ne <flur01ne@flu0r1ne.net> | 2021-08-05 15:56:10 -0500 | 
|---|---|---|
| committer | Flu0r1ne <flur01ne@flu0r1ne.net> | 2021-08-05 15:56:10 -0500 | 
| commit | 72a70b127636ae8a83e2a2bd53b69143e3c5ded0 (patch) | |
| tree | fdddf5cccdb487d63909f97074d111e67c79ded7 /adapters/gtest | |
| parent | f90a14d5d723c5d2b87f2eaa19f441dec33bb9b2 (diff) | |
| download | planr-72a70b127636ae8a83e2a2bd53b69143e3c5ded0.tar.xz planr-72a70b127636ae8a83e2a2bd53b69143e3c5ded0.zip  | |
Runtime & reorganziation
Diffstat (limited to 'adapters/gtest')
| -rw-r--r-- | adapters/gtest/adapter.go | 106 | ||||
| -rw-r--r-- | adapters/gtest/config.go | 96 | ||||
| -rw-r--r-- | adapters/gtest/results.go | 75 | ||||
| -rw-r--r-- | adapters/gtest/templating.go | 84 | 
4 files changed, 361 insertions, 0 deletions
diff --git a/adapters/gtest/adapter.go b/adapters/gtest/adapter.go new file mode 100644 index 0000000..09e6ac1 --- /dev/null +++ b/adapters/gtest/adapter.go @@ -0,0 +1,106 @@ +package gtest + +import ( +	"context" +	"fmt" +	"io/ioutil" +	"log" +	"os" +	"os/exec" +        "time" +	"path" +        "errors" +	"golang.flu0r1ne.net/planr" +) + +const GTEST_CMAKE = "CMakeLists.txt" + +func mkUnit(tc *planr.TestCase) cmakeUnit { +  cfg := tc.AdapterConfig("gtest").(*GtestConfig) + +  return cmakeUnit { +    tc.Cname, +    cfg.joinTests(*cfg.Testfile), +    cfg.srcList(), +  }; +} + +func chdir(dir string) { +  if err := os.Chdir(dir); err != nil { +    log.Fatal(err) +  } +} + +type GtestAdapter struct {} + +func (a *GtestAdapter) Config() planr.AdapterConfig { +  return planr.AdapterConfig { +    Name: "gtest", +    ParseConfig: ParseConfig, +    ParseDefaultConfig: ParseDefaultConfig, + } +} + +func (adapter *GtestAdapter) Build(tcs []*planr.TestCase) { +  buildDir :=  adapter.Config().Dir() +  cmakeFile := path.Join(buildDir, GTEST_CMAKE) + +  units := make([]cmakeUnit, 0) +  for _, tc := range tcs { +     +    fmt.Printf("[R] Building %s (%s)\n", tc.Cname, tc.Path) +    cfg := tc.AdapterConfig("gtest").(*GtestConfig) +    cfg.ensureSatisfied(tc.Path) + +    units = append(units, mkUnit(tc)) +  } + +  genCmake(cmakeFile, units) +   +  chdir(buildDir) +  planr.RunCmd("cmake", "-S", ".", "-B", ".") +} + +func (adapter *GtestAdapter) Evaluate(tcs []*planr.TestCase) { +  planr.RunCmd("make", "-k") +  buildDir := adapter.Config().Dir() + +  results := make([]planr.TestResult, 0) +  for _, tc := range tcs { +      fmt.Printf("[R] Evaluating %s (%s)\n", tc.Cname, tc.Path) + +      exe := path.Join(buildDir, tc.Cname) + +      f, err := ioutil.TempFile(buildDir, "gtest_adapter_*.json") + +      if err != nil { +        log.Fatal(err) +      } + +      ctx, cancel := context.WithTimeout(context.Background(), 9999*time.Millisecond) +      cmd := exec.CommandContext(ctx, exe, "--gtest_output=json:" + f.Name()) + +      defer cancel() +      defer os.Remove(f.Name()) + +      exitFail := false +      if err := cmd.Run(); err != nil { +        var exiterr *exec.ExitError + +        if errors.As(err, &exiterr) && exiterr.ExitCode() == 1{ +          exitFail = true               +        } else { +          log.Printf("%v\n", err) +          os.Exit(exiterr.ExitCode()) +        } +      } + +      if exitFail { +        fmt.Printf("Failure detected") +      } + +      results = append(results, decodeResults(f)...) +  } + +  fmt.Println(results) +} diff --git a/adapters/gtest/config.go b/adapters/gtest/config.go new file mode 100644 index 0000000..6a6c8bf --- /dev/null +++ b/adapters/gtest/config.go @@ -0,0 +1,96 @@ +package gtest + +import ( +  "log" +  "golang.flu0r1ne.net/planr" +  "strings" +  "github.com/BurntSushi/toml" +) + +type GtestDefaults struct { +  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 } +} + + +type GtestConfig struct { +  GtestDefaults +} + +func (g GtestConfig) ensureSatisfied(path string) { +  if g.Name == nil { +    log.Fatalf("\"name\" is not defined for unit: %s\n", path) +  } else if g.Suite == nil { +    log.Fatalf("\"suite\" is not defined for unit: %s\n", path) +  } else if g.Testfile == nil { +    log.Fatalf("\"testfile\" is not defined for unit: %s\n", path) +  } +} + +func (cfg GtestConfig) joinTests(path_ string) string { +  if cfg.Test_root == nil { +    return planr.JoinConfigDir("tests", path_) +  } +    +  return planr.JoinConfigDir(*cfg.Test_root, path_) +} + +func (cfg GtestConfig) joinSrcs(path_ string) string { +  if cfg.Srcs_root == nil { +    return planr.JoinConfigDir("../src", path_) +  } + +  return planr.JoinConfigDir(*cfg.Srcs_root, path_) +} + +func (cfg GtestConfig) srcList() string { +  var srcList string + +  if cfg.Srcs != nil { +    srcs := make([]string, len(*cfg.Srcs)) +    for i, src := range *cfg.Srcs { +      srcs[i] = cfg.joinSrcs(src) +    } +     +    srcList = strings.Join(srcs, "\n  ") +  } + +  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 { +    config := GtestConfig{} + +    primitiveDecode(prim, &config) + +    return &config +} + +func ParseDefaultConfig(prim toml.Primitive) planr.InheritableConfig { +    config := GtestDefaults{} + +    primitiveDecode(prim, &config) + +    return &config +} diff --git a/adapters/gtest/results.go b/adapters/gtest/results.go new file mode 100644 index 0000000..f8c8a23 --- /dev/null +++ b/adapters/gtest/results.go @@ -0,0 +1,75 @@ +package gtest + +import ( +	"bytes" +	"encoding/json" +	"io" +	"log" +	"time" + +	"golang.flu0r1ne.net/planr" +) + +type gFailure struct { +  Failure string `json:"failure"` +  Type    string `json:"type"` +} + +type gTestsuite struct { +  Name      string     `json:"name"` +  Status    string     `json:"status"` +  Result    string     `json:"result"` +  Timestamp time.Time  `json:"timestamp"` +  Time      string     `json:"time"` +  Classname string     `json:"classname"` +  Failures  []gFailure `json:"failures"` +} + +type gTestsuites struct { +  Name      string       `json:"name"` +  Tests     int          `json:"tests"` +  Failures  int          `json:"failures"` +  Disabled  int          `json:"disabled"` +  Errors    int          `json:"errors"` +  Timestamp time.Time    `json:"timestamp"` +  Time      string       `json:"time"` +  Testsuite []gTestsuite `json:"testsuite"` +} + +type gResults struct { +  Tests      int           `json:"tests"` +  Failures   int           `json:"failures"` +  Disabled   int           `json:"disabled"` +  Errors     int           `json:"errors"` +  Timestamp  time.Time     `json:"timestamp"` +  Time       string        `json:"time"` +  Name       string        `json:"name"` +  Testsuites []gTestsuites `json:"testsuites"` +} + +func decodeResults(r io.Reader) []planr.TestResult { +  var results gResults +  buf := bytes.Buffer{} + +  if _, err := buf.ReadFrom(r); err != nil { +    log.Fatal(err)  +  } + +  if err := json.Unmarshal(buf.Bytes(), &results); err != nil { +    log.Fatal(err) +  } + +  decoded := make([]planr.TestResult, 0) +  for _, suite := range results.Testsuites { +    for _, test := range suite.Testsuite { +      n := len(test.Failures) + +      decoded = append(decoded, planr.TestResult { +        Id: suite.Name + "_" + test.Name, +        Pass: n == 0, +      }) +    } +  } + +  return decoded +} diff --git a/adapters/gtest/templating.go b/adapters/gtest/templating.go new file mode 100644 index 0000000..a78eaf8 --- /dev/null +++ b/adapters/gtest/templating.go @@ -0,0 +1,84 @@ +package gtest + +import ( +	"io" +	"log" +	"text/template" +        "os" +) + +type cmakeUnit struct { +  Cname string +  File  string +  Srcs  string +}; + +func genCmake(out string, units []cmakeUnit) { +  file, err := os.OpenFile(out, os.O_RDWR | os.O_CREATE, 0644) +  defer func () { +    err := file.Close() + +    if err != nil { +      log.Fatal(err) +    } +  }() + +  if err != nil { +    log.Fatalf("Could not open CMakeFile (%s)\n%v", out, err) +  } + +  writeBoiler(file) +   +  tmpl := unitTemplate() + +  for _, unit := range units { +    if err := tmpl.Execute(file, unit); err != nil { +      log.Fatalf("Failed to generate unit %s: %v", unit.Cname, err); +    } +  } +} + + +func unitTemplate() *template.Template { +  tmpl, err := template.New("gtest_unit").Parse(` +add_executable( +  {{.Cname}} +  {{.File}} +  {{.Srcs}} +) + +target_link_libraries( +  {{.Cname}} +  gtest_main +) + +gtest_discover_tests( +  {{.Cname}} +) +`) + +  if err != nil { +    log.Fatalf("Cannot load Gtest Unit Template %v", err) +  } + +  return tmpl +} + +func writeBoiler(w io.Writer) { +  w.Write([]byte(` +cmake_minimum_required (VERSION 3.1.0) + +project(PlanRGtestAdapter) + +include(FetchContent) +FetchContent_Declare( +  googletest +  URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip +) + +include(GoogleTest) +FetchContent_MakeAvailable(googletest) +`)) +} + +  | 
