summaryrefslogtreecommitdiff
path: root/config.go
diff options
context:
space:
mode:
authorFlu0r1ne <flur01ne@flu0r1ne.net>2021-08-03 02:02:40 -0500
committerFlu0r1ne <flur01ne@flu0r1ne.net>2021-08-03 02:02:40 -0500
commita0b020a78eb0b33965c59460fc093c6959216e44 (patch)
tree3b2722388ea6b312e927b6066b0831524ba4ed6b /config.go
downloaddeb-planr-a0b020a78eb0b33965c59460fc093c6959216e44.tar.xz
deb-planr-a0b020a78eb0b33965c59460fc093c6959216e44.zip
Initial commit with basic build structure
Diffstat (limited to 'config.go')
-rw-r--r--config.go172
1 files changed, 172 insertions, 0 deletions
diff --git a/config.go b/config.go
new file mode 100644
index 0000000..6dd264b
--- /dev/null
+++ b/config.go
@@ -0,0 +1,172 @@
+package planr
+
+import (
+ // "fmt"
+ "log"
+ "github.com/BurntSushi/toml"
+)
+
+
+/*
+ TODO: Every property defined within the defaults currently
+ has to implement the "inherit" method to conditionally inherit a
+ property in relation to a parent. (Ostensibly so that test cases
+ can override default configuration.) This is pedantic because
+ most properties will end up writing boilerplate amounting to:
+
+ parent.inherit()
+ ...
+ if config.property == nil {
+ config.property = config.parent.property
+ }
+
+ This library provides copying behavior between structs
+ with common properties using reflection. It seems like
+ a slight abuse of reflection... But, it could be
+ retro-fitted to implement this behavior if a "onlyCopyZeroFields"
+ option was provided.
+
+ > "github.com/jinzhu/copier"
+*/
+
+// Inheritable configuration can inherit properties defined in a
+// defaults file. This happens on a per-directory basis so multiple
+// tests can share common configuration.
+//
+// The parent will always be of the same type as the child and an
+// assertion is required to define the proper behavior.
+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
+
+// 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
+type Defaults struct {
+ Points *float32
+
+ /*
+ The TOML library only parses exported fields.
+ The Adapters field is an intermediate mapping
+ individual adapters to their locally defined
+ configuration. After they individually process
+ the configuration, it is mapped to the adapters_
+ field.
+
+ See: decodeAdapters()
+ */
+ Adapters *map[string] toml.Primitive
+ adapters_ map[string] InheritableConfig
+
+ /*
+ The configs_ field is necessary to property
+ implement the Inherit method using a common
+ interface.
+ */
+ configs_ *[]AdapterConfig
+}
+
+// Program-wide testcase config
+type TestCaseConfig struct {
+ Defaults
+ Title *string
+ Description *string
+}
+
+// The default configuration must be able in inherit from
+// other defaults further up the tree
+//
+// This provides multiple levels of configurability
+func (child *Defaults) Inherit(p interface{}) {
+ parent := p.(Defaults)
+
+ // Inherit properties which haven't been configured
+ if child.Points == nil {
+ child.Points = parent.Points;
+ }
+
+ // Call the inherit method as defined by the adapters
+ // If an adapter is undefined, inherit the parent configuration
+ //
+ // _configs represents all adapters (registered to a runner)
+ for _, adapter := range *child.configs_ {
+ parent_adapter, parent_exists := parent.adapters_[adapter.Name]
+ child_adapter, child_exists := child.adapters_[adapter.Name]
+
+ if parent_exists {
+ if child_exists {
+ child_adapter.Inherit(parent_adapter)
+ } else {
+ child.adapters_[adapter.Name] = parent_adapter
+ }
+ }
+ }
+}
+
+// Parses the intermediate adapters Adapters containing TOML primitives
+// 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) {
+ defaults.configs_ = &adapters
+ defaults.adapters_ = make(map[string]InheritableConfig)
+
+ if defaults.Adapters != nil {
+ for _, config := range adapters {
+ primitive, exists := (*defaults.Adapters)[config.Name]
+
+ if exists {
+ var parsed InheritableConfig
+ if asDefault {
+ parsed = config.ParseDefaultConfig(primitive)
+ } else {
+ parsed = config.ParseConfig(primitive)
+ }
+
+ defaults.adapters_[config.Name] = parsed
+ }
+ }
+ }
+}
+
+// Decode defaults.toml
+func DecodeDefaults(path string, adapterCfg []AdapterConfig) Defaults {
+ defaults := Defaults { }
+
+ if _, err := toml.DecodeFile(path, &defaults); err != nil {
+ log.Fatal(err)
+ }
+
+ defaults.decodeAdapters(adapterCfg, true)
+
+ return defaults
+}
+
+// Decode an individual unit
+func DecodeConfig(path string, adapterCfg []AdapterConfig) TestCaseConfig {
+ config := TestCaseConfig { }
+
+ if _, err := toml.DecodeFile(path, &config); err != nil {
+ log.Fatal(err)
+ }
+
+ config.decodeAdapters(adapterCfg, false)
+
+ return config
+}