mirror of
https://github.com/taigrr/adb.git
synced 2026-04-02 02:58:42 -07:00
- 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
262 lines
6.4 KiB
Go
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)
|
|
}
|
|
}
|