package device import ( "math" "os" "path/filepath" "runtime" "strings" "testing" ) func inputFixture(t *testing.T) (*Service, string) { t.Helper() if runtime.GOOS == "windows" { t.Skip("fake adb uses a POSIX shell") } dir := t.TempDir() calls := filepath.Join(dir, "calls") t.Setenv("INPUT_CALLS", calls) path := filepath.Join(dir, "adb") script := `#!/bin/sh printf '%s\n' "$*" >> "$INPUT_CALLS" if [ "$1" != -P ] || [ "$2" != 17891 ]; then exit 42; fi if [ "$REJECT_INPUT" = 1 ]; then echo 'java.lang.SecurityException: requires INJECT_EVENTS permission' >&2; exit 1; fi ` if err := os.WriteFile(path, []byte(script), 0700); err != nil { t.Fatal(err) } previous := adbPathOverride SetAdbPath(path) t.Cleanup(func() { SetAdbPath(previous) }) return &Service{devices: map[string]DeviceInfo{"phone": {ID: "phone", Online: true, Width: 1080, Height: 2400}}}, calls } func TestPhoneInputCommands(t *testing.T) { s, calls := inputFixture(t) if err := s.Tap(TapRequest{DeviceID: "phone", X: 540, Y: 1200}); err != nil { t.Fatal(err) } if err := s.Swipe(SwipeRequest{DeviceID: "phone", X1: 500, Y1: 1800, X2: 500, Y2: 600, DurationMs: 350}); err != nil { t.Fatal(err) } if err := s.Swipe(SwipeRequest{DeviceID: "phone", X1: 1500, Y1: 500, X2: 500, Y2: 500, DurationMs: 400}); err != nil { t.Fatal(err) } output, err := os.ReadFile(calls) if err != nil { t.Fatal(err) } for _, want := range []string{ "-P 17891 -s phone shell input tap 540 1200\n", "-P 17891 -s phone shell input swipe 500 1800 500 600 350\n", "-P 17891 -s phone shell input swipe 1500 500 500 500 400\n", } { if !strings.Contains(string(output), want) { t.Fatalf("wrong phone input: %s", output) } } } func TestInvalidPhoneInputDoesNotExecuteADB(t *testing.T) { s, calls := inputFixture(t) for _, req := range []TapRequest{ {DeviceID: "missing", X: 1, Y: 1}, {DeviceID: "phone", X: math.NaN(), Y: 1}, {DeviceID: "phone", X: 1, Y: math.Inf(1)}, {DeviceID: "phone", X: -1, Y: 1}, {DeviceID: "phone", X: 3000, Y: 1}, {DeviceID: "phone", X: 1500, Y: 1500}, } { if err := s.Tap(req); err == nil { t.Fatalf("accepted invalid tap: %+v", req) } } if err := s.Swipe(SwipeRequest{DeviceID: "phone", DurationMs: 0}); err == nil { t.Fatal("accepted zero swipe duration") } if err := s.Swipe(SwipeRequest{DeviceID: "phone", DurationMs: 1501}); err == nil { t.Fatal("accepted excessive swipe duration") } s.devices["phone"] = DeviceInfo{ID: "phone", Online: false, Width: 1080, Height: 2400} if err := s.Tap(TapRequest{DeviceID: "phone", X: 1, Y: 1}); err == nil { t.Fatal("accepted offline input") } if _, err := os.Stat(calls); !os.IsNotExist(err) { t.Fatalf("invalid input executed adb: %v", err) } } func TestPhoneInputPermissionError(t *testing.T) { s, _ := inputFixture(t) t.Setenv("REJECT_INPUT", "1") err := s.Tap(TapRequest{DeviceID: "phone", X: 1, Y: 1}) if err == nil || !strings.Contains(err.Error(), "USB 调试(安全设置)") { t.Fatalf("missing actionable permission error: %v", err) } }