summaryrefslogtreecommitdiffstats
path: root/back/qver/version_test.go
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2026-03-14 10:13:55 -0400
committerSam Anthony <sam@samanthony.xyz>2026-03-14 10:13:55 -0400
commit7d622695ae19e518fded6aa5fbf001dae4652211 (patch)
treecca62a7c6213c824adc0ad8447ff189cb106fcf0 /back/qver/version_test.go
parent3b8368d665c8818b84557f54681c5ebab35ba22e (diff)
downloadbuth-7d622695ae19e518fded6aa5fbf001dae4652211.zip
back: add qver package to track qid versions
Diffstat (limited to 'back/qver/version_test.go')
-rw-r--r--back/qver/version_test.go206
1 files changed, 206 insertions, 0 deletions
diff --git a/back/qver/version_test.go b/back/qver/version_test.go
new file mode 100644
index 0000000..4bc9eff
--- /dev/null
+++ b/back/qver/version_test.go
@@ -0,0 +1,206 @@
+package qver_test
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "git.samanthony.xyz/buth/back/qver"
+)
+
+// Bump() should increment the version.
+func TestBump(t *testing.T) {
+ t.Parallel()
+
+ ver := qver.New()
+ defer ver.Close()
+ var i uint32
+ for i = 0; i < 5; i++ {
+ requireVer(t, i, ver)
+ ver.Bump()
+ }
+}
+
+// Bumping the child version should bump the parent version too.
+func TestBumpChild(t *testing.T) {
+ t.Parallel()
+
+ parent := qver.New()
+ child := qver.New(qver.Parent(parent))
+ defer parent.Close()
+ defer child.Close()
+
+ var i uint32
+ for i = 0; i < 5; i++ {
+ requireVer(t, i, child)
+ requireVer(t, i, parent)
+ child.Bump()
+ }
+}
+
+// Bumping the parent version should not affect the child.
+func TestBumpParent(t *testing.T) {
+ t.Parallel()
+
+ parent := qver.New()
+ child := qver.New(qver.Parent(parent))
+ defer parent.Close()
+ defer child.Close()
+
+ requireVer(t, 0, parent)
+ requireVer(t, 0, child)
+
+ for i := 0; i < 5; i++ {
+ parent.Bump()
+ }
+ requireVer(t, 5, parent)
+ requireVer(t, 0, child)
+}
+
+// Bumps should propagate up the chain from parent to child.
+func TestBumpChain(t *testing.T) {
+ t.Parallel()
+
+ a := qver.New()
+ b := qver.New(qver.Parent(a))
+ c := qver.New(qver.Parent(b))
+ defer a.Close()
+ defer b.Close()
+ defer c.Close()
+
+ var i uint32
+ for i = 0; i < 5; i++ {
+ requireVer(t, i, a)
+ requireVer(t, i, b)
+ requireVer(t, i, c)
+ c.Bump()
+ }
+}
+
+// Parent can have several children.
+func TestMultiChild(t *testing.T) {
+ t.Parallel()
+
+ root := qver.New()
+ a, b := qver.New(qver.Parent(root)), qver.New(qver.Parent(root))
+ defer root.Close()
+ defer a.Close()
+ defer b.Close()
+
+ var i uint32
+ for i = 0; i < 3; i++ {
+ requireVer(t, i, root)
+ a.Bump()
+ }
+
+ for i = 0; i < 3; i++ {
+ requireVer(t, i+3, root)
+ b.Bump()
+ }
+
+ root.Bump()
+ requireVer(t, 3+3+1, root)
+}
+
+func TestUpdate(t *testing.T) {
+ t.Parallel()
+
+ state, update := newUpdateFunc()
+ ver := qver.New(qver.Update(state, update))
+ defer ver.Close()
+
+ requireVer(t, 0, ver)
+ state <- true
+ requireVer(t, 1, ver)
+ requireVer(t, 1, ver)
+ state <- false
+ requireVer(t, 1, ver)
+ state <- true
+ requireVer(t, 2, ver)
+}
+
+// Updating the child should bump the parent's version.
+func TestUpdateChild(t *testing.T) {
+ t.Parallel()
+
+ parent := qver.New()
+ defer parent.Close()
+
+ state, update := newUpdateFunc()
+ child := qver.New(qver.Parent(parent), qver.Update(state, update))
+ defer close(state)
+ defer child.Close()
+
+ requireVer(t, 0, parent)
+ requireVer(t, 0, child)
+ state <- true // update child
+ requireVer(t, 1, parent)
+ requireVer(t, 1, child)
+}
+
+// Updating the parent should not affect the child.
+func TestUpdateParent(t *testing.T) {
+ t.Parallel()
+
+ state, update := newUpdateFunc()
+ parent := qver.New(qver.Update(state, update))
+ child := qver.New(qver.Parent(parent))
+ defer close(state)
+ defer parent.Close()
+ defer child.Close()
+
+ requireVer(t, 0, parent)
+ requireVer(t, 0, child)
+ state <- true // update parent
+ requireVer(t, 1, parent)
+ requireVer(t, 0, child)
+}
+
+// Parent should keep working after child is closed.
+func TestCloseChild(t *testing.T) {
+ t.Parallel()
+
+ a := qver.New()
+ requireVer(t, 0, a)
+ a.Bump()
+ requireVer(t, 1, a)
+
+ b := qver.New(qver.Parent(a))
+ b.Bump()
+ requireVer(t, 2, a)
+ b.Close()
+ requireVer(t, 2, a)
+ a.Bump()
+ requireVer(t, 3, a)
+
+ a.Close()
+}
+
+// Update when state buffer contains 'true'.
+func newUpdateFunc() (state chan bool, f qver.UpdateFunc) {
+ return make(chan bool, 1), func(v uint32, state interface{}) (uint32, interface{}, error) {
+ s := state.(chan bool)
+ select {
+ case inc := <-s:
+ if inc {
+ v++
+ }
+ default:
+ }
+ return v, s, nil
+ }
+}
+
+func requireVer(t *testing.T, want uint32, v *qver.Version) {
+ t.Helper()
+ got, err := v.Get()
+ require.NoError(t, err)
+ require.Equal(t, want, got)
+}
+
+func requireAllVer(t *testing.T, want uint32, vs ...*qver.Version) {
+ t.Helper()
+ for _, v := range vs {
+ requireVer(t, want, v)
+ }
+}