diff options
| author | Flu0r1ne <flur01ne@flu0r1ne.net> | 2021-09-02 03:14:47 -0500 | 
|---|---|---|
| committer | Flu0r1ne <flur01ne@flu0r1ne.net> | 2021-09-02 03:14:47 -0500 | 
| commit | d078f6dc10eb265a5d88cd96adf86173d6d3ba2e (patch) | |
| tree | ed8bc2405b60b2ae31405c3d8e27b24fda3ac003 | |
| parent | 96701f87a114557f1a013229e889b4b726aa7dc1 (diff) | |
| download | deb-planr-d078f6dc10eb265a5d88cd96adf86173d6d3ba2e.tar.xz deb-planr-d078f6dc10eb265a5d88cd96adf86173d6d3ba2e.zip | |
Make adapters and internals complient with new directory structure
| -rw-r--r-- | adapters.go | 24 | ||||
| -rw-r--r-- | adapters/gtest/adapter.go | 77 | ||||
| -rw-r--r-- | adapters/gtest/config.go | 21 | ||||
| -rw-r--r-- | adapters/gtest/templating.go | 2 | ||||
| -rw-r--r-- | cmd/planr/sub/build.go | 12 | ||||
| -rw-r--r-- | cmd/planr/sub/evaluate.go | 4 | ||||
| -rw-r--r-- | config.go | 33 | ||||
| -rw-r--r-- | fs.go | 115 | ||||
| -rw-r--r-- | runner.go | 48 | ||||
| -rw-r--r-- | stddirs.go | 53 | ||||
| -rw-r--r-- | testcase.go | 19 | 
11 files changed, 170 insertions, 238 deletions
| diff --git a/adapters.go b/adapters.go index 8419c8b..f4e53ce 100644 --- a/adapters.go +++ b/adapters.go @@ -1,16 +1,38 @@  package planr +import ( +  "github.com/BurntSushi/toml" +) +  // Test adapters must implement all life cycle hooks  // This allows common config, code generation, etc  // Test cases matching adapter configurations will be  // fed into the adapter interface  type Adapter interface { -  //      Config() AdapterConfig +  Init(dirs DirConfig) +    // Called once to preform expensive code generation    Build(testCase []*TestCase)    // Called every time source changes    Evaluate(testCase []*TestCase)  } + +// A parser function takes a blob of TOML and decodes it into +// configuration relevant to an adapter +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 +// TOML will be passed to the ParseConfig method or ParseDefaultConfig +// for parsing. The ParseConfig file parses options in test case files. +// The ParseDefaultConfig is parsed by `defaults.toml` files and can +// be used to establish default configuration that will be inherited +// by all units in a common directory (collection) +type AdapterConfig struct { +   Name                string +   ParseConfig         TomlParser +   ParseDefaultConfig  TomlParser +} diff --git a/adapters/gtest/adapter.go b/adapters/gtest/adapter.go index f4fde27..9331cf7 100644 --- a/adapters/gtest/adapter.go +++ b/adapters/gtest/adapter.go @@ -11,55 +11,38 @@ import (  	"path"  	"sync"  	"time" -  	"golang.flu0r1ne.net/planr"  )  const GTEST_CMAKE = "CMakeLists.txt" -func mkUnit(tc *planr.TestCase) cmakeUnit { +func makeUnit(tc *planr.TestCase, dirs planr.DirConfig) cmakeUnit {    cfg := tc.AdapterConfig().(*GtestConfig) +  testpath := path.Join(dirs.TestsDir(), *cfg.Testfile) +  srclist := cfg.srcList(dirs.SrcDir()) +    return cmakeUnit {      tc.Cname, -    cfg.joinTests(*cfg.Testfile), -    cfg.srcList(), +    testpath, +    srclist,    };  } +func safeWd() string{ +  wd, err := os.Getwd() -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 { -     -    cfg := tc.AdapterConfig().(*GtestConfig) -    cfg.ensureSatisfied(tc.Path) - -    units = append(units, mkUnit(tc)) +  if err != nil { +    log.Fatalf("Could not get GtestBuildDir %s %v\n", wd, err)    } -  genCmake(cmakeFile, units) - -  planr.RunCmd("cmake", "-S", ".", "-B", ".") +  return wd  }  type ResultFromId map[string] Result  func (adapter *GtestAdapter) execTests(cnames []string) ResultFromId { -  buildDir := adapter.Config().Dir() +  buildDir := safeWd()    lut := make(ResultFromId, 0)    for _, exe := range cnames { @@ -154,6 +137,40 @@ func compile(wg * sync.WaitGroup, tc *planr.TestCase) {    tc.Result.DebugOutput = string(out)  } +type GtestAdapter struct { +  dirs planr.DirConfig +} + +func (a *GtestAdapter) Config() planr.AdapterConfig { +  return planr.AdapterConfig { +    Name: "gtest", +    ParseConfig: ParseConfig, +    ParseDefaultConfig: ParseDefaultConfig, +  } +} + +func (a *GtestAdapter) Init(dirs planr.DirConfig) { +  a.dirs = dirs +} + +func (adapter *GtestAdapter) Build(tcs []*planr.TestCase) { +  buildDir := safeWd() +  cmakeFile := path.Join(buildDir, GTEST_CMAKE) + +  units := make([]cmakeUnit, 0) +  for _, tc := range tcs { +     +    cfg := tc.AdapterConfig().(*GtestConfig) +    cfg.ensureSatisfied(tc.Path) + +    units = append(units, makeUnit(tc, adapter.dirs)) +  } + +  genCmake(cmakeFile, units) + +  planr.RunCmd("cmake", "-S", ".", "-B", ".") +} +  // ./planr eval  0.93s user 0.16s system 100% cpu 1.089 total  func (adapter *GtestAdapter) Evaluate(tcs []*planr.TestCase) {    var wg sync.WaitGroup @@ -169,7 +186,7 @@ func (adapter *GtestAdapter) Evaluate(tcs []*planr.TestCase) {    for _, tc := range tcs {      result, ok := resultById[id(tc)] -    // compilation failure +    // compilation failure       if !ok {        fmt.Printf("CAN'T FIND %s: status %d\n", tc.Cname, tc.Result.Status) diff --git a/adapters/gtest/config.go b/adapters/gtest/config.go index cff45fa..4f8735f 100644 --- a/adapters/gtest/config.go +++ b/adapters/gtest/config.go @@ -5,6 +5,7 @@ import (    "golang.flu0r1ne.net/planr"    "strings"    "github.com/BurntSushi/toml" +  "path"  )  type GtestDefaults struct { @@ -42,29 +43,13 @@ func (g GtestConfig) ensureSatisfied(path string) {    }  } -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 { +func (cfg GtestConfig) srcList(srcDir string) 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) + "\"" +      srcs[i] = "\"" + path.Join(srcDir, src) + "\""      }      srcList = strings.Join(srcs, "\n  ") diff --git a/adapters/gtest/templating.go b/adapters/gtest/templating.go index c49f170..a9a3b07 100644 --- a/adapters/gtest/templating.go +++ b/adapters/gtest/templating.go @@ -80,5 +80,3 @@ include(GoogleTest)  FetchContent_MakeAvailable(googletest)  `))  } - - diff --git a/cmd/planr/sub/build.go b/cmd/planr/sub/build.go index 58c3a38..a8b19ec 100644 --- a/cmd/planr/sub/build.go +++ b/cmd/planr/sub/build.go @@ -3,17 +3,21 @@ package sub  import (  	"golang.flu0r1ne.net/planr"  	"golang.flu0r1ne.net/planr/adapters/gtest" +        "os"  )  func Runner() planr.Runner {    r := planr.Runner {} +    r.RegisterAdapter(>est.GtestAdapter{}) + +  if wd, err := os.Getwd(); err != nil { +    r.SetConfigDirFromTree(wd) +  } +    return r  }  func Build(params []string) { - -  rd := planr.RubricDir() - -  Runner().Build(rd) +  Runner().Build()  } diff --git a/cmd/planr/sub/evaluate.go b/cmd/planr/sub/evaluate.go index 8ce4d81..d183b86 100644 --- a/cmd/planr/sub/evaluate.go +++ b/cmd/planr/sub/evaluate.go @@ -5,9 +5,7 @@ import (  )  func Evaluate(params []string) { -  rd := planr.RubricDir() - -  tcs := Runner().Evaluate(rd) +  tcs := Runner().Evaluate()    earned := 0.0    total  := 0.0 @@ -1,11 +1,8 @@  package planr  import ( -  "log"    "github.com/BurntSushi/toml"  ) - -  /*    TODO: Every property defined within the defaults currently     has to implement the "inherit" method to conditionally inherit a @@ -38,22 +35,6 @@ type InheritableConfig interface {    Inherit(parent interface{})  } -// A parser function takes a blob of TOML and decodes it into -// configuration relevant to an adapter -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 -// TOML will be passed to the ParseConfig method or ParseDefaultConfig -// for parsing. The ParseConfig file parses options in test case files. -// The ParseDefaultConfig is parsed by `defaults.toml` files and can -// be used to establish default configuration that will be inherited -// by all units in a common directory (collection) -type AdapterConfig struct { -   Name                string -   ParseConfig         TomlParser -   ParseDefaultConfig  TomlParser -}  // Program-wide configuration which is recognized  // in defaults.toml @@ -82,18 +63,6 @@ type Defaults struct {    configs_    *[]AdapterConfig  } -// Program-wide testcase config -type TestCaseConfig struct { -  Defaults -  Title       *string -  Description *string -} - -func (c TestCaseConfig) ensureSatisfied(name string) { -  if (c.Adapter == nil) { -    log.Fatalf("Adapter must be provided for testcase %s", name) -  } -}  // The default configuration must be able in inherit from  // other defaults further up the tree @@ -169,8 +138,6 @@ func (defaults *Defaults) decodeAdapters(  func DecodeDefaults(path string, adapterCfg []AdapterConfig) (Defaults, error) {    defaults := Defaults { } - -    if _, err := toml.DecodeFile(path, &defaults); err != nil {      return defaults, err    } @@ -45,115 +45,6 @@ func directoryExists(path string) bool {    return info.IsDir()  } -// Find the configuration directory -// Uses: -// 1. PlANR_DIRECTORY env if set -// 2. planr -// 3. .planr -func ConfigDir() string { - -  // Return environmental override if set -  if dir, isSet := os.LookupEnv("PLANR_DIRECTORY"); isSet { - -    if !directoryExists(dir) { -      log.Fatalf("Cannot find planr directory %s", dir); -    } - -    return dir; -  } - -  cwd, err := os.Getwd() - -  if err != nil { -    log.Fatal(err) -  } - -  var rubricDir string - -  rubric_search_dirs := [2]string{ -    "planr", -    ".planr", -  } - -  found := traverseUp(cwd, func (path string) bool { - -    for _, dir := range rubric_search_dirs { -      rubricDir = filepath.Join(path, dir) -       -      if directoryExists(rubricDir) { -        return true -      } -    } - -    return false  -  }); - -  if !found { -    log.Fatal("Could not find planr directory"); -  } - -  return rubricDir -} - -func JoinConfigDir(path_ string, file string) string { -  if path.IsAbs(path_) { -    return path.Join(path_, file)  -  } - -  return path.Join(ConfigDir(), path_, file) -} - -func RootDir() string { -  return path.Join(ConfigDir(), "..") -} - -// Find rubric directory at PLANR_DIR/rubric -func RubricDir() string { -  rubricDir := path.Join(ConfigDir(), "rubric"); - -  if !directoryExists(rubricDir) { -    log.Fatal("Could not find the rubric directory inside of planr")  -  } - -  return rubricDir -} - -func BuildDir() string { -  buildDir := path.Join(ConfigDir(), "build") - -  if !directoryExists(buildDir) { -    err := os.Mkdir(buildDir, 0755) - -    if err != nil { -      log.Fatalf("Cannot create build directory %v\n", err) -    } -  } - -  return buildDir -} - -func CleanBuildDir() { -  buildDir := path.Join(ConfigDir(), "build") -  if err := os.RemoveAll(buildDir); err != nil { -    log.Fatalf("Cannot clean (removeAll) in build directory %v\n", err) -  } -} - -func (ac AdapterConfig) Dir() string { -  dir := BuildDir() -  dir = path.Join(dir, ac.Name) -  -  if !directoryExists(dir) { -    err := os.Mkdir(dir, 0755) - -    if err != nil { -      log.Fatalf("Cannot create build/%s directory %v\n", ac.Name, err) -    } -  } - -  return dir -} -  func basename(path string) string {    ext := filepath.Ext(path)    return path[0:len(path) - len(ext)] @@ -262,3 +153,9 @@ func collectFromDir(      }    }  } + +func safeCd(newWd string) { +  if err := os.Chdir(newWd); err != nil { +    log.Fatalf("Could not change into directory %v\n", err) +  } +} @@ -3,10 +3,12 @@ package planr  import (  	"log"  	"os" +        "path"  )  type Runner struct {    adapters    []Adapter +  DirConfig  }  func (r *Runner) RegisterAdapter(a Adapter) { @@ -43,12 +45,17 @@ func (r Runner) checkConfig(tcs []TestCase) {    }  } -func cdBuild(adapter Adapter) { -  dir := adapter.Config().Dir() +func (r Runner) setupEnv(adapter Adapter) { +  nm := adapter.Config().Name +  wd := path.Join(r.BuildDir(), nm) -  if err := os.Chdir(dir); err != nil { -    log.Fatal(err) -  } +  if !directoryExists(wd) { +    if err := os.Mkdir(wd, 0755); err != nil { +      log.Fatalf("Could not create adapter config %s %v\n", wd, err) +    } +  }  +   +  safeCd(wd)  }  func (r Runner) build(tcs []TestCase) { @@ -58,18 +65,25 @@ func (r Runner) build(tcs []TestCase) {    for _, adapter := range r.adapters {      nm := adapter.Config().Name -    cdBuild(adapter) +    r.setupEnv(adapter)      adapter.Build(tcTab[nm])    } + +  safeCd(r.ConfigDir())  } -func (r Runner) units(root string) []TestCase { -  return collectUnits(root, r.adapterCfgs()) +func (r Runner) units() []TestCase { +  return collectUnits(r.RubricDir(), r.adapterCfgs())  } -func (r Runner) Build(root string) { -  units := r.units(root)  +func (r Runner) Build() { +  units := r.units()  + +  if !directoryExists(r.BuildDir()) { +    r.MkBuildDir() +  } +    r.build(units)  } @@ -78,16 +92,22 @@ func (r Runner) evaluate(tcs []TestCase) {    for _, adapter := range r.adapters {      nm := adapter.Config().Name -    cdBuild(adapter) - +     +    r.setupEnv(adapter)      adapter.Evaluate(tcTab[nm])    } + +  safeCd(r.ConfigDir())  } -func (r Runner) Evaluate(root string) []TestCase { -  units := r.units(root) +func (r Runner) Evaluate() []TestCase { +  units := r.units()    r.evaluate(units)    return units  } + +func (r Runner) Clean() { +  r.CleanBuildDir() +} @@ -40,10 +40,13 @@ const (    DEFAULT_PATH_TESTS="tests"  ) -type dirConfig struct { -  src    string -  config string -  build  string +type DirConfig struct { +  src        string +  config     string +  build      string +   +  // Config falls back to the config found in the parent directory if the env variable hasn't been overridden +  pdFallback string  }  func dieDirAbsent(name, path string) { @@ -63,22 +66,22 @@ func dirFromEnv(name, env string) *string {    return nil  } -func (c *dirConfig) SetSrcDir(srcDir string) { +func (c *DirConfig) SetSrcDir(srcDir string) {    dieDirAbsent("src", srcDir)    c.src = srcDir  } -func (c *dirConfig) SetConfigDir(configDir string) { +func (c *DirConfig) SetConfigDir(configDir string) {    dieDirAbsent("planr (config)", configDir)    c.config = configDir  } -func (c *dirConfig) SetBuildDir(buildDir string) { +func (c *DirConfig) SetBuildDir(buildDir string) {    dieDirAbsent("build", buildDir)    c.build = buildDir  } -func (c *dirConfig) SetConfigDirFromTree(cdir string) { +func (c *DirConfig) SetConfigDirFromTree(cdir string) {    var configDir string    found := traverseUp(cdir, func (path string) bool { @@ -94,28 +97,32 @@ func (c *dirConfig) SetConfigDirFromTree(cdir string) {      return false     }); -  if !found { -    log.Fatal("Could not find planr directory"); -  } -  c.config = configDir +  if found { +    c.pdFallback = configDir +  }  } -func (c dirConfig) ConfigDir() string { +func (c DirConfig) ConfigDir() string {    if c.config != "" {      return c.config    } -  dir := dirFromEnv("config", ENV_CONFIG_DIR) -  if dir == nil { -    log.Fatal("Could not find directory") +   +  if dir := dirFromEnv("config", ENV_CONFIG_DIR); dir != nil { +    c.config = *dir +    return c.config +  } + +  if c.pdFallback == "" { +    log.Fatal("Could not find planr directory");    } -  c.config = *dir +  c.config = c.pdFallback;    return c.config  } -func (c dirConfig) SrcDir() string { +func (c DirConfig) SrcDir() string {    if c.src != "" {      return c.src    } @@ -130,7 +137,7 @@ func (c dirConfig) SrcDir() string {    return path.Join(dir, DEFAULT_PATH_SRC)  } -func (c dirConfig) BuildDir() string { +func (c DirConfig) BuildDir() string {    if c.src != "" {      return c.src    } @@ -144,7 +151,7 @@ func (c dirConfig) BuildDir() string {    return path.Join(dir, DEFAULT_PATH_BUILD)  } -func (c dirConfig) CleanBuildDir() { +func (c DirConfig) CleanBuildDir() {    build := c.BuildDir()    if err := os.RemoveAll(build); err != nil { @@ -156,7 +163,7 @@ func (c dirConfig) CleanBuildDir() {    }  } -func (c dirConfig) MkBuildDir() { +func (c DirConfig) MkBuildDir() {    build := c.BuildDir()    if err := os.Mkdir(build, 0755); err != nil { @@ -164,13 +171,13 @@ func (c dirConfig) MkBuildDir() {    }  } -func (c dirConfig) RubricDir() string { +func (c DirConfig) RubricDir() string {    rubric := path.Join(c.ConfigDir(), "rubric")    dieDirAbsent("rubric", rubric)    return rubric  } -func (c dirConfig) TestsDir() string { +func (c DirConfig) TestsDir() string {    tests := path.Join(c.ConfigDir(), "tests")    dieDirAbsent("tests", tests)    return tests diff --git a/testcase.go b/testcase.go index 8506b84..7e0bf17 100644 --- a/testcase.go +++ b/testcase.go @@ -1,9 +1,13 @@  package planr +import ( +  "log" +) +  type TestStatus uint  const ( -  PASSING TestStatus = iota +  PASSING  TestStatus = iota    COMPILATION_FAILURE    RUNTIME_FAILURE  ) @@ -15,6 +19,19 @@ type TestResult struct {    TestOutput  string  } +// Program-wide testcase config +type TestCaseConfig struct { +  Defaults +  Title       *string +  Description *string +} + +func (c TestCaseConfig) ensureSatisfied(name string) { +  if (c.Adapter == nil) { +    log.Fatalf("Adapter must be provided for testcase %s", name) +  } +} +  type TestCase struct {    // absolute path to the test case configuration    Path   string | 
