Files
five/hbrdd/bitmap_test.go
Charles KWON OhJun 59568f3301 Five v0.9 — Harbour + Go fusion language
- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline
- Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch
- RTL: 351 Harbour-compatible functions
- RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization
- Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec)
- HB_FUNC API: Full Harbour C API compatible Go bridge
- Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT
- Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST
- Macro Compiler: Runtime AST parsing and evaluation
- Debugger: TUI debugger with source display, breakpoints, stepping
- FRB: Native + Pcode dual mode runtime binary
- Tests: 13 packages ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:41:50 +09:00

238 lines
6.5 KiB
Go

package hbrdd
import (
"testing"
)
// === Unit Tests ===
func TestBitmap_Basic(t *testing.T) {
bm := NewBitmapFilter(100)
bm.Set(1); bm.Set(50); bm.Set(100)
if !bm.Test(1) || !bm.Test(50) || !bm.Test(100) { t.Error("Set bits should test true") }
if bm.Test(2) || bm.Test(99) { t.Error("Unset bits should test false") }
if bm.Count() != 3 { t.Errorf("Count = %d, want 3", bm.Count()) }
}
func TestBitmap_NextSet(t *testing.T) {
bm := NewBitmapFilter(1000)
bm.Set(10); bm.Set(100); bm.Set(500); bm.Set(999)
if n := bm.NextSet(1); n != 10 { t.Errorf("NextSet(1) = %d, want 10", n) }
if n := bm.NextSet(11); n != 100 { t.Errorf("NextSet(11) = %d, want 100", n) }
if n := bm.NextSet(501); n != 999 { t.Errorf("NextSet(501) = %d, want 999", n) }
if n := bm.NextSet(1000); n != 0 { t.Errorf("NextSet(1000) = %d, want 0", n) }
}
func TestBitmap_PrevSet(t *testing.T) {
bm := NewBitmapFilter(1000)
bm.Set(10); bm.Set(100); bm.Set(500); bm.Set(999)
if n := bm.PrevSet(1000); n != 999 { t.Errorf("PrevSet(1000) = %d, want 999", n) }
if n := bm.PrevSet(998); n != 500 { t.Errorf("PrevSet(998) = %d, want 500", n) }
if n := bm.PrevSet(99); n != 10 { t.Errorf("PrevSet(99) = %d, want 10", n) }
if n := bm.PrevSet(9); n != 0 { t.Errorf("PrevSet(9) = %d, want 0", n) }
}
func TestBitmap_Full(t *testing.T) {
bm := NewBitmapFilterFull(100)
if bm.Count() != 100 { t.Errorf("Full count = %d, want 100", bm.Count()) }
bm.Clear(50)
if bm.Count() != 99 { t.Errorf("After clear = %d, want 99", bm.Count()) }
if bm.Test(50) { t.Error("Cleared bit should be false") }
// Verify no excess bits
if bm.Test(101) { t.Error("Bit 101 should be false (past maxRec)") }
}
func TestBitmap_FullEdge(t *testing.T) {
// Test exact 64-bit boundary
bm := NewBitmapFilterFull(64)
if bm.Count() != 64 { t.Errorf("Full(64) = %d", bm.Count()) }
bm2 := NewBitmapFilterFull(65)
if bm2.Count() != 65 { t.Errorf("Full(65) = %d", bm2.Count()) }
bm3 := NewBitmapFilterFull(128)
if bm3.Count() != 128 { t.Errorf("Full(128) = %d", bm3.Count()) }
}
func TestBitmap_And(t *testing.T) {
a := NewBitmapFilter(100)
b := NewBitmapFilter(100)
a.Set(1); a.Set(2); a.Set(3)
b.Set(2); b.Set(3); b.Set(4)
result := a.And(b)
if result.Count() != 2 { t.Errorf("AND count = %d, want 2", result.Count()) }
if !result.Test(2) || !result.Test(3) { t.Error("AND should have 2,3") }
}
func TestBitmap_Or(t *testing.T) {
a := NewBitmapFilter(100)
b := NewBitmapFilter(100)
a.Set(1); a.Set(2)
b.Set(3); b.Set(4)
result := a.Or(b)
if result.Count() != 4 { t.Errorf("OR count = %d, want 4", result.Count()) }
}
func TestBitmap_AndNot(t *testing.T) {
a := NewBitmapFilterFull(100)
b := NewBitmapFilter(100)
b.Set(1); b.Set(50); b.Set(100)
result := a.AndNot(b)
if result.Count() != 97 { t.Errorf("ANDNOT count = %d, want 97", result.Count()) }
if result.Test(1) || result.Test(50) || result.Test(100) { t.Error("ANDNOT should exclude 1,50,100") }
if !result.Test(2) { t.Error("ANDNOT should include 2") }
}
func TestBitmap_Not(t *testing.T) {
bm := NewBitmapFilter(64)
bm.Set(1)
inv := bm.Not()
if inv.Test(1) { t.Error("NOT should clear bit 1") }
if !inv.Test(2) { t.Error("NOT should set bit 2") }
if inv.Count() != 63 { t.Errorf("NOT count = %d, want 63", inv.Count()) }
}
func TestBitmap_InPlace(t *testing.T) {
a := NewBitmapFilterFull(100)
b := NewBitmapFilter(100)
b.Set(10); b.Set(20); b.Set(30)
a.AndInPlace(b)
if a.Count() != 3 { t.Errorf("AndInPlace count = %d, want 3", a.Count()) }
c := NewBitmapFilter(100)
c.Set(40); c.Set(50)
a.OrInPlace(c)
if a.Count() != 5 { t.Errorf("OrInPlace count = %d, want 5", a.Count()) }
}
func TestBitmap_Parallel(t *testing.T) {
bm := BuildParallel(10000, func(r uint32) bool {
return r%10 == 0 // every 10th record
})
if bm.Count() != 1000 { t.Errorf("Parallel count = %d, want 1000", bm.Count()) }
if !bm.Test(10) { t.Error("Record 10 should match") }
if bm.Test(11) { t.Error("Record 11 should not match") }
}
// === Benchmarks ===
func BenchmarkBitmap_NextSet_Sparse(b *testing.B) {
bm := NewBitmapFilter(1000000)
for i := uint32(1); i <= 1000000; i += 100 {
bm.Set(i)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
rec := uint32(1)
for rec != 0 {
rec = bm.NextSet(rec + 1)
}
}
}
func BenchmarkBitmap_PrevSet_Sparse(b *testing.B) {
bm := NewBitmapFilter(1000000)
for i := uint32(1); i <= 1000000; i += 100 {
bm.Set(i)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
rec := bm.maxRec
for rec != 0 {
rec = bm.PrevSet(rec - 1)
}
}
}
func BenchmarkBitmap_NextSet_Dense(b *testing.B) {
bm := NewBitmapFilterFull(1000000)
for i := uint32(1); i <= 1000000; i += 100 {
bm.Clear(i)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
count := 0
rec := uint32(1)
for rec != 0 {
count++
rec = bm.NextSet(rec + 1)
if count > 1000000 { break }
}
}
}
func BenchmarkBitmap_SequentialScan(b *testing.B) {
records := make([]bool, 1000000)
for i := 0; i < len(records); i += 100 {
records[i] = true
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
count := 0
for _, match := range records {
if match { count++ }
}
}
}
func BenchmarkBitmap_And_1M(b *testing.B) {
a := NewBitmapFilterFull(1000000)
bm := NewBitmapFilterFull(1000000)
for i := uint32(1); i <= 1000000; i += 2 { a.Clear(i) }
b.ResetTimer()
for i := 0; i < b.N; i++ {
a.And(bm)
}
}
func BenchmarkBitmap_AndInPlace_1M(b *testing.B) {
template := NewBitmapFilterFull(1000000)
other := NewBitmapFilterFull(1000000)
for i := uint32(1); i <= 1000000; i += 2 { other.Clear(i) }
b.ResetTimer()
for i := 0; i < b.N; i++ {
bm := NewBitmapFilterFull(1000000)
copy(bm.bits, template.bits)
bm.count = template.count
bm.AndInPlace(other)
}
}
func BenchmarkBitmap_Or_1M(b *testing.B) {
a := NewBitmapFilter(1000000)
bm := NewBitmapFilter(1000000)
for i := uint32(1); i <= 1000000; i += 3 { a.Set(i) }
for i := uint32(1); i <= 1000000; i += 5 { bm.Set(i) }
b.ResetTimer()
for i := 0; i < b.N; i++ {
a.Or(bm)
}
}
func BenchmarkBitmap_AndNot_1M(b *testing.B) {
a := NewBitmapFilterFull(1000000)
bm := NewBitmapFilter(1000000)
for i := uint32(1); i <= 1000000; i += 3 { bm.Set(i) }
b.ResetTimer()
for i := 0; i < b.N; i++ {
a.AndNot(bm)
}
}
func BenchmarkBitmap_Parallel_1M(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
BuildParallel(1000000, func(r uint32) bool {
return r%100 == 0
})
}
}
func BenchmarkBitmap_Sequential_1M(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
bm := NewBitmapFilter(1000000)
for r := uint32(1); r <= 1000000; r++ {
if r%100 == 0 { bm.Set(r) }
}
}
}