package tools
import (
"math/rand"
"testing"
"skraak/utils"
)
func TestTotalSegmentsRespectsFilters(t *testing.T) {
df1 := &utils.DataFile{
FilePath: "/test/file1.data",
Segments: []*utils.Segment{
{
StartTime: 0,
EndTime: 10,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0"},
},
},
{
StartTime: 10,
EndTime: 20,
Labels: []*utils.Label{
{Species: "Tomtit", Filter: "model-1.0"},
},
},
},
}
df2 := &utils.DataFile{
FilePath: "/test/file2.data",
Segments: []*utils.Segment{
{
StartTime: 0,
EndTime: 10,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0"},
},
},
},
}
state1 := NewClassifyState(ClassifyConfig{Certainty: -1}, []*utils.DataFile{df1, df2})
if got := state1.TotalSegments(); got != 3 {
t.Errorf("No filters: expected 3 segments, got %d", got)
}
state2 := NewClassifyState(ClassifyConfig{Species: "Kiwi", Certainty: -1}, []*utils.DataFile{df1, df2})
if got := state2.TotalSegments(); got != 2 {
t.Errorf("Species=Kiwi: expected 2 segments, got %d", got)
}
state3 := NewClassifyState(ClassifyConfig{Species: "Tomtit", Certainty: -1}, []*utils.DataFile{df1, df2})
if got := state3.TotalSegments(); got != 1 {
t.Errorf("Species=Tomtit: expected 1 segment, got %d", got)
}
state4 := NewClassifyState(ClassifyConfig{Filter: "model-1.0", Certainty: -1}, []*utils.DataFile{df1, df2})
if got := state4.TotalSegments(); got != 3 {
t.Errorf("Filter=model-1.0: expected 3 segments, got %d", got)
}
state5 := NewClassifyState(ClassifyConfig{Species: "NonExistent", Certainty: -1}, []*utils.DataFile{df1, df2})
if got := state5.TotalSegments(); got != 0 {
t.Errorf("Species=NonExistent: expected 0 segments, got %d", got)
}
df3 := &utils.DataFile{
FilePath: "/test/file3.data",
Segments: []*utils.Segment{
{
StartTime: 0,
EndTime: 10,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0", CallType: "Duet"},
},
},
{
StartTime: 10,
EndTime: 20,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-2.0", CallType: "Male"},
},
},
},
}
state6 := NewClassifyState(ClassifyConfig{Filter: "model-1.0", Species: "Kiwi", Certainty: -1}, []*utils.DataFile{df3})
if got := state6.TotalSegments(); got != 1 {
t.Errorf("Filter=model-1.0 + Species=Kiwi: expected 1 segment, got %d", got)
}
}
func TestCurrentSegmentNumberWithFilters(t *testing.T) {
df1 := &utils.DataFile{
FilePath: "/test/file1.data",
Segments: []*utils.Segment{
{
StartTime: 0,
EndTime: 10,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0"},
},
},
{
StartTime: 10,
EndTime: 20,
Labels: []*utils.Label{
{Species: "Tomtit", Filter: "model-1.0"},
},
},
},
}
df2 := &utils.DataFile{
FilePath: "/test/file2.data",
Segments: []*utils.Segment{
{
StartTime: 0,
EndTime: 10,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0"},
},
},
},
}
state := NewClassifyState(ClassifyConfig{Species: "Kiwi", Certainty: -1}, []*utils.DataFile{df1, df2})
state.FileIdx = 1 state.SegmentIdx = 0
if got := state.CurrentSegmentNumber(); got != 2 {
t.Errorf("Species=Kiwi, at file 2, seg 0: expected current segment 2, got %d", got)
}
}
func TestCertaintyFiltering(t *testing.T) {
df := &utils.DataFile{
FilePath: "/test/file1.data",
Segments: []*utils.Segment{
{
StartTime: 0,
EndTime: 10,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0", Certainty: 70},
},
},
{
StartTime: 10,
EndTime: 20,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0", Certainty: 100},
},
},
{
StartTime: 20,
EndTime: 30,
Labels: []*utils.Label{
{Species: "Tomtit", Filter: "model-1.0", Certainty: 70},
},
},
},
}
state1 := NewClassifyState(ClassifyConfig{Certainty: 70}, []*utils.DataFile{df})
if got := state1.TotalSegments(); got != 2 {
t.Errorf("Certainty=70: expected 2 segments, got %d", got)
}
state2 := NewClassifyState(ClassifyConfig{Certainty: 100}, []*utils.DataFile{df})
if got := state2.TotalSegments(); got != 1 {
t.Errorf("Certainty=100: expected 1 segment, got %d", got)
}
state3 := NewClassifyState(ClassifyConfig{Certainty: 0}, []*utils.DataFile{df})
if got := state3.TotalSegments(); got != 0 {
t.Errorf("Certainty=0: expected 0 segments, got %d", got)
}
state4 := NewClassifyState(ClassifyConfig{Species: "Kiwi", Certainty: 70}, []*utils.DataFile{df})
if got := state4.TotalSegments(); got != 1 {
t.Errorf("Species=Kiwi + Certainty=70: expected 1 segment, got %d", got)
}
}
func TestSampling(t *testing.T) {
makeSegs := func(n int) []*utils.Segment {
s := make([]*utils.Segment, n)
for i := range s {
s[i] = &utils.Segment{StartTime: float64(i), EndTime: float64(i + 1)}
}
return s
}
df1 := &utils.DataFile{FilePath: "/test/f1.data", Segments: makeSegs(6)}
df2 := &utils.DataFile{FilePath: "/test/f2.data", Segments: makeSegs(4)}
kept := []*utils.DataFile{df1, df2}
cached := [][]*utils.Segment{df1.Segments, df2.Segments}
countTotal := func(c [][]*utils.Segment) int {
n := 0
for _, s := range c {
n += len(s)
}
return n
}
k, c := applySampling(kept, cached, 50, rand.New(rand.NewSource(42)))
if got := countTotal(c); got != 5 {
t.Errorf("sample 50%%: expected 5, got %d", got)
}
for i := 1; i < len(k); i++ {
if k[i].FilePath < k[i-1].FilePath {
t.Errorf("sample 50%%: files out of order at index %d", i)
}
}
_, c2 := applySampling(kept, cached, 10, rand.New(rand.NewSource(42)))
if got := countTotal(c2); got != 1 {
t.Errorf("sample 10%%: expected 1, got %d", got)
}
_, c3 := applySampling(kept, cached, 1, rand.New(rand.NewSource(42)))
if got := countTotal(c3); got != 1 {
t.Errorf("sample 1%%: expected 1 (clamped), got %d", got)
}
_, c4 := applySampling(kept, cached, 99, rand.New(rand.NewSource(42)))
if got := countTotal(c4); got != 9 {
t.Errorf("sample 99%%: expected 9, got %d", got)
}
}
func TestCertaintyPruning(t *testing.T) {
df1 := &utils.DataFile{
FilePath: "/test/file1.data",
Segments: []*utils.Segment{
{
StartTime: 0,
EndTime: 10,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0", Certainty: 70},
},
},
},
}
df2 := &utils.DataFile{
FilePath: "/test/file2.data",
Segments: []*utils.Segment{
{
StartTime: 0,
EndTime: 10,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0", Certainty: 100},
},
},
},
}
state := NewClassifyState(ClassifyConfig{Certainty: 100}, []*utils.DataFile{df1, df2})
if got := state.TotalSegments(); got != 1 {
t.Errorf("Certainty=100: expected 1 segment, got %d", got)
}
}
func TestCallTypeNoneFiltering(t *testing.T) {
df := &utils.DataFile{
FilePath: "/test/file1.data",
Segments: []*utils.Segment{
{
StartTime: 0,
EndTime: 10,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0", CallType: "Male"},
},
},
{
StartTime: 10,
EndTime: 20,
Labels: []*utils.Label{
{Species: "Kiwi", Filter: "model-1.0"}, },
},
{
StartTime: 20,
EndTime: 30,
Labels: []*utils.Label{
{Species: "Tomtit", Filter: "model-1.0"}, },
},
},
}
state1 := NewClassifyState(ClassifyConfig{Species: "Kiwi", CallType: utils.CallTypeNone, Certainty: -1}, []*utils.DataFile{df})
if got := state1.TotalSegments(); got != 1 {
t.Errorf("Species=Kiwi+_: expected 1 segment, got %d", got)
}
state2 := NewClassifyState(ClassifyConfig{Species: "Kiwi", Certainty: -1}, []*utils.DataFile{df})
if got := state2.TotalSegments(); got != 2 {
t.Errorf("Species=Kiwi: expected 2 segments, got %d", got)
}
state3 := NewClassifyState(ClassifyConfig{Species: "Kiwi", CallType: "Male", Certainty: -1}, []*utils.DataFile{df})
if got := state3.TotalSegments(); got != 1 {
t.Errorf("Species=Kiwi+Male: expected 1 segment, got %d", got)
}
}