diff --git a/env_test.go b/env_test.go index 0000618..198d744 100644 --- a/env_test.go +++ b/env_test.go @@ -212,9 +212,73 @@ func TestMatch(t *testing.T) { t.Errorf("expected Foo to load 5 but is %d instead", test.Foo) } }) + + t.Run("complicated match", func(t *testing.T) { + type connect struct { + Passing + Role string `tea:"save"` + Name string `tea:"save"` + ID int `tea:"save"` + } + + type request struct { + Passing + Role string `tea:"match"` + Name string `tea:"match"` + ID int `tea:"load"` + } + + e := mkenv(connect{ + Role: "host", + ID: 1, + }) + e = e.save(connect{ + Role: "player", + Name: "alice", + ID: 2, + }) + e = e.save(connect{ + Role: "player", + Name: "bob", + ID: 3, + }) + + bob := request{Role: "player", Name: "bob"} + if err := e.load(&bob); err != nil { + t.Errorf("failed to load bob: %s", err) + } else { + if bob.ID != 3 { + t.Errorf("expected bob to have ID 3, has %d instead", bob.ID) + } + } + + alice := request{Role: "player", Name: "alice"} + if err := e.load(&alice); err != nil { + t.Errorf("failed to load alice: %s", err) + } else { + if alice.ID != 2 { + t.Errorf("expected alice to have ID 2, has %d instead", alice.ID) + } + } + + host := request{Role: "host"} + if err := e.load(&host); err != nil { + t.Errorf("failed to load host: %s", err) + } else { + if host.ID != 1 { + t.Errorf("expected host to have ID 1, has %d instead", host.ID) + } + } + + }) } -// A.Optional(B).Child(C) +// Constructing a test node that has multiple parents: +// ----------------------------------------------------------------------------- +// +// In this example, B is an optional test. +// +// Logical Execution // // A A // /| / \ @@ -223,8 +287,38 @@ func TestMatch(t *testing.T) { // \ | | // \| | // C C - -// what to call this thing? +// +// This logical graph of test dependencies would yield an execution plan +// consisting of two test chains: +// +// A -> B -> C +// A -> C +// +// We could write this as follows: +// +// root := New(A) +// b := root.Child(B) +// root.And(b).Child(C) +// +// Alternatively: +// +// root := New(A) +// root.Child(B).And(root).Child(C) +// +// If we permit a selection to append multiple children, we could write this as +// follows: +// +// root := New(A) +// root.Child(B, Pass).Child(C) +// +// This last form is not strictly the same, since it includes an additional +// node in the graph which is a passing test. However since Pass is a +// specific example, we can trivially remove nodes having a test value of +// Pass in the planning phase. +// +// Another simple example: a diamond-shaped test graph +// +// Logical Execution // // A A // / \ / \ @@ -233,3 +327,50 @@ func TestMatch(t *testing.T) { // \ / | | // \ / | | // D D D' +// +// Test Plan: +// - A -> B -> D +// - A -> C -> D +// +// Expressed in test code as follows: +// +// root := New(A) +// both := root.Child(B, C) +// both.Child(D) +// +// Alternatively: +// +// New(A).Child(B, C).Child(D) +// +// +// +// This API is fairly straightforward to use, but breaks down with even simple +// shapes: +// +// A +// / \ +// / \ +// B C +// / \ / +// / \ / +// E D +// +// Test Plan: +// - A -> B -> E +// - A -> B -> D +// - A -> C -> D +// +// Essentially what we're saying is: +// Run test A. +// If test A passes: +// Run test B. +// Run test C. +// +// Expressed as: +// +// root := New(A) +// b := root.Child(B) +// c := root.Child(C) +// b.Child(E) +// b.And(c).Child(D) +//