package tdb import ( "errors" "fmt" "log" "math/rand" "os" "reflect" "strings" "testing" "time" // "encoding/ascii85" // "log" // "strconv" "git.keganmyers.com/terribleplan/tdb/stringy" bolt "go.etcd.io/bbolt" ) const debug = false type testDb struct { db DB TEST_Main Table TEST_OwnedBy Table TEST_ArrayHas Table } const ( letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" letterIdxBits = 6 // 6 bits to represent a letter index letterIdxMask = 1<= 0; { if remain == 0 { cache, remain = src.Int63(), letterIdxMax } if idx := int(cache & letterIdxMask); idx < len(letterBytes) { sb.WriteByte(letterBytes[idx]) i-- } cache >>= letterIdxBits remain-- } return sb.String() } var tdb *testDb var testFilename string func setupCustomTestDb(tb interface{}, schema func(db DBSetup) error) DB { if debug { log.Print("- Creating test database") } testFilename = fmt.Sprintf("%s_test.testdb", randomString(16)) b, err := bolt.Open(testFilename, 0600, nil) if err != nil { panic(fmt.Errorf("Unable to create test DB '%s'", testFilename)) } if db, err := New(b, tb, schema); err != nil { panic(err) } else { return db } } func setupTestDb() { tdb = &testDb{} db := setupCustomTestDb(tdb, func(db DBSetup) error { db.SetDebug(debug) db.AddTableOrPanic(&TEST_Main{}, func(t TableSetup) error { return nil }) db.AddTableOrPanic(&TEST_OwnedBy{}, func(t TableSetup) error { t.AddIndexOrPanic(SimpleIndexOptions{ ConstraintOptions: ConstraintOptions{ Field: "MainId", Foreign: "TEST_Main", NotNull: true, }, }) return nil }) db.AddTableOrPanic(&TEST_ArrayHas{}, func(t TableSetup) error { t.AddArrayIndexOrPanic(ArrayIndexOptions{ ElementsNotNull: true, ConstraintOptions: ConstraintOptions{ Field: "MainIds", Foreign: "TEST_Main", NotNull: true, }, }) return nil }) return nil }) tdb.db = db if tdb.TEST_Main == nil { panic(errors.New("tdb.TEST_Main was not set")) } if tdb.TEST_OwnedBy == nil { panic(errors.New("tdb.TEST_OwnedBy was not set")) } } func cleanupTestDb() { if debug { log.Print("- Closing test database") } tdb.db.Close() err := os.Remove(testFilename) testFilename = "" if err != nil { panic(err) } if debug { log.Print("- Closed test database") } return } func assertUint64Equal(t *testing.T, actual, expected uint64, message string) { assertUint64EqualEnd(t, actual, expected, message) } func assertUint64EqualEnd(t *testing.T, actual, expected uint64, message string) bool { if actual != expected { t.Errorf("%s: got %s, expected %s", message, stringy.ToStringOrPanic(actual), stringy.ToStringOrPanic(expected)) return true } return false } func assertEqual(t *testing.T, actual, expected interface{}, message string) { assertEqualEnd(t, actual, expected, message) } func assertEqualEnd(t *testing.T, actual, expected interface{}, message string) bool { if actual != expected { t.Errorf("%s: got %s, expected %s", message, stringy.ToStringOrPanic(actual), stringy.ToStringOrPanic(expected)) return true } return false } func assertNotEqual(t *testing.T, actual, expected interface{}, message string) { assertNotEqualEnd(t, actual, expected, message) } func assertNotEqualEnd(t *testing.T, actual, expected interface{}, message string) bool { if actual == expected { t.Errorf("%s: got %s, expected anything else", message, stringy.ToStringOrPanic(actual)) return true } return false } func assertNotNil(t *testing.T, actual interface{}, message string) { assertNotNilEnd(t, actual, message) } func assertNotNilEnd(t *testing.T, actual interface{}, message string) bool { if actual == nil { t.Errorf("%s: got %#v, expected non-nil", message, actual) return true } return false } func assertNil(t *testing.T, actual interface{}, message string) { assertNilEnd(t, actual, message) } // typed nil is stupid func assertNilEnd(t *testing.T, actual interface{}, message string) bool { if actual != nil { av := reflect.ValueOf(actual) if !av.IsValid() { return false } if !av.IsNil() || !av.IsZero() { t.Errorf("%s: got %#v, expected nil", message, actual) return true } } return false } func assertOk(t *testing.T, actual bool, message string) { assertOkEnd(t, actual, message) } func assertOkEnd(t *testing.T, actual bool, message string) bool { if !actual { t.Errorf("%s: expected to be ok", message) return true } return false } func dumpBuckets(db *bolt.DB) { fmt.Printf("\n----------\nbuckets:\n\n") if err := db.View(func(tx *bolt.Tx) error { return tx.ForEach(func(name []byte, _ *bolt.Bucket) error { fmt.Printf("%s\n", name) return nil }) }); err != nil { fmt.Printf("\nerror while dumping buckets: %s", err.Error()) } } func dumpKeyspace(db *bolt.DB, bucket string) { fmt.Printf("\n----------\nkeys in '%s':\n\n", bucket) if err := db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(bucket)) if b == nil { fmt.Printf(" (nil bucket)") return nil } c := b.Cursor() for k, _ := c.First(); k != nil; k, _ = c.Next() { fmt.Printf("%s\n", k) } return nil }); err != nil { fmt.Printf("\nerror while dumping keys: %s", err.Error()) } }