Files
adb/adb_test.go
Tai Groot 9ed4d3ef4f fix: replace panic with error return in execute(), fix Pull/Push/Reboot/Root targeting
- execute() no longer panics when adb is not found; returns ErrNotInstalled
- Use sync.Once for lazy adb path lookup instead of init()
- Fix Pull() checking src (device path) instead of dest (local path)
- Add ErrDestExists error for Pull destination conflicts
- Add -s serial flag to Push, Pull, Reboot, Root for multi-device support
- Root() now parses stdout to determine actual success
- Fix Shell() redundant variable redeclaration
- Fix 'inconsostency' typo in KillServer doc
- Add doc comments to all error variables
- Update Go 1.26.0 -> 1.26.1
- Add tests: ConnString, ShortenSleep, GetLength, JSON roundtrip,
  SequenceImporter.ToInput, insertSleeps, parseDevices edge cases,
  parseScreenResolution edge cases, filterErr
2026-03-14 06:33:10 +00:00

262 lines
6.4 KiB
Go

package adb
import (
"net"
"reflect"
"testing"
"time"
)
func Test_parseDevices(t *testing.T) {
type args struct {
stdout string
}
tests := []struct {
name string
args args
want []Device
wantErr bool
}{
{
name: "no devices", args: args{stdout: `List of devices attached`},
wantErr: false,
want: []Device{},
},
{
name: "1 auth dev", args: args{stdout: `List of devices attached
19291FDEE0023W device`},
wantErr: false,
want: []Device{
{IsAuthorized: true, SerialNo: "19291FDEE0023W"},
},
},
{
name: "1 unauth dev", args: args{stdout: `List of devices attached
HT75R0202681 unauthorized`},
wantErr: false,
want: []Device{
{IsAuthorized: false, SerialNo: "HT75R0202681"},
},
},
{
name: "2 auth 1 unauth", args: args{stdout: `List of devices attached
19291FDEE0023W device
9B061FFBA00BC9 device
HT75R0202681 unauthorized`},
wantErr: false,
want: []Device{
{IsAuthorized: true, SerialNo: "19291FDEE0023W"},
{IsAuthorized: true, SerialNo: "9B061FFBA00BC9"},
{IsAuthorized: false, SerialNo: "HT75R0202681"},
},
},
{
name: "empty string",
args: args{stdout: ""},
wantErr: false,
want: []Device{},
},
{
name: "offline device",
args: args{stdout: `List of devices attached
ABCD1234 offline`},
wantErr: false,
want: []Device{
{IsAuthorized: false, SerialNo: "ABCD1234"},
},
},
{
name: "extra whitespace lines",
args: args{stdout: `List of devices attached
19291FDEE0023W device
`},
wantErr: false,
want: []Device{
{IsAuthorized: true, SerialNo: "19291FDEE0023W"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseDevices(tt.args.stdout)
if (err != nil) != tt.wantErr {
t.Errorf("parseDevices() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseDevices() = %v, want %v", got, tt.want)
}
})
}
}
func TestDevice_ConnString(t *testing.T) {
tests := []struct {
name string
dev Device
want string
}{
{
name: "default port",
dev: Device{IP: net.IPAddr{IP: net.ParseIP("192.168.1.100")}},
want: "192.168.1.100:5555",
},
{
name: "custom port",
dev: Device{IP: net.IPAddr{IP: net.ParseIP("10.0.0.5")}, Port: 5556},
want: "10.0.0.5:5556",
},
{
name: "ipv6",
dev: Device{IP: net.IPAddr{IP: net.ParseIP("::1")}, Port: 5555},
want: "::1:5555",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.dev.ConnString()
if got != tt.want {
t.Errorf("ConnString() = %q, want %q", got, tt.want)
}
})
}
}
func TestTapSequence_ShortenSleep(t *testing.T) {
seq := TapSequence{
Events: []Input{
SequenceTap{X: 100, Y: 200, Type: SeqTap},
SequenceSleep{Duration: time.Second * 4, Type: SeqSleep},
SequenceTap{X: 300, Y: 400, Type: SeqTap},
},
}
shortened := seq.ShortenSleep(2)
if len(shortened.Events) != 3 {
t.Fatalf("expected 3 events, got %d", len(shortened.Events))
}
sleep, ok := shortened.Events[1].(SequenceSleep)
if !ok {
t.Fatal("expected second event to be SequenceSleep")
}
if sleep.Duration != time.Second*2 {
t.Errorf("expected sleep duration 2s, got %v", sleep.Duration)
}
}
func TestTapSequence_GetLength(t *testing.T) {
now := time.Now()
seq := TapSequence{
Events: []Input{
SequenceSleep{Duration: time.Second * 10, Type: SeqSleep},
SequenceSwipe{
X1: 0, Y1: 0, X2: 100, Y2: 100,
Start: now, End: now.Add(time.Second * 5),
Type: SeqSwipe,
},
},
}
got := seq.GetLength()
// 15s * 110/100 = 16.5s
want := time.Second * 15 * 110 / 100
if got != want {
t.Errorf("GetLength() = %v, want %v", got, want)
}
}
func TestTapSequence_JSONRoundTrip(t *testing.T) {
now := time.UnixMilli(1700000000000)
original := TapSequence{
Resolution: Resolution{Width: 1080, Height: 2340},
Events: []Input{
SequenceSwipe{
X1: 10, Y1: 20, X2: 30, Y2: 40,
Start: now, End: now.Add(time.Millisecond * 500),
Type: SeqSwipe,
},
},
}
jsonBytes := original.ToJSON()
roundTripped, err := TapSequenceFromJSON(jsonBytes)
if err != nil {
t.Fatalf("TapSequenceFromJSON() error = %v", err)
}
if roundTripped.Resolution != original.Resolution {
t.Errorf("Resolution mismatch: got %v, want %v", roundTripped.Resolution, original.Resolution)
}
if len(roundTripped.Events) != len(original.Events) {
t.Fatalf("Events length mismatch: got %d, want %d", len(roundTripped.Events), len(original.Events))
}
}
func TestSequenceImporter_ToInput(t *testing.T) {
now := time.UnixMilli(1700000000000)
tests := []struct {
name string
importer SequenceImporter
wantType SeqType
}{
{
name: "sleep",
importer: SequenceImporter{Type: SeqSleep, Duration: time.Second},
wantType: SeqSleep,
},
{
name: "tap",
importer: SequenceImporter{Type: SeqTap, X: 10, Y: 20, Start: now, End: now},
wantType: SeqTap,
},
{
name: "swipe",
importer: SequenceImporter{Type: SeqSwipe, X1: 10, Y1: 20, X2: 30, Y2: 40, Start: now, End: now.Add(time.Second)},
wantType: SeqSwipe,
},
{
name: "unknown defaults to sleep",
importer: SequenceImporter{Type: SeqType(99)},
wantType: SeqSleep,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
input := tt.importer.ToInput()
switch tt.wantType {
case SeqSleep:
if _, ok := input.(SequenceSleep); !ok {
t.Errorf("expected SequenceSleep, got %T", input)
}
case SeqTap:
if _, ok := input.(SequenceTap); !ok {
t.Errorf("expected SequenceTap, got %T", input)
}
case SeqSwipe:
if _, ok := input.(SequenceSwipe); !ok {
t.Errorf("expected SequenceSwipe, got %T", input)
}
}
})
}
}
func TestInsertSleeps(t *testing.T) {
now := time.UnixMilli(1000)
inputs := []Input{
SequenceTap{X: 1, Y: 2, Start: now, End: now.Add(time.Millisecond * 100), Type: SeqTap},
SequenceTap{X: 3, Y: 4, Start: now.Add(time.Millisecond * 500), End: now.Add(time.Millisecond * 600), Type: SeqTap},
}
result := insertSleeps(inputs)
// Should be: tap, sleep, tap
if len(result) != 3 {
t.Fatalf("expected 3 events, got %d", len(result))
}
sleep, ok := result[1].(SequenceSleep)
if !ok {
t.Fatal("expected second event to be SequenceSleep")
}
// Sleep should be from end of first (100ms) to end of second (600ms) = 500ms
if sleep.Duration != time.Millisecond*500 {
t.Errorf("expected sleep duration 500ms, got %v", sleep.Duration)
}
}