aboutsummaryrefslogtreecommitdiff
path: root/rubric_config.go
diff options
context:
space:
mode:
Diffstat (limited to 'rubric_config.go')
-rw-r--r--rubric_config.go166
1 files changed, 166 insertions, 0 deletions
diff --git a/rubric_config.go b/rubric_config.go
new file mode 100644
index 0000000..887bbb0
--- /dev/null
+++ b/rubric_config.go
@@ -0,0 +1,166 @@
+package planr
+
+import (
+ "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{})
+}
+
+
+// Program-wide configuration which is recognized
+// in defaults.toml
+type Defaults struct {
+ Points *float32
+ Adapter *string
+
+ /*
+ 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
+}
+
+
+// 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;
+ }
+
+ if child.Adapter == nil {
+ child.Adapter = parent.Adapter;
+ }
+
+ // 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,
+) error {
+ 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
+ var err error
+ if asDefault {
+ parsed, err = config.ParseDefaultConfig(primitive)
+ } else {
+ 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, error) {
+ defaults := Defaults { }
+
+ if _, err := toml.DecodeFile(path, &defaults); err != nil {
+ return defaults, err
+ }
+
+ if err := defaults.decodeAdapters(adapterCfg, true); err != nil {
+ return defaults, err
+ }
+
+
+ return defaults, nil
+}
+
+// Decode an individual unit
+func DecodeConfig(path string, adapterCfg []AdapterConfig) (TestCaseConfig, error) {
+ config := TestCaseConfig { }
+
+ if _, err := toml.DecodeFile(path, &config); err != nil {
+ return config, nil
+ }
+
+ if err := config.decodeAdapters(adapterCfg, false); err != nil {
+ return config, err
+ }
+
+ return config, nil
+}