Refactor logging messages for clarity and add unit tests for core functionalities
This commit is contained in:
11
main.go
11
main.go
@ -205,7 +205,7 @@ func (d *twoToneDetector) stepWindow(pcms []int16, t0 time.Time) (event string,
|
|||||||
now := t0
|
now := t0
|
||||||
|
|
||||||
if r < d.rmsThresh {
|
if r < d.rmsThresh {
|
||||||
slog.Debug("Window at %s: RMS %.2f below threshold %.2f, resetting", now.Format(time.RFC3339), r, d.rmsThresh)
|
slog.Debug("Window RMS below threshold, resetting", "at", now.Format(time.RFC3339), "RMS", r, "threshold", d.rmsThresh)
|
||||||
d.reset()
|
d.reset()
|
||||||
return "", 0, 0, 0, 0
|
return "", 0, 0, 0, 0
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ func (d *twoToneDetector) stepWindow(pcms []int16, t0 time.Time) (event string,
|
|||||||
}
|
}
|
||||||
ratio := bestPow / (total + 1e-12)
|
ratio := bestPow / (total + 1e-12)
|
||||||
if ratio < d.ratioThresh {
|
if ratio < d.ratioThresh {
|
||||||
slog.Debug("Window at %s: ratio %.3f below threshold %.3f, resetting", now.Format(time.RFC3339), ratio, d.ratioThresh)
|
slog.Debug("Window ratio below threshold, resetting", "at", now.Format(time.RFC3339), "ratio", ratio, "threshold", d.ratioThresh)
|
||||||
d.reset()
|
d.reset()
|
||||||
return "", 0, 0, 0, 0
|
return "", 0, 0, 0, 0
|
||||||
}
|
}
|
||||||
@ -244,7 +244,7 @@ func (d *twoToneDetector) stepWindow(pcms []int16, t0 time.Time) (event string,
|
|||||||
d.gapRemainMs = d.gapMaxMs
|
d.gapRemainMs = d.gapMaxMs
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
slog.Debug("Window at %s: freq %.1f Hz differs from Tone A %.1f Hz, resetting", now.Format(time.RFC3339), freq, d.aFreq)
|
slog.Debug("Window freq differs from Tone A, resetting A", "at", now.Format(time.RFC3339), "freq (Hz)", freq, "Tone A (Hz)", d.aFreq)
|
||||||
d.reset()
|
d.reset()
|
||||||
}
|
}
|
||||||
} else if d.waitingB {
|
} else if d.waitingB {
|
||||||
@ -258,7 +258,7 @@ func (d *twoToneDetector) stepWindow(pcms []int16, t0 time.Time) (event string,
|
|||||||
d.bFreq = freq
|
d.bFreq = freq
|
||||||
d.bStart = now
|
d.bStart = now
|
||||||
} else if math.Abs(freq-d.bFreq) > 10.0 {
|
} else if math.Abs(freq-d.bFreq) > 10.0 {
|
||||||
slog.Debug("Window at %s: freq %.1f Hz differs from Tone B %.1f Hz, resetting B", now.Format(time.RFC3339), freq, d.bFreq)
|
slog.Debug("Window freq differs from Tone B, resetting B", "at", now.Format(time.RFC3339), "freq (Hz)", freq, "Tone B (Hz)", d.bFreq)
|
||||||
d.bFreq = freq
|
d.bFreq = freq
|
||||||
d.bAccumMs = 0
|
d.bAccumMs = 0
|
||||||
d.bStart = now
|
d.bStart = now
|
||||||
@ -426,8 +426,7 @@ func main() {
|
|||||||
if det.recording {
|
if det.recording {
|
||||||
if !det.bEnd.IsZero() && !chunkTime.Before(det.bEnd.Add(100*time.Millisecond)) {
|
if !det.bEnd.IsZero() && !chunkTime.Before(det.bEnd.Add(100*time.Millisecond)) {
|
||||||
r := rmsPCM(chunk)
|
r := rmsPCM(chunk)
|
||||||
slog.Info("Chunk at %s: RMS=%.2f, silenceThresh=%.2f, silenceAccum=%d ms, recordBuf=%d samples",
|
slog.Info("chunk", "at", chunkTime.Format(time.RFC3339), "RMS", r, "silenceThresh", *silenceThresh, "silenceAccum (ms)", det.silenceAccumMs, "record buffer (samples)", len(det.recordBuf))
|
||||||
chunkTime.Format(time.RFC3339), r, *silenceThresh, det.silenceAccumMs, len(det.recordBuf))
|
|
||||||
if r < *silenceThresh {
|
if r < *silenceThresh {
|
||||||
det.silenceAccumMs += int(time.Duration(len(chunk)) * time.Second / time.Duration(fs) / time.Millisecond)
|
det.silenceAccumMs += int(time.Duration(len(chunk)) * time.Second / time.Duration(fs) / time.Millisecond)
|
||||||
if det.silenceAccumMs >= *silenceDurMs && len(det.recordBuf) > 0 {
|
if det.silenceAccumMs >= *silenceDurMs && len(det.recordBuf) > 0 {
|
||||||
|
100
main_test.go
Normal file
100
main_test.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test decodeMuLaw basic functionality
|
||||||
|
func TestDecodeMuLaw(t *testing.T) {
|
||||||
|
data := []byte{0x00, 0xFF, 0x7F, 0x80}
|
||||||
|
pcm, err := decodeMuLaw(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("decodeMuLaw returned error: %v", err)
|
||||||
|
}
|
||||||
|
if len(pcm) != len(data) {
|
||||||
|
t.Errorf("Expected %d samples, got %d", len(data), len(pcm))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Goertzel power calculation
|
||||||
|
func TestGoertzelPower(t *testing.T) {
|
||||||
|
fs := 8000.0
|
||||||
|
N := 100
|
||||||
|
freq := 1000.0
|
||||||
|
g := newGoertzel(freq, fs, N)
|
||||||
|
signal := make([]float64, N)
|
||||||
|
for i := range signal {
|
||||||
|
signal[i] = math.Sin(2 * math.Pi * freq * float64(i) / fs)
|
||||||
|
}
|
||||||
|
power := g.Power(signal)
|
||||||
|
if power <= 0 {
|
||||||
|
t.Errorf("Expected positive power, got %f", power)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test windowHann modifies slice
|
||||||
|
func TestWindowHann(t *testing.T) {
|
||||||
|
x := []float64{1, 1, 1, 1}
|
||||||
|
windowHann(x)
|
||||||
|
for i, v := range x {
|
||||||
|
if v == 1 {
|
||||||
|
t.Errorf("windowHann did not modify value at index %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test rmsPCM returns correct RMS
|
||||||
|
func TestRmsPCM(t *testing.T) {
|
||||||
|
buf := []int16{1000, -1000, 1000, -1000}
|
||||||
|
rms := rmsPCM(buf)
|
||||||
|
if rms < 900 || rms > 1100 {
|
||||||
|
t.Errorf("Unexpected RMS value: %f", rms)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test twoToneDetector reset
|
||||||
|
func TestTwoToneDetectorReset(t *testing.T) {
|
||||||
|
d := newTwoToneDetector(8000, 100, 50, 0.65, 300, 1000, 3000, 5000)
|
||||||
|
d.inA = true
|
||||||
|
d.aFreq = 1000
|
||||||
|
d.reset()
|
||||||
|
if d.inA || d.aFreq != 0 {
|
||||||
|
t.Errorf("reset did not clear state")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test min function
|
||||||
|
func TestMin(t *testing.T) {
|
||||||
|
if min(1, 2) != 1 {
|
||||||
|
t.Errorf("min(1,2) should be 1")
|
||||||
|
}
|
||||||
|
if min(2, 1) != 1 {
|
||||||
|
t.Errorf("min(2,1) should be 1")
|
||||||
|
}
|
||||||
|
if min(2, 2) != 2 {
|
||||||
|
t.Errorf("min(2,2) should be 2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test saveToWAV (does not check file output, just runs function)
|
||||||
|
func TestSaveToWAV(t *testing.T) {
|
||||||
|
data := make([]int16, 8000)
|
||||||
|
for i := range data {
|
||||||
|
data[i] = int16(i % 32768)
|
||||||
|
}
|
||||||
|
saveToWAV(data, 8000)
|
||||||
|
// No assertion, just ensure no panic
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test stepWindow returns expected values for silence
|
||||||
|
func TestStepWindowSilence(t *testing.T) {
|
||||||
|
d := newTwoToneDetector(8000, 100, 50, 0.65, 300, 1000, 3000, 5000)
|
||||||
|
buf := make([]int16, 100)
|
||||||
|
t0 := time.Now()
|
||||||
|
event, aFreq, aDur, bFreq, bDur := d.stepWindow(buf, t0)
|
||||||
|
if event != "" || aFreq != 0 || aDur != 0 || bFreq != 0 || bDur != 0 {
|
||||||
|
t.Errorf("stepWindow should return zero values for silence")
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user