From e43149ab9861e1c349086e76cabbba231a6a2f43 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Fri, 31 Jul 2020 19:16:45 +0000 Subject: [PATCH] merging no longer mutates the env --- env.go | 65 ++++++++++++++++++++++++++++++++++++++++------------- env_test.go | 20 ++++++++++++++--- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/env.go b/env.go index 0c11572..9df85fb 100644 --- a/env.go +++ b/env.go @@ -1,8 +1,11 @@ package tea import ( + "bytes" "fmt" "reflect" + "sort" + "strings" ) type env struct { @@ -10,6 +13,31 @@ type env struct { parent *env } +func (e *env) String() string { + var buf bytes.Buffer + e.pretty(&buf) + return buf.String() +} + +func (e *env) pretty(buf *bytes.Buffer) { + if e.parent != nil { + e.parent.pretty(buf) + buf.WriteRune(' ') + } + + var parts []string + for k, v := range e.data { + if s, ok := v.(string); ok { + parts = append(parts, fmt.Sprintf("[%s=%q]", k, s)) + } else { + parts = append(parts, fmt.Sprintf("[%s=%v]", k, v)) + } + } + sort.Strings(parts) + + fmt.Fprintf(buf, "{%s}", strings.Join(parts, ", ")) +} + func mkenv(test Test) *env { var e *env return e.save(test) @@ -110,6 +138,16 @@ func (e *env) match(dest Test) (*env, error) { foundWithCorrectValue = make(map[string]bool) ) + keep := func(v *env) { + if leaf == nil { + leaf = &env{data: v.data} + last = leaf + } else { + next := &env{data: v.data, parent: last} + last = next + } + } + for e := e; e != nil; e = e.parent { present := make([]reflect.StructField, 0, len(required)) @@ -131,6 +169,8 @@ func (e *env) match(dest Test) (*env, error) { // check that the values in the env match the values that were // asked for. matched := make(map[string]interface{}) + wrongVal := make(map[string]bool) + for _, f := range required { fv := destV.FieldByName(f.Name) if fv.Interface() == e.data[f.Name] { @@ -138,32 +178,25 @@ func (e *env) match(dest Test) (*env, error) { matched[f.Name] = e.data[f.Name] } else { foundWithWrongValue[f.Name] = true + wrongVal[f.Name] = true } } + if len(wrongVal) > 0 { + continue + } + // all required match conditions are met if len(matched) == len(required) { - if leaf == nil { - // if this is the first matched layer, it is the leaf of the - // resultant env. - leaf = e - last = leaf - } else { - // otherwise we keep this layer, since it matched our match - // requirements. Another layer already did, but there may - // be other things in the layer we want to keep. - last.parent = e - last = e - } + keep(e) } } else { // the required fields do not exist in the layer, so this layer // does not conflict with the match requirement. if leaf != nil { - // since we have a leaf node, we have found a matching layer, - // and since this layer does not conflict, we keep it. - last.parent = e - last = e + // since we have a leaf node, we have already found a matching + // layer, and since this layer does not conflict, we keep it. + keep(e) } } } diff --git a/env_test.go b/env_test.go index 9973f51..d27f79e 100644 --- a/env_test.go +++ b/env_test.go @@ -280,6 +280,7 @@ func TestMatch(t *testing.T) { ID: 3, }) + t.Logf("before bob loaded %v", e) bob := request{Role: "player", Name: "bob"} if err := e.load(&bob); err != nil { t.Errorf("failed to load bob: %s", err) @@ -288,6 +289,7 @@ func TestMatch(t *testing.T) { t.Errorf("expected bob to have ID 3, has %d instead", bob.ID) } } + t.Logf("after bob loaded %v", e) alice := request{Role: "player", Name: "alice"} if err := e.load(&alice); err != nil { @@ -297,6 +299,7 @@ func TestMatch(t *testing.T) { t.Errorf("expected alice to have ID 2, has %d instead", alice.ID) } } + t.Logf("after alice loaded %v", e) host := request{Role: "host"} if err := e.load(&host); err != nil { @@ -308,7 +311,7 @@ func TestMatch(t *testing.T) { } }) - t.Run("layer-skipping matches", func(t *testing.T) { + t.Run("junk-filtering matches", func(t *testing.T) { type connect struct { Passing Role string `tea:"save"` @@ -324,14 +327,21 @@ func TestMatch(t *testing.T) { body string } + type junk struct { + Passing + Fart string `tea:"save"` + } + e := mkenv(connect{ Role: "host", ID: 1, }) + e = e.save(junk{Fart: "first-junk"}) e = e.save(request{ Role: "host", body: "one", }) + e = e.save(connect{ Role: "player", Name: "alice", @@ -343,6 +353,7 @@ func TestMatch(t *testing.T) { Name: "alice", ID: 2, }) + e = e.save(Pass) e = e.save(connect{ Role: "player", Name: "bob", @@ -353,8 +364,12 @@ func TestMatch(t *testing.T) { Role: "player", body: "one", }) + e = e.save(junk{Fart: "second-junk"}) bob := request{Role: "player", Name: "bob"} + alice := request{Role: "player", Name: "alice"} + host := request{Role: "host"} + if err := e.load(&bob); err != nil { t.Errorf("failed to load bob: %s", err) } else { @@ -363,8 +378,8 @@ func TestMatch(t *testing.T) { } } - alice := request{Role: "player", Name: "alice"} if err := e.load(&alice); err != nil { + t.Log(e) t.Errorf("failed to load alice: %s", err) } else { if alice.ID != 2 { @@ -372,7 +387,6 @@ func TestMatch(t *testing.T) { } } - host := request{Role: "host"} if err := e.load(&host); err != nil { t.Errorf("failed to load host: %s", err) } else {