testmark-go

Merge pull request #13 from TripleDogDare/index-fix

commit 99388b38fe570cdfddfc7f1f4a538481a949a282 · parent 9d18105c14 · parent 38936448f0 · browse this tree
Eric Myhre, 2022-11-26 23:16:00 UTC

Index fix
diff --git a/index.go b/index.go
index 25c554c..6d3463d 100644
--- a/index.go
+++ b/index.go
@@ -32,10 +32,11 @@ func (dirent *DirEnt) fill(pathSegs []string, hunk Hunk) {
 		next.fill(pathSegs[1:], hunk)
 	} else {
 		l := len(dirent.ChildrenList)
-		dirent.ChildrenList = append(dirent.ChildrenList, DirEnt{
+		child := DirEnt{
 			Name: pathSegs[0],
-		})
-		dirent.Children[pathSegs[0]] = &dirent.ChildrenList[l]
+		}
+		dirent.ChildrenList = append(dirent.ChildrenList, &child)
+		dirent.Children[pathSegs[0]] = &child
 		dirent.ChildrenList[l].fill(pathSegs[1:], hunk)
 	}
 }
diff --git a/index_test.go b/index_test.go
index a4c9c19..6c4fef8 100644
--- a/index_test.go
+++ b/index_test.go
@@ -1,8 +1,12 @@
-package testmark
+package testmark_test
 
 import (
+	"fmt"
 	"path/filepath"
+	"strings"
 	"testing"
+
+	"github.com/warpfork/go-testmark"
 )
 
 func TestIndexingDirs(t *testing.T) {
@@ -10,13 +14,17 @@ func TestIndexingDirs(t *testing.T) {
 	if err != nil {
 		panic(err)
 	}
-	doc, err := ReadFile(filepath.Join(testdata, "exampleWithDirs.md"))
+	doc, err := testmark.ReadFile(filepath.Join(testdata, "exampleWithDirs.md"))
+	if err != nil {
+		panic(err)
+	}
 	doc.BuildDirIndex()
+
 	if len(doc.DirEnt.ChildrenList) != 2 {
-		t.Errorf("root dirent list should be length 2")
+		t.Errorf("root dirent list should be length 2 but was %d", len(doc.DirEnt.ChildrenList))
 	}
 	if len(doc.DirEnt.Children) != 2 {
-		t.Errorf("root dirent map should be length 2")
+		t.Errorf("root dirent map should be length 2 but was %d", len(doc.DirEnt.Children))
 	}
 	if doc.DirEnt.ChildrenList[0].Name != "one" {
 		t.Errorf("first child of root dirent should've been 'one'")
@@ -37,3 +45,91 @@ func TestIndexingDirs(t *testing.T) {
 		t.Errorf("hunk 'really/deep/dirs/wow' looked up through dir maps should have the right content")
 	}
 }
+
+func TestIndexingTree(t *testing.T) {
+	testdata, err := filepath.Abs("testdata")
+	if err != nil {
+		panic(err)
+	}
+	doc, err := testmark.ReadFile(filepath.Join(testdata, "exampleWithDirs.md"))
+	if err != nil {
+		panic(err)
+	}
+	if len(doc.DataHunks) != len(doc.HunksByName) {
+		t.Errorf("doc hunk list has different length than hunks-by-name: %d != %d",
+			len(doc.DataHunks), len(doc.HunksByName))
+	}
+	doc.BuildDirIndex()
+
+	for _, _hunk := range doc.DataHunks {
+		hunk := _hunk
+		t.Run("index:"+hunk.Name, func(t *testing.T) {
+			assertHunkReachable(t, doc, hunk)
+		})
+	}
+	assertChildren(t, doc.DirEnt)
+}
+
+func assertHunkReachable(t *testing.T, doc *testmark.Document, hunk testmark.DocHunk) {
+	splits := strings.Split(hunk.Name, "/")
+	dir := doc.DirEnt
+	for _, split := range splits {
+		if len(dir.Children) != len(dir.ChildrenList) {
+			t.Errorf("expected dir to have equal number of children in both data structures")
+		}
+		child, ok := dir.Children[split]
+		if !ok {
+			t.Errorf("expected dir %q to have child named %q", dir.Name, split)
+		}
+		dir = child
+	}
+	assert(t, hunk.Hunk, fmt.Sprintf("%v", *dir.Hunk))
+}
+
+func assertChildren(t *testing.T, dir *testmark.DirEnt) {
+	foundChildren := make(map[string]struct{})
+	for _, _child := range dir.ChildrenList {
+		child := _child
+		t.Run(child.Name, func(t *testing.T) {
+			_, exists := foundChildren[child.Name]
+			if exists {
+				t.Errorf("dir %q has duplicate child: %q", dir.Name, child.Name)
+			}
+			foundChildren[child.Name] = struct{}{}
+
+			mapChild, exists := dir.Children[child.Name]
+			if !exists {
+				t.Errorf("dir %q missing child: %q", dir.Name, child.Name)
+			}
+			if child != mapChild {
+				t.Errorf("child %q should have equivalent pointers: %p %p", child.Name, child, mapChild)
+			}
+
+			assertChildren(t, child)
+		})
+	}
+	// If the lengths are equal then the map and list should contain entries with the same names.
+	// We don't know if the dir entries are _actually_ equivalent but the test recurses above so it should be fine.
+	if len(dir.Children) != len(dir.ChildrenList) {
+		t.Errorf(
+			"expected dir to have equal number of children in both data structures"+
+				"\n\t%s:\n\tlist: %v\n\tkeys: %v",
+			dir.Name, names(dir.ChildrenList), keys(dir.Children))
+	}
+}
+
+func keys(dirs map[string]*testmark.DirEnt) []string {
+	names := make([]string, 0, len(dirs))
+	for k := range dirs {
+		names = append(names, k)
+	}
+	return names
+}
+
+func names(dirs []*testmark.DirEnt) []string {
+	names := make([]string, 0, len(dirs))
+	for _, d := range dirs {
+		names = append(names, d.Name)
+	}
+	return names
+}
diff --git a/read_test.go b/read_test.go
index 4ce03c8..41d1c12 100644
--- a/read_test.go
+++ b/read_test.go
@@ -18,7 +18,9 @@ func TestRead(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-
+	if len(doc.DataHunks) != len(doc.HunksByName) {
+		t.Errorf("document hunk list has different length than hunks-by-name: %d != %d", len(doc.DataHunks), len(doc.HunksByName))
+	}
 	readFixturesExample(t, doc)
 }
 
diff --git a/testexec/testexec.go b/testexec/testexec.go
index 1981444..8006d83 100644
--- a/testexec/testexec.go
+++ b/testexec/testexec.go
@@ -139,22 +139,22 @@ func (tcfg *Tester) init() {
 // Regen mode will only update hunks that already exist; it won't add them.
 // As an edge case, note that if that an exitcode hunk is absent, but a nonzero exitcode is encountered,
 // the test will still be failed, even though in patch regen mode most assertions are usually skipped.
-func (tcfg Tester) TestSequence(t *testing.T, data testmark.DirEnt) {
+func (tcfg Tester) TestSequence(t *testing.T, data *testmark.DirEnt) {
 	t.Helper()
 	tcfg.test(t, data, true, false, "")
 }
 
-func (tcfg Tester) TestScript(t *testing.T, data testmark.DirEnt) {
+func (tcfg Tester) TestScript(t *testing.T, data *testmark.DirEnt) {
 	t.Helper()
 	tcfg.test(t, data, false, true, "")
 }
 
-func (tcfg Tester) Test(t *testing.T, data testmark.DirEnt) {
+func (tcfg Tester) Test(t *testing.T, data *testmark.DirEnt) {
 	t.Helper()
 	tcfg.test(t, data, true, true, "")
 }
 
-func (tcfg Tester) test(t *testing.T, data testmark.DirEnt, allowExec, allowScript bool, parentTmpdir string) {
+func (tcfg Tester) test(t *testing.T, data *testmark.DirEnt, allowExec, allowScript bool, parentTmpdir string) {
 	t.Helper()
 	tcfg.init()
 
diff --git a/testmark.go b/testmark.go
index 7b87315..4113279 100644
--- a/testmark.go
+++ b/testmark.go
@@ -72,5 +72,5 @@ type DirEnt struct {
 
 	// Children, recursively.
 	Children     map[string]*DirEnt
-	ChildrenList []DirEnt
+	ChildrenList []*DirEnt
 }
diff --git a/testutil_test.go b/testutil_test.go
index cea3512..8eddc7a 100644
--- a/testutil_test.go
+++ b/testutil_test.go
@@ -22,6 +22,7 @@ import (
 // anything else relies on "%v".
 // It'll emit both the expected and actual values as strings if there's a mismatch.
 func assert(t *testing.T, actual interface{}, expect string) {
+	t.Helper()
 	var actualStr string
 	if s, ok := actual.(string); ok {
 		actualStr = s