aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--adapters.go24
-rw-r--r--adapters/gtest/adapter.go77
-rw-r--r--adapters/gtest/config.go21
-rw-r--r--adapters/gtest/templating.go2
-rw-r--r--cmd/planr/sub/build.go12
-rw-r--r--cmd/planr/sub/evaluate.go4
-rw-r--r--config.go33
-rw-r--r--fs.go115
-rw-r--r--runner.go48
-rw-r--r--stddirs.go53
-rw-r--r--testcase.go19
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(&gtest.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
diff --git a/config.go b/config.go
index bc0fa6a..887bbb0 100644
--- a/config.go
+++ b/config.go
@@ -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
}
diff --git a/fs.go b/fs.go
index 86de16b..ffc5f05 100644
--- a/fs.go
+++ b/fs.go
@@ -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)
+ }
+}
diff --git a/runner.go b/runner.go
index 3bee17a..f2eb8e9 100644
--- a/runner.go
+++ b/runner.go
@@ -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()
+}
diff --git a/stddirs.go b/stddirs.go
index adefce8..14776d8 100644
--- a/stddirs.go
+++ b/stddirs.go
@@ -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