package ultrabeam

import (
	"errors"
	"io"
	"net"
	"testing"
	"time"
)

// The two transports report a slow reply differently, and neither means the
// link is gone: a remote TCP hop and a controller busy moving its motors both
// look like silence. Getting this wrong tears the connection down on every poll.
func TestTransientRead(t *testing.T) {
	if !transientRead(timeoutErr{}) {
		t.Errorf("a TCP read timeout must be transient")
	}
	// A serial port that stays silent returns (0, nil) forever; bufio gives up
	// after a hundred empty reads with ErrNoProgress.
	if !transientRead(io.ErrNoProgress) {
		t.Errorf("a silent serial port must be transient")
	}
	if transientRead(io.EOF) {
		t.Errorf("EOF is the link closing, not a slow reply")
	}
	if transientRead(errors.New("access denied")) {
		t.Errorf("an open failure is not a slow reply")
	}
}

// open must refuse a configuration it cannot honour rather than dial nothing.
func TestOpenRejectsEmptyConfig(t *testing.T) {
	if _, err := New(Transport{Mode: "serial"}).open(); err == nil {
		t.Errorf("serial with no COM port must fail")
	}
	if _, err := New(Transport{Mode: "tcp"}).open(); err == nil {
		t.Errorf("tcp with no host must fail")
	}
}

// A missing baud is the controller's default, not zero — serial.Open would
// reject 0 and the operator would see "invalid speed" for a field they never
// knew existed.
func TestDefaultBaud(t *testing.T) {
	if got := New(Transport{Mode: "serial", COM: "COM3"}).tr.Baud; got != 9600 {
		t.Errorf("default baud = %d, want 9600", got)
	}
}

type timeoutErr struct{}

func (timeoutErr) Error() string   { return "i/o timeout" }
func (timeoutErr) Timeout() bool   { return true }
func (timeoutErr) Temporary() bool { return true }

var _ net.Error = timeoutErr{}
var _ = time.Second
