Hold replayPairs to a whole replay of every read set rendering together
This commit is contained in:
@@ -146,3 +146,117 @@ func renderRecordRoot(s *session, t *template, columns []Column) {
|
|||||||
}
|
}
|
||||||
renderRecord(s, t, columns, sc)
|
renderRecord(s, t, columns, sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReplayPairsFindsWhatAWholeReplayFinds(t *testing.T) {
|
||||||
|
corpus := fenceCorpus(t)
|
||||||
|
roots, _ := fenceRoots(t, corpus)
|
||||||
|
shipped, err := New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("New() = %v", err)
|
||||||
|
}
|
||||||
|
_ = walkNodes(shipped.categories, func(path string, n node) error {
|
||||||
|
if tm, ok := n.(*template); ok {
|
||||||
|
roots = append(roots, fenceRoot{path, tm})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
for _, root := range roots {
|
||||||
|
wantPairsFindAll(t, root.label, renderDraws(root.t).reads)
|
||||||
|
if root.t.isRecord && len(root.t.fields) > 0 {
|
||||||
|
wantPairsFindAll(t, root.label+" as a record", columnDraws(root.t, sortedNames(root.t.fields)).reads)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReplayPairsFindsWhatAWholeReplayOfSelectedRowsFinds(t *testing.T) {
|
||||||
|
f, err := New(WithDataPath(writeFiles(t, siblings())))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("New = %v", err)
|
||||||
|
}
|
||||||
|
var reads []pathRead
|
||||||
|
_ = walkNodes(f.categories, func(_ string, n node) error {
|
||||||
|
tb, isTable := n.(*table)
|
||||||
|
if !isTable || tb.keyIndex < 0 || tb.familyRoot().path != "region" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for r := 0; r < tb.rowCount(); r++ {
|
||||||
|
inline, err := f.NewTemplate(`"{/` + tb.selectorSpelling(r) + `}"`)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTemplate(%s) = %v", tb.selectorSpelling(r), err)
|
||||||
|
}
|
||||||
|
root, isTemplate := inline.n.(*template)
|
||||||
|
if !isTemplate {
|
||||||
|
t.Fatalf("NewTemplate(%s) compiled to %T", tb.selectorSpelling(r), inline.n)
|
||||||
|
}
|
||||||
|
reads = append(reads, renderDraws(root).reads...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
conflicts := 0
|
||||||
|
for _, a := range reads {
|
||||||
|
for _, b := range reads {
|
||||||
|
for _, c := range reads {
|
||||||
|
triple := []pathRead{a, b, c}
|
||||||
|
wantPairsFindAll(t, a.a.spelling+", "+b.a.spelling+", "+c.a.spelling, triple)
|
||||||
|
if replayPairs(triple) != nil {
|
||||||
|
conflicts++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if conflicts == 0 {
|
||||||
|
t.Error("no triple of selected rows conflicts, so the comparison proved nothing")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func wantPairsFindAll(t *testing.T, label string, reads []pathRead) {
|
||||||
|
t.Helper()
|
||||||
|
var tabled []pathRead
|
||||||
|
for _, r := range reads {
|
||||||
|
if r.tr != nil {
|
||||||
|
tabled = append(tabled, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pairs := replayPairs(reads)
|
||||||
|
var whole error
|
||||||
|
eachRenderSet(tabled, func(set []pathRead) {
|
||||||
|
var d pinSet
|
||||||
|
for _, r := range set {
|
||||||
|
if err := r.tr.replay(&d); err != nil && whole == nil {
|
||||||
|
whole = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (pairs == nil) != (whole == nil) {
|
||||||
|
t.Errorf("%s: replayPairs = %v, a whole replay of every read set rendering together = %v", label, pairs, whole)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eachRenderSet calls fn with every maximal set of reads that render together, by Bron–Kerbosch.
|
||||||
|
func eachRenderSet(reads []pathRead, fn func([]pathRead)) {
|
||||||
|
together := func(a, b pathRead) bool { return a.at.group == b.at.group && !alternatives(a.at, b.at) }
|
||||||
|
var grow func(set, candidates, excluded []pathRead)
|
||||||
|
grow = func(set, candidates, excluded []pathRead) {
|
||||||
|
if len(candidates) == 0 && len(excluded) == 0 {
|
||||||
|
fn(set)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for len(candidates) > 0 {
|
||||||
|
r := candidates[0]
|
||||||
|
var nextC, nextX []pathRead
|
||||||
|
for _, c := range candidates[1:] {
|
||||||
|
if together(r, c) {
|
||||||
|
nextC = append(nextC, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, x := range excluded {
|
||||||
|
if together(r, x) {
|
||||||
|
nextX = append(nextX, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grow(append(set[:len(set):len(set)], r), nextC, nextX)
|
||||||
|
candidates, excluded = candidates[1:], append(excluded, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grow(nil, reads, nil)
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,9 +23,6 @@ Shape 5.8, Self-sufficiency 5.7), every seat capped by Locality, all nine naming
|
|||||||
|
|
||||||
This round, in order:
|
This round, in order:
|
||||||
|
|
||||||
- Hold `replayPairs`' claim that pairs find every conflict a full replay would to a
|
|
||||||
test replaying every read set whole, over the fixtures and the shipped data: six
|
|
||||||
seats could only take the comment's proof on trust.
|
|
||||||
- Key `drawWalk`'s visits by the pins, not `rowsKey`'s `%p` strings, and make leaving
|
- Key `drawWalk`'s visits by the pins, not `rowsKey`'s `%p` strings, and make leaving
|
||||||
`wholeTable` out of the key fail loudly where `checkOwnFamily` has not run: the walk is
|
`wholeTable` out of the key fail loudly where `checkOwnFamily` has not run: the walk is
|
||||||
sound only because another fence ran first, and nothing at the walk enforces it.
|
sound only because another fence ran first, and nothing at the walk enforces it.
|
||||||
|
|||||||
Reference in New Issue
Block a user