|
- package rds
-
- import (
- "math"
- "strings"
- "testing"
- )
-
- func TestCRC10KnownVector(t *testing.T) {
- // Verify the CRC polynomial produces 10-bit outputs
- c := crc10(0x1234)
- if c > 0x3FF {
- t.Fatalf("CRC exceeds 10 bits: %x", c)
- }
- }
-
- func TestEncodeBlockProduces26Bits(t *testing.T) {
- block := encodeBlock(0x1234, 'A')
- // Must fit in 26 bits
- if block>>26 != 0 {
- t.Fatalf("block exceeds 26 bits: %x", block)
- }
- // Data portion should be the original word
- data := uint16(block >> 10)
- if data != 0x1234 {
- t.Fatalf("data mismatch: got %x want %x", data, 0x1234)
- }
- }
-
- func TestBuildGroup0ABlockCount(t *testing.T) {
- g := buildGroup0A(0x1234, 0, false, false, 0, "TESTFM")
- // Block A must be PI
- if g[0] != 0x1234 {
- t.Fatalf("block A not PI: %x", g[0])
- }
- // Block D should contain first two PS chars 'T','E'
- ch0 := byte(g[3] >> 8)
- ch1 := byte(g[3] & 0xFF)
- if ch0 != 'T' || ch1 != 'E' {
- t.Fatalf("unexpected PS chars: %c %c", ch0, ch1)
- }
- }
-
- func TestBuildGroup2ABlockCount(t *testing.T) {
- g := buildGroup2A(0x1234, 0, false, false, 0, "Hello World")
- if g[0] != 0x1234 {
- t.Fatalf("block A not PI: %x", g[0])
- }
- // Group type field in block B should have type 2 in bits 15..12
- groupType := (g[1] >> 12) & 0x0F
- if groupType != 2 {
- t.Fatalf("unexpected group type: %d", groupType)
- }
- }
-
- func TestBuildGroupUsesConfiguredPI(t *testing.T) {
- g0 := buildGroup0A(0xBEEF, 0, false, false, 0, "TESTFM")
- if g0[0] != 0xBEEF {
- t.Fatalf("group0A block A not configured PI: %x", g0[0])
- }
- g2 := buildGroup2A(0xCAFE, 0, false, false, 0, "Hello World")
- if g2[0] != 0xCAFE {
- t.Fatalf("group2A block A not configured PI: %x", g2[0])
- }
- }
-
- func TestEncoderGenerate(t *testing.T) {
- cfg := DefaultConfig()
- cfg.SampleRate = 228000
- enc, err := NewEncoder(cfg)
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
-
- samples := enc.Generate(1024)
- if len(samples) != 1024 {
- t.Fatalf("expected 1024 samples, got %d", len(samples))
- }
-
- var maxAbs float64
- var energy float64
- for _, s := range samples {
- a := math.Abs(s)
- energy += s * s
- if a > maxAbs {
- maxAbs = a
- }
- }
-
- if energy == 0 {
- t.Fatal("expected non-zero energy in RDS output")
- }
- if maxAbs > defaultAmplitude*1.01 {
- t.Fatalf("samples exceed configured amplitude: %.6f", maxAbs)
- }
- }
-
- func TestEncoderReset(t *testing.T) {
- cfg := DefaultConfig()
- cfg.SampleRate = 228000
- enc, err := NewEncoder(cfg)
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
-
- sampleA := enc.Generate(1)[0]
- enc.Generate(100)
- enc.Reset()
- sampleB := enc.Generate(1)[0]
- if math.Abs(sampleA-sampleB) > 1e-9 {
- t.Fatalf("expected reset to replay initial sample: %v vs %v", sampleA, sampleB)
- }
- }
-
- func TestGroupSchedulerCycles(t *testing.T) {
- cfg := DefaultConfig()
- cfg.PS = "TESTPS"
- cfg.RT = "short"
- gs := newGroupScheduler(cfg)
-
- // Should get 4 PS groups then RT groups then cycle
- for i := 0; i < 40; i++ {
- _ = gs.NextGroup()
- }
- // No panic = success
- }
-
- func TestNormalizePS(t *testing.T) {
- got := normalizePS("radiox")
- if got != "RADIOX " {
- t.Fatalf("unexpected PS: %q", got)
- }
- }
-
- func TestNormalizeRT(t *testing.T) {
- long := strings.Repeat("a", 80)
- got := normalizeRT(long)
- if len(got) != 64 {
- t.Fatalf("unexpected RT length: %d", len(got))
- }
- }
-
- func TestDifferentialEncoder(t *testing.T) {
- d := diffEncoder{}
- // Input: 0 -> out = 0^0 = 0, prev=0
- // Input: 1 -> out = 0^1 = 1, prev=1
- // Input: 0 -> out = 1^0 = 1, prev=1
- // Input: 1 -> out = 1^1 = 0, prev=0
- expected := []uint8{0, 1, 1, 0}
- input := []uint8{0, 1, 0, 1}
- for i, in := range input {
- got := d.encode(in)
- if got != expected[i] {
- t.Fatalf("step %d: input=%d expected=%d got=%d", i, in, expected[i], got)
- }
- }
- }
-
- func TestRTSegmentCount(t *testing.T) {
- if n := rtSegmentCount("Hi"); n != 1 {
- t.Fatalf("expected 1, got %d", n)
- }
- if n := rtSegmentCount("Hello World!"); n != 3 {
- t.Fatalf("expected 3, got %d", n)
- }
- if n := rtSegmentCount(strings.Repeat("x", 64)); n != 16 {
- t.Fatalf("expected 16, got %d", n)
- }
- }
|