package tools
import (
"testing"
"skraak/utils"
)
func NewClassifyState(config ClassifyConfig, dataFiles []*utils.DataFile) *ClassifyState {
hasFilter := config.Filter != "" || config.Species != "" || config.Certainty >= 0
cached := make([][]*utils.Segment, len(dataFiles))
for i, df := range dataFiles {
if !hasFilter {
cached[i] = df.Segments
} else {
for _, seg := range df.Segments {
if seg.SegmentMatchesFilters(config.Filter, config.Species, config.CallType, config.Certainty) {
cached[i] = append(cached[i], seg)
}
}
}
}
total := 0
for _, segs := range cached {
total += len(segs)
}
return &ClassifyState{
Config: config,
DataFiles: dataFiles,
filteredSegs: cached,
totalSegs: total,
}
}
func TestParseKeyBuffer(t *testing.T) {
bindings := []KeyBinding{
{Key: "k", Species: "Kiwi"},
{Key: "d", Species: "Kiwi", CallType: "Duet"},
{Key: "n", Species: "Don't Know"},
{Key: "p", Species: "Morepork"},
}
state := NewClassifyState(ClassifyConfig{Bindings: bindings, Certainty: -1}, nil)
tests := []struct {
key string
want *BindingResult
wantNil bool
}{
{"k", &BindingResult{Species: "Kiwi"}, false},
{"d", &BindingResult{Species: "Kiwi", CallType: "Duet"}, false},
{"n", &BindingResult{Species: "Don't Know"}, false},
{"p", &BindingResult{Species: "Morepork"}, false},
{"x", nil, true}, }
for _, tt := range tests {
got := state.ParseKeyBuffer(tt.key)
if tt.wantNil {
if got != nil {
t.Errorf("ParseKeyBuffer(%q) = %v, want nil", tt.key, got)
}
} else {
if got == nil {
t.Errorf("ParseKeyBuffer(%q) = nil, want %+v", tt.key, tt.want)
continue
}
if got.Species != tt.want.Species {
t.Errorf("ParseKeyBuffer(%q).Species = %q, want %q", tt.key, got.Species, tt.want.Species)
}
if got.CallType != tt.want.CallType {
t.Errorf("ParseKeyBuffer(%q).CallType = %q, want %q", tt.key, got.CallType, tt.want.CallType)
}
}
}
}
func TestApplyBinding(t *testing.T) {
bindings := []KeyBinding{
{Key: "k", Species: "Kiwi"},
{Key: "n", Species: "Don't Know"},
{Key: "d", Species: "Kiwi", CallType: "Duet"},
}
df := &utils.DataFile{
Meta: &utils.DataMeta{},
Segments: []*utils.Segment{
{
StartTime: 10.0,
EndTime: 20.0,
Labels: []*utils.Label{
{Species: "Unknown", Certainty: 50, Filter: "test-filter", CallType: "OldType"},
},
},
},
}
state := NewClassifyState(ClassifyConfig{
Filter: "test-filter",
Reviewer: "David",
Bindings: bindings,
Certainty: -1,
}, []*utils.DataFile{df})
result := &BindingResult{Species: "Kiwi"}
state.ApplyBinding(result)
if len(df.Segments[0].Labels) != 1 {
t.Errorf("expected 1 label, got %d", len(df.Segments[0].Labels))
}
if df.Segments[0].Labels[0].Species != "Kiwi" {
t.Errorf("expected Species=Kiwi, got %s", df.Segments[0].Labels[0].Species)
}
if df.Segments[0].Labels[0].Certainty != 100 {
t.Errorf("expected Certainty=100, got %d", df.Segments[0].Labels[0].Certainty)
}
if df.Segments[0].Labels[0].CallType != "" {
t.Errorf("expected CallType='', got %s (should be removed)", df.Segments[0].Labels[0].CallType)
}
if df.Meta.Reviewer != "David" {
t.Errorf("expected Reviewer=David, got %s", df.Meta.Reviewer)
}
result = &BindingResult{Species: "Kiwi", CallType: "Duet"}
state.ApplyBinding(result)
if df.Segments[0].Labels[0].CallType != "Duet" {
t.Errorf("expected CallType=Duet, got %s", df.Segments[0].Labels[0].CallType)
}
result = &BindingResult{Species: "Don't Know"}
state.ApplyBinding(result)
if df.Segments[0].Labels[0].Species != "Don't Know" {
t.Errorf("expected Species=Don't Know, got %s", df.Segments[0].Labels[0].Species)
}
if df.Segments[0].Labels[0].Certainty != 0 {
t.Errorf("expected Certainty=0 for Don't Know, got %d", df.Segments[0].Labels[0].Certainty)
}
}
func TestApplyBindingCallTypeRemoval(t *testing.T) {
bindings := []KeyBinding{
{Key: "k", Species: "Kiwi"}, }
df := &utils.DataFile{
Meta: &utils.DataMeta{},
Segments: []*utils.Segment{
{
StartTime: 10.0,
EndTime: 20.0,
Labels: []*utils.Label{
{Species: "Kiwi", Certainty: 100, Filter: "test-filter", CallType: "Male"},
},
},
},
}
state := NewClassifyState(ClassifyConfig{
Filter: "test-filter",
Reviewer: "David",
Bindings: bindings,
Certainty: -1,
}, []*utils.DataFile{df})
result := &BindingResult{Species: "Kiwi"}
state.ApplyBinding(result)
if df.Segments[0].Labels[0].CallType != "" {
t.Errorf("expected CallType='', got %s (should be removed)", df.Segments[0].Labels[0].CallType)
}
}
func TestConfirmLabelDontKnow(t *testing.T) {
df := &utils.DataFile{
Meta: &utils.DataMeta{},
Segments: []*utils.Segment{
{
StartTime: 10.0,
EndTime: 20.0,
Labels: []*utils.Label{
{Species: "Don't Know", Certainty: 0, Filter: "test-filter"},
},
},
},
}
state := NewClassifyState(ClassifyConfig{
Filter: "test-filter",
Reviewer: "David",
Certainty: -1,
}, []*utils.DataFile{df})
if state.ConfirmLabel() {
t.Error("ConfirmLabel() should return false for Don't Know (certainty=0)")
}
label := df.Segments[0].Labels[0]
if label.Species != "Don't Know" {
t.Errorf("Species should remain Don't Know, got %s", label.Species)
}
if label.Certainty != 0 {
t.Errorf("Certainty should remain 0, got %d", label.Certainty)
}
if state.Dirty {
t.Error("State should not be dirty after confirming Don't Know")
}
}