From 10508bceebc397d36089c67449e641daef7e3670 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sat, 25 Jul 2020 01:40:08 +0000 Subject: [PATCH] get this shit started --- std_test.go | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ tea/fn.go | 5 ++++ tea/plan.go | 34 +++++++++++++++++++++ tea/runner.go | 1 + tea/test.go | 7 +++++ tea/tree.go | 32 ++++++++++++++++++++ tea_test.go | 53 ++++++++++++++++++++++++++++++++ thing.go | 40 +++++++++++++++++++++++++ 8 files changed, 255 insertions(+) create mode 100644 std_test.go create mode 100644 tea/fn.go create mode 100644 tea/plan.go create mode 100644 tea/runner.go create mode 100644 tea/test.go create mode 100644 tea/tree.go create mode 100644 tea_test.go create mode 100644 thing.go diff --git a/std_test.go b/std_test.go new file mode 100644 index 0000000..855191e --- /dev/null +++ b/std_test.go @@ -0,0 +1,83 @@ +// +build std + +package thing + +import ( + "testing" +) + +func TestSet(t *testing.T) { + tests := []struct { + key string + value string + bad bool + }{ + {"foo", "bar", false}, + {"foo", "a-value", false}, + {"foo", "a value", false}, + {"one-two-three", "whatever", false}, + {"one-two-three", "what ever", false}, + {"one two three", "whatever", true}, + {" one-two-three", "whatever", true}, + } + + for _, test := range tests { + thing := new(Thing) + err := thing.Set(test.key, test.value) + if !test.bad && err != nil { + t.Errorf("should be able to set %q=%q but saw error %v", test.key, test.value, err) + } + if test.bad && err == nil { + t.Errorf("able to set bad values %q=%q", test.key, test.value) + } + } +} + +func TestHas(t *testing.T) { + var ( + key = "foo" + value = "bar" + thing = &Thing{ + data: map[string]string{ + key: value, + }, + } + ) + + if !thing.Has(key) { + t.Errorf("missing expected key %q", key) + } +} + +func TestGet(t *testing.T) { + var ( + key = "foo" + value = "bar" + thing = &Thing{ + data: map[string]string{ + key: value, + }, + } + ) + + if v := thing.Get(key); v != value { + t.Errorf("read value %q, expected %q", v, value) + } +} + +func TestKeys(t *testing.T) { + goodKeys := []string{"one", "two", "3", "one-two-three", "steve?"} + badKeys := []string{"o n e", "one two three", " one", "one "} + + for _, key := range goodKeys { + if err := validateKey(key); err != nil { + t.Errorf("key %q should be valid but saw validation error %v", key, err) + } + } + + for _, key := range badKeys { + if err := validateKey(key); err == nil { + t.Errorf("key %q should be invalid but passed validation", key) + } + } +} diff --git a/tea/fn.go b/tea/fn.go new file mode 100644 index 0000000..0eb81fa --- /dev/null +++ b/tea/fn.go @@ -0,0 +1,5 @@ +package tea + +import "testing" + +type Fn func(*testing.T) diff --git a/tea/plan.go b/tea/plan.go new file mode 100644 index 0000000..c90e492 --- /dev/null +++ b/tea/plan.go @@ -0,0 +1,34 @@ +package tea + +import "testing" + +type step struct { + Test + next *step +} + +func (s *step) run(t *testing.T) { + t.Logf("running step: %v", s.Test) + s.Test.Run(t) + if s.next != nil { + s.next.run(t) + } +} + +func (t *Tree) plan() []step { + if len(t.children) == 0 { + // this is a leaf node. + s := &step{Test: t.Test} + for t.parent != nil { + t = t.parent + s = &step{Test: t.Test, next: s} + } + return []step{*s} + } + + var steps []step + for _, child := range t.children { + steps = append(steps, child.plan()...) + } + return steps +} diff --git a/tea/runner.go b/tea/runner.go new file mode 100644 index 0000000..f9164ac --- /dev/null +++ b/tea/runner.go @@ -0,0 +1 @@ +package tea diff --git a/tea/test.go b/tea/test.go new file mode 100644 index 0000000..bc18655 --- /dev/null +++ b/tea/test.go @@ -0,0 +1,7 @@ +package tea + +import "testing" + +type Test interface { + Run(*testing.T) +} diff --git a/tea/tree.go b/tea/tree.go new file mode 100644 index 0000000..8dce551 --- /dev/null +++ b/tea/tree.go @@ -0,0 +1,32 @@ +package tea + +import "testing" + +// Run runs a tree of tests, starting from its root. +func Run(t *testing.T, tree *Tree) { + plan := tree.plan() + t.Logf("steps in plan: %d", len(plan)) + for _, start := range plan { + t.Logf("start test %T: %#v", start.Test, start.Test) + start.run(t) + } +} + +func New(test Test) *Tree { + return &Tree{Test: test} +} + +type Tree struct { + Test + parent *Tree + children []*Tree +} + +func (t *Tree) Child(test Test) *Tree { + child := &Tree{ + Test: test, + parent: t, + } + t.children = append(t.children, child) + return child +} diff --git a/tea_test.go b/tea_test.go new file mode 100644 index 0000000..c2cda1d --- /dev/null +++ b/tea_test.go @@ -0,0 +1,53 @@ +// +build tea + +package thing + +import ( + "fmt" + "testing" + + "./tea" +) + +type testThingSetup struct { + thing *Thing +} + +func (test *testThingSetup) Run(t *testing.T) { + t.Log("Running testThingSetup") + test.thing = new(Thing) +} + +func (test testThingSetup) String() string { return "thingSetup" } + +type setKey struct { + key string + value string + bad bool +} + +func (test setKey) String() string { + return fmt.Sprintf("setKey(%q=%q)", test.key, test.value) +} + +func (test *setKey) Run(t *testing.T) { + t.Logf("Running setKey key: %q value: %q bad?: %t", test.key, test.value, test.bad) + thing := new(Thing) + + err := thing.Set(test.key, test.value) + if !test.bad && err != nil { + t.Errorf("should be able to set %q=%q but saw error %v", test.key, test.value, err) + } + if test.bad && err == nil { + t.Errorf("able to set bad values %q=%q", test.key, test.value) + } +} + +func TestThing(t *testing.T) { + root := tea.New(new(testThingSetup)) + root.Child(&setKey{key: "alice", value: "apple"}) + bob := root.Child(&setKey{key: "bob", value: "banana"}) + bob.Child(&setKey{key: "car-el", value: "candy"}) + root.Child(&setKey{key: "d' oh", bad: true}) + tea.Run(t, root) +} diff --git a/thing.go b/thing.go new file mode 100644 index 0000000..d87fe4c --- /dev/null +++ b/thing.go @@ -0,0 +1,40 @@ +package thing + +import ( + "errors" + "fmt" + "strings" +) + +var ( + ErrInvalidKey = errors.New("invalid key") + ErrNotFound = errors.New("not found") +) + +func validateKey(key string) error { + if strings.Count(key, " ") > 0 { + return fmt.Errorf("%w: key cannot contain spaces", ErrInvalidKey) + } + return nil +} + +type Thing struct { + data map[string]string +} + +func (t *Thing) Get(key string) string { + return t.data[key] +} + +func (t *Thing) Set(key, value string) error { + if err := validateKey(key); err != nil { + return fmt.Errorf("unable to set value for key %q: %w", key, err) + } + t.data = map[string]string{key: value} + return nil +} + +func (t *Thing) Has(key string) bool { + _, ok := t.data[key] + return ok +}