calls_classify_nav_test.go
package calls
import (
"testing"
"skraak/datafile"
)
// --- Navigation: NextSegment / PrevSegment ---
func TestNextSegment(t *testing.T) {
df := &datafile.DataFile{
FilePath: "/test/f1.data",
Segments: []*datafile.Segment{
{StartTime: 0, EndTime: 10},
{StartTime: 10, EndTime: 20},
},
}
df2 := &datafile.DataFile{
FilePath: "/test/f2.data",
Segments: []*datafile.Segment{
{StartTime: 0, EndTime: 10},
},
}
state := NewClassifyState(ClassifyConfig{Certainty: -1}, []*datafile.DataFile{df, df2})
// Start at file 0, segment 0
if state.FileIdx != 0 || state.SegmentIdx != 0 {
t.Fatalf("initial: file=%d seg=%d", state.FileIdx, state.SegmentIdx)
}
// Advance within same file
if !state.NextSegment() {
t.Error("next within file should succeed")
}
if state.FileIdx != 0 || state.SegmentIdx != 1 {
t.Errorf("after next: file=%d seg=%d", state.FileIdx, state.SegmentIdx)
}
// Advance to next file
if !state.NextSegment() {
t.Error("next to next file should succeed")
}
if state.FileIdx != 1 || state.SegmentIdx != 0 {
t.Errorf("after next file: file=%d seg=%d", state.FileIdx, state.SegmentIdx)
}
// At end
if state.NextSegment() {
t.Error("should fail at end")
}
}
func TestPrevSegment(t *testing.T) {
df := &datafile.DataFile{
FilePath: "/test/f1.data",
Segments: []*datafile.Segment{
{StartTime: 0, EndTime: 10},
},
}
df2 := &datafile.DataFile{
FilePath: "/test/f2.data",
Segments: []*datafile.Segment{
{StartTime: 0, EndTime: 10},
{StartTime: 10, EndTime: 20},
},
}
state := NewClassifyState(ClassifyConfig{Certainty: -1}, []*datafile.DataFile{df, df2})
state.FileIdx = 1
state.SegmentIdx = 1
// Prev within same file
if !state.PrevSegment() {
t.Error("prev within file should succeed")
}
if state.FileIdx != 1 || state.SegmentIdx != 0 {
t.Errorf("after prev: file=%d seg=%d", state.FileIdx, state.SegmentIdx)
}
// Prev to previous file
if !state.PrevSegment() {
t.Error("prev to previous file should succeed")
}
if state.FileIdx != 0 || state.SegmentIdx != 0 {
t.Errorf("after prev file: file=%d seg=%d", state.FileIdx, state.SegmentIdx)
}
// At start
if state.PrevSegment() {
t.Error("should fail at start")
}
}
// --- buildClassifyState goto logic ---
func TestBuildClassifyState_GotoFound(t *testing.T) {
df1 := &datafile.DataFile{FilePath: "/test/alpha.data", Segments: []*datafile.Segment{{}}}
df2 := &datafile.DataFile{FilePath: "/test/beta.data", Segments: []*datafile.Segment{{}}}
segs := [][]*datafile.Segment{df1.Segments, df2.Segments}
state, err := buildClassifyState(ClassifyConfig{Goto: "beta.data"}, []*datafile.DataFile{df1, df2}, segs, 0)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if state.FileIdx != 1 {
t.Errorf("FileIdx=%d, want 1", state.FileIdx)
}
}
func TestBuildClassifyState_GotoNotFound(t *testing.T) {
df1 := &datafile.DataFile{FilePath: "/test/alpha.data", Segments: []*datafile.Segment{{}}}
segs := [][]*datafile.Segment{df1.Segments}
_, err := buildClassifyState(ClassifyConfig{Goto: "missing.data"}, []*datafile.DataFile{df1}, segs, 0)
if err == nil {
t.Error("expected error for missing goto file")
}
}
func TestBuildClassifyState_NoGoto(t *testing.T) {
df1 := &datafile.DataFile{FilePath: "/test/alpha.data", Segments: []*datafile.Segment{{}}}
segs := [][]*datafile.Segment{df1.Segments}
state, err := buildClassifyState(ClassifyConfig{}, []*datafile.DataFile{df1}, segs, 0)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if state.FileIdx != 0 {
t.Errorf("FileIdx=%d, want 0", state.FileIdx)
}
}
// --- FormatLabels ---
func TestFormatLabels(t *testing.T) {
labels := []*datafile.Label{
{Species: "Kiwi", CallType: "Duet", Certainty: 90, Filter: "model-1.0"},
{Species: "Tomtit", Certainty: 70, Filter: "model-2.0"},
}
t.Run("no filter", func(t *testing.T) {
got := FormatLabels(labels, "")
if got == "" {
t.Error("expected non-empty output")
}
// Both labels should appear
if !contains(got, "Kiwi/Duet") {
t.Errorf("expected Kiwi/Duet in %q", got)
}
if !contains(got, "Tomtit") {
t.Errorf("expected Tomtit in %q", got)
}
})
t.Run("with filter", func(t *testing.T) {
got := FormatLabels(labels, "model-1.0")
if !contains(got, "Kiwi") {
t.Errorf("expected Kiwi in %q", got)
}
if contains(got, "Tomtit") {
t.Errorf("Tomtit should be filtered out in %q", got)
}
})
t.Run("with comment", func(t *testing.T) {
labels := []*datafile.Label{
{Species: "Kiwi", Certainty: 100, Filter: "f1", Comment: "nice call"},
}
got := FormatLabels(labels, "")
if !contains(got, `"nice call"`) {
t.Errorf("expected comment in %q", got)
}
})
}
// --- Bookmark navigation ---
func TestBookmarkNavigation(t *testing.T) {
df := &datafile.DataFile{
FilePath: "/test/f1.data",
Meta: &datafile.DataMeta{},
Segments: []*datafile.Segment{
{Labels: []*datafile.Label{{Species: "Kiwi", Filter: "f", Bookmark: true}}},
{Labels: []*datafile.Label{{Species: "Tomtit", Filter: "f"}}},
{Labels: []*datafile.Label{{Species: "Roroa", Filter: "f", Bookmark: true}}},
},
}
state := NewClassifyState(ClassifyConfig{Filter: "f", Certainty: -1}, []*datafile.DataFile{df})
// Start at segment 0 (has bookmark)
if !state.HasBookmark() {
t.Error("segment 0 should have bookmark")
}
// NextBookmark should go to segment 2
if !state.NextBookmark() {
t.Error("NextBookmark should find bookmark at segment 2")
}
if state.SegmentIdx != 2 {
t.Errorf("after NextBookmark: seg=%d, want 2", state.SegmentIdx)
}
// PrevBookmark should go back to segment 0
if !state.PrevBookmark() {
t.Error("PrevBookmark should find bookmark at segment 0")
}
if state.SegmentIdx != 0 {
t.Errorf("after PrevBookmark: seg=%d, want 0", state.SegmentIdx)
}
}
func TestToggleBookmark(t *testing.T) {
df := &datafile.DataFile{
FilePath: "/test/f1.data",
Meta: &datafile.DataMeta{},
Segments: []*datafile.Segment{
{Labels: []*datafile.Label{{Species: "Kiwi", Filter: "f"}}},
},
}
state := NewClassifyState(ClassifyConfig{Filter: "f", Reviewer: "Test", Certainty: -1}, []*datafile.DataFile{df})
if state.HasBookmark() {
t.Error("should start without bookmark")
}
state.ToggleBookmark()
if !state.HasBookmark() {
t.Error("should have bookmark after toggle")
}
state.ToggleBookmark()
if state.HasBookmark() {
t.Error("bookmark should be removed after second toggle")
}
}
// --- ConfirmLabel ---
func TestConfirmLabel(t *testing.T) {
df := &datafile.DataFile{
FilePath: "/test/f1.data",
Meta: &datafile.DataMeta{},
Segments: []*datafile.Segment{
{Labels: []*datafile.Label{{Species: "Kiwi", Filter: "f", Certainty: 70}}},
},
}
state := NewClassifyState(ClassifyConfig{Filter: "f", Reviewer: "Test", Certainty: -1}, []*datafile.DataFile{df})
// Confirm should upgrade 70 → 100
if !state.ConfirmLabel() {
t.Error("ConfirmLabel should return true for certainty < 100")
}
if df.Segments[0].Labels[0].Certainty != 100 {
t.Errorf("certainty=%d, want 100", df.Segments[0].Labels[0].Certainty)
}
// Confirm again on 100 should be no-op
if state.ConfirmLabel() {
t.Error("ConfirmLabel should return false when already at 100")
}
}