diff options
Diffstat (limited to 'internal/cond')
| -rw-r--r-- | internal/cond/eval.go | 13 | ||||
| -rw-r--r-- | internal/cond/eval_test.go | 24 |
2 files changed, 30 insertions, 7 deletions
diff --git a/internal/cond/eval.go b/internal/cond/eval.go index c9f7f75..31c54e3 100644 --- a/internal/cond/eval.go +++ b/internal/cond/eval.go @@ -24,7 +24,11 @@ type Facts interface { // -1 when it contains none. ContentContains(opt Options, keywords []string) (int, error) Duplicate(dirs []string) (original string, ok bool, err error) - Matched() bool // an earlier rule matched this file + // Matched reports whether an earlier rule matched this file, and whether + // an earlier rule could not be decided (its condition was unknown): with + // no match and an undecided rule, (matched) is unknown (plan 11 review + // L6). + Matched() (matched, undecided bool) } // Result is the outcome of evaluating a Cond against one file's Facts. @@ -154,6 +158,9 @@ func (c *Cond) eval(n *node, f Facts, ctx *evalCtx, negated bool) (tri, []string } return yes, []string{"not " + label} default: + if m, undecided := f.Matched(); n.kind == kMatched && !m && undecided { + return unknown, nil + } ok, reason, warn, caps := c.evalLeaf(n, f) ctx.warn(warn) if warn != "" && n.kind == kContent { @@ -258,7 +265,7 @@ func (c *Cond) evalLeaf(n *node, f Facts) (ok bool, reason, warn string, caps [] return false, "", "", nil case kMatched: - if f.Matched() { + if m, _ := f.Matched(); m { return true, "matched", "", nil } return false, "", "", nil @@ -348,7 +355,7 @@ func (c *Cond) explain(n *node, f Facts) *Trace { default: ok, _, warn, _ := c.evalLeaf(n, f) t := &Trace{Label: n.label, Value: ok, Err: warn} - if warn != "" && n.kind == kContent { + if m, undecided := f.Matched(); (warn != "" && n.kind == kContent) || (n.kind == kMatched && !m && undecided) { t.set(unknown) } return t diff --git a/internal/cond/eval_test.go b/internal/cond/eval_test.go index 7d796a1..9352b82 100644 --- a/internal/cond/eval_test.go +++ b/internal/cond/eval_test.go @@ -21,6 +21,7 @@ type fake struct { size int64 age time.Duration matched bool + matchedUnknown bool dupOrig string dupOK bool contentCalls int @@ -33,10 +34,10 @@ func (f *fake) Rel() string { } return f.name } -func (f *fake) Size() int64 { return f.size } -func (f *fake) ModTime() time.Time { return now.Add(-f.age) } -func (f *fake) Now() time.Time { return now } -func (f *fake) Matched() bool { return f.matched } +func (f *fake) Size() int64 { return f.size } +func (f *fake) ModTime() time.Time { return now.Add(-f.age) } +func (f *fake) Now() time.Time { return now } +func (f *fake) Matched() (bool, bool) { return f.matched, f.matchedUnknown } func (f *fake) ContentContains(opt Options, keywords []string) (int, error) { f.contentCalls++ if f.rawErr != nil { @@ -284,3 +285,18 @@ func TestUnreadableContentIsUnknown(t *testing.T) { } } } + +// TestMatchedIsUnknownAfterAnUnknownRule: when no earlier rule matched but +// one could not be decided, (matched) is unknown, so a later +// (not (matched)) does not act on a file krino could not read (plan 11 +// review L6). +func TestMatchedIsUnknownAfterAnUnknownRule(t *testing.T) { + f := &fake{name: "a.docx", matchedUnknown: true} + if r := eval(t, `(not (matched))`, Options{}, f); r.Match || !r.Unreadable { + t.Errorf("(not (matched)): Match %v Unreadable %v; want false, true", r.Match, r.Unreadable) + } + f = &fake{name: "a.docx", matched: true, matchedUnknown: true} + if r := eval(t, `(matched)`, Options{}, f); !r.Match { + t.Errorf("(matched) after a rule that did match: %+v, want true", r) + } +} |
