test(05-01): add failing tests for TesterDriver, mock drivers, FNB58 streaming

This commit is contained in:
Mikkel Georgsen 2026-04-10 07:06:23 +00:00
parent 984f67834f
commit 384ffac870

View file

@ -0,0 +1,249 @@
package tester_test
import (
"testing"
"time"
"git.georgsen.dk/hwlab/internal/tester"
)
// Compile-time interface assertions
var (
_ tester.TesterDriver = (*tester.MockUSBDriver)(nil)
_ tester.TesterDriver = (*tester.MockDPDriver)(nil)
_ tester.TesterDriver = (*tester.MockHDMIDriver)(nil)
_ tester.StreamingTesterDriver = (*tester.MockFNB58Driver)(nil)
)
// ---- MockUSBDriver tests ----
func TestMockUSBDriver_Connect_Read_Disconnect(t *testing.T) {
d := &tester.MockUSBDriver{}
if err := d.Connect(); err != nil {
t.Fatalf("Connect() unexpected error: %v", err)
}
result, err := d.Read()
if err != nil {
t.Fatalf("Read() unexpected error: %v", err)
}
if result.CableType != tester.CableTypeUSB {
t.Errorf("CableType = %v, want CableTypeUSB", result.CableType)
}
if result.USBVersion != "USB 3.2 Gen 2" {
t.Errorf("USBVersion = %q, want %q", result.USBVersion, "USB 3.2 Gen 2")
}
if result.SpeedGbps != 10.0 {
t.Errorf("SpeedGbps = %v, want 10.0", result.SpeedGbps)
}
if result.MaxWatts != 100 {
t.Errorf("MaxWatts = %v, want 100", result.MaxWatts)
}
if !result.PinContinuity {
t.Error("PinContinuity = false, want true")
}
if !result.HasEMarker {
t.Error("HasEMarker = false, want true")
}
if result.ResistanceOhm != 0.12 {
t.Errorf("ResistanceOhm = %v, want 0.12", result.ResistanceOhm)
}
if err := d.Disconnect(); err != nil {
t.Fatalf("Disconnect() unexpected error: %v", err)
}
// Idempotent second disconnect
if err := d.Disconnect(); err != nil {
t.Fatalf("second Disconnect() unexpected error: %v", err)
}
}
func TestMockUSBDriver_ReadBeforeConnect(t *testing.T) {
d := &tester.MockUSBDriver{}
_, err := d.Read()
if err != tester.ErrNotConnected {
t.Errorf("Read() before Connect() = %v, want ErrNotConnected", err)
}
}
// ---- MockDPDriver tests ----
func TestMockDPDriver_Connect_Read_Disconnect(t *testing.T) {
d := &tester.MockDPDriver{}
if err := d.Connect(); err != nil {
t.Fatalf("Connect() unexpected error: %v", err)
}
result, err := d.Read()
if err != nil {
t.Fatalf("Read() unexpected error: %v", err)
}
if result.CableType != tester.CableTypeDP {
t.Errorf("CableType = %v, want CableTypeDP", result.CableType)
}
if result.DPVersion != "1.4" {
t.Errorf("DPVersion = %q, want %q", result.DPVersion, "1.4")
}
if !result.PinContinuity {
t.Error("PinContinuity = false, want true")
}
if err := d.Disconnect(); err != nil {
t.Fatalf("Disconnect() unexpected error: %v", err)
}
if err := d.Disconnect(); err != nil {
t.Fatalf("second Disconnect() unexpected error: %v", err)
}
}
func TestMockDPDriver_ReadBeforeConnect(t *testing.T) {
d := &tester.MockDPDriver{}
_, err := d.Read()
if err != tester.ErrNotConnected {
t.Errorf("Read() before Connect() = %v, want ErrNotConnected", err)
}
}
// ---- MockHDMIDriver tests ----
func TestMockHDMIDriver_Connect_Read_Disconnect(t *testing.T) {
d := &tester.MockHDMIDriver{}
if err := d.Connect(); err != nil {
t.Fatalf("Connect() unexpected error: %v", err)
}
result, err := d.Read()
if err != nil {
t.Fatalf("Read() unexpected error: %v", err)
}
if result.CableType != tester.CableTypeHDMI {
t.Errorf("CableType = %v, want CableTypeHDMI", result.CableType)
}
if result.HDMIVersion != "2.1" {
t.Errorf("HDMIVersion = %q, want %q", result.HDMIVersion, "2.1")
}
if !result.PinContinuity {
t.Error("PinContinuity = false, want true")
}
if err := d.Disconnect(); err != nil {
t.Fatalf("Disconnect() unexpected error: %v", err)
}
if err := d.Disconnect(); err != nil {
t.Fatalf("second Disconnect() unexpected error: %v", err)
}
}
func TestMockHDMIDriver_ReadBeforeConnect(t *testing.T) {
d := &tester.MockHDMIDriver{}
_, err := d.Read()
if err != tester.ErrNotConnected {
t.Errorf("Read() before Connect() = %v, want ErrNotConnected", err)
}
}
// ---- KnownDevices tests ----
func TestKnownDevices_HasTesterEntries(t *testing.T) {
// This test is in usb package — placeholder to ensure cross-package compile succeeds.
// Actual KnownDevices assertions are in internal/usb/device_test.go
}
// ---- MockFNB58Driver tests ----
func TestFNB58Driver_Connect_Stream_Readings(t *testing.T) {
d := &tester.MockFNB58Driver{}
if err := d.Connect(); err != nil {
t.Fatalf("Connect() unexpected error: %v", err)
}
ch := d.Stream()
if ch == nil {
t.Fatal("Stream() returned nil channel")
}
var readings []tester.LiveReading
timeout := time.After(5 * time.Second)
for {
select {
case r, ok := <-ch:
if !ok {
goto done
}
readings = append(readings, r)
case <-timeout:
t.Fatal("timed out waiting for stream to close")
}
}
done:
if len(readings) != 3 {
t.Errorf("got %d readings, want 3", len(readings))
}
for i, r := range readings {
if r.Voltage != 5.1 {
t.Errorf("reading[%d].Voltage = %v, want 5.1", i, r.Voltage)
}
if r.CurrentAmps != 3.0 {
t.Errorf("reading[%d].CurrentAmps = %v, want 3.0", i, r.CurrentAmps)
}
if r.PowerWatts != 15.3 {
t.Errorf("reading[%d].PowerWatts = %v, want 15.3", i, r.PowerWatts)
}
if r.PDProtocol != "PD3.0" {
t.Errorf("reading[%d].PDProtocol = %q, want %q", i, r.PDProtocol, "PD3.0")
}
if r.Timestamp.IsZero() {
t.Errorf("reading[%d].Timestamp is zero", i)
}
}
if err := d.Disconnect(); err != nil {
t.Fatalf("Disconnect() unexpected error: %v", err)
}
}
func TestStreamBeforeConnect_ReturnsClosed(t *testing.T) {
d := &tester.MockFNB58Driver{}
ch := d.Stream()
if ch == nil {
t.Fatal("Stream() returned nil, want closed channel")
}
select {
case _, ok := <-ch:
if ok {
t.Error("Stream() before Connect() should return a closed channel, got open")
}
default:
t.Error("Stream() before Connect() should return a closed (readable) channel, not blocked")
}
}
func TestFNB58Driver_DisconnectStopsStream(t *testing.T) {
d := &tester.MockFNB58Driver{}
if err := d.Connect(); err != nil {
t.Fatalf("Connect() unexpected error: %v", err)
}
ch := d.Stream()
// Disconnect early — may receive 0..3 readings, then channel closes
if err := d.Disconnect(); err != nil {
t.Fatalf("Disconnect() unexpected error: %v", err)
}
timeout := time.After(2 * time.Second)
for {
select {
case _, ok := <-ch:
if !ok {
return // channel closed — success
}
case <-timeout:
t.Fatal("channel not closed after Disconnect()")
}
}
}