Adding upstream version 0.0~git20250520.a1d9079+dfsg.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
590ac7ff5f
commit
20149b7f3a
456 changed files with 70406 additions and 0 deletions
237
app/app_test.go
Normal file
237
app/app_test.go
Normal file
|
@ -0,0 +1,237 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package app_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
_ "image/png"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/mobile/app/internal/apptest"
|
||||
"golang.org/x/mobile/event/size"
|
||||
)
|
||||
|
||||
// TestAndroidApp tests the lifecycle, event, and window semantics of a
|
||||
// simple android app.
|
||||
//
|
||||
// Beyond testing the app package, the goal is to eventually have
|
||||
// helper libraries that make tests like these easy to write. Hopefully
|
||||
// having a user of such a fictional package will help illuminate the way.
|
||||
func TestAndroidApp(t *testing.T) {
|
||||
t.Skip("see issue #23835")
|
||||
if _, err := exec.Command("which", "adb").CombinedOutput(); err != nil {
|
||||
t.Skip("command adb not found, skipping")
|
||||
}
|
||||
devicesTxt, err := exec.Command("adb", "devices").CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("adb devices failed: %v: %v", err, devicesTxt)
|
||||
}
|
||||
deviceCount := 0
|
||||
for _, d := range strings.Split(strings.TrimSpace(string(devicesTxt)), "\n") {
|
||||
if strings.Contains(d, "List of devices") {
|
||||
continue
|
||||
}
|
||||
// TODO(crawshaw): I believe some unusable devices can appear in the
|
||||
// list with note on them, but I cannot reproduce this right now.
|
||||
deviceCount++
|
||||
}
|
||||
if deviceCount == 0 {
|
||||
t.Skip("no android devices attached")
|
||||
}
|
||||
|
||||
run(t, "gomobile", "version")
|
||||
|
||||
origWD, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tmpdir, err := os.MkdirTemp("", "app-test-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
if err := os.Chdir(tmpdir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Chdir(origWD)
|
||||
|
||||
run(t, "gomobile", "install", "golang.org/x/mobile/app/internal/testapp")
|
||||
|
||||
ln, err := net.Listen("tcp4", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
localaddr := fmt.Sprintf("tcp:%d", ln.Addr().(*net.TCPAddr).Port)
|
||||
t.Logf("local address: %s", localaddr)
|
||||
|
||||
exec.Command("adb", "reverse", "--remove", "tcp:"+apptest.Port).Run() // ignore failure
|
||||
run(t, "adb", "reverse", "tcp:"+apptest.Port, localaddr)
|
||||
|
||||
const (
|
||||
KeycodePower = "26"
|
||||
KeycodeUnlock = "82"
|
||||
)
|
||||
|
||||
run(t, "adb", "shell", "input", "keyevent", KeycodePower)
|
||||
run(t, "adb", "shell", "input", "keyevent", KeycodeUnlock)
|
||||
|
||||
const (
|
||||
rotationPortrait = "0"
|
||||
rotationLandscape = "1"
|
||||
)
|
||||
|
||||
rotate := func(rotation string) {
|
||||
run(t, "adb", "shell", "content", "insert", "--uri", "content://settings/system", "--bind", "name:s:user_rotation", "--bind", "value:i:"+rotation)
|
||||
}
|
||||
|
||||
// turn off automatic rotation and start in portrait
|
||||
run(t, "adb", "shell", "content", "insert", "--uri", "content://settings/system", "--bind", "name:s:accelerometer_rotation", "--bind", "value:i:0")
|
||||
rotate(rotationPortrait)
|
||||
|
||||
// start testapp
|
||||
run(t,
|
||||
"adb", "shell", "am", "start", "-n",
|
||||
"org.golang.testapp/org.golang.app.GoNativeActivity",
|
||||
)
|
||||
|
||||
var conn net.Conn
|
||||
connDone := make(chan struct{})
|
||||
go func() {
|
||||
conn, err = ln.Accept()
|
||||
connDone <- struct{}{}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("timeout waiting for testapp to dial host")
|
||||
case <-connDone:
|
||||
if err != nil {
|
||||
t.Fatalf("ln.Accept: %v", err)
|
||||
}
|
||||
}
|
||||
defer conn.Close()
|
||||
comm := &apptest.Comm{
|
||||
Conn: conn,
|
||||
Fatalf: t.Fatalf,
|
||||
Printf: t.Logf,
|
||||
}
|
||||
|
||||
var pixelsPerPt float32
|
||||
var orientation size.Orientation
|
||||
|
||||
comm.Recv("hello_from_testapp")
|
||||
comm.Send("hello_from_host")
|
||||
comm.Recv("lifecycle_visible")
|
||||
comm.Recv("size", &pixelsPerPt, &orientation)
|
||||
if pixelsPerPt < 0.1 {
|
||||
t.Fatalf("bad pixelsPerPt: %f", pixelsPerPt)
|
||||
}
|
||||
|
||||
// A single paint event is sent when the lifecycle enters
|
||||
// StageVisible, and after the end of a touch event.
|
||||
var color string
|
||||
comm.Recv("paint", &color)
|
||||
// Ignore the first paint color, it may be slow making it to the screen.
|
||||
|
||||
rotate(rotationLandscape)
|
||||
comm.Recv("size", &pixelsPerPt, &orientation)
|
||||
if want := size.OrientationLandscape; orientation != want {
|
||||
t.Errorf("want orientation %d, got %d", want, orientation)
|
||||
}
|
||||
|
||||
var x, y int
|
||||
var ty string
|
||||
|
||||
tap(t, 50, 260)
|
||||
comm.Recv("touch", &ty, &x, &y)
|
||||
if ty != "begin" || x != 50 || y != 260 {
|
||||
t.Errorf("want touch begin(50, 260), got %s(%d,%d)", ty, x, y)
|
||||
}
|
||||
comm.Recv("touch", &ty, &x, &y)
|
||||
if ty != "end" || x != 50 || y != 260 {
|
||||
t.Errorf("want touch end(50, 260), got %s(%d,%d)", ty, x, y)
|
||||
}
|
||||
|
||||
comm.Recv("paint", &color)
|
||||
if gotColor := currentColor(t); color != gotColor {
|
||||
t.Errorf("app reports color %q, but saw %q", color, gotColor)
|
||||
}
|
||||
|
||||
rotate(rotationPortrait)
|
||||
comm.Recv("size", &pixelsPerPt, &orientation)
|
||||
if want := size.OrientationPortrait; orientation != want {
|
||||
t.Errorf("want orientation %d, got %d", want, orientation)
|
||||
}
|
||||
|
||||
tap(t, 50, 260)
|
||||
comm.Recv("touch", &ty, &x, &y) // touch begin
|
||||
comm.Recv("touch", &ty, &x, &y) // touch end
|
||||
comm.Recv("paint", &color)
|
||||
if gotColor := currentColor(t); color != gotColor {
|
||||
t.Errorf("app reports color %q, but saw %q", color, gotColor)
|
||||
}
|
||||
|
||||
// TODO: lifecycle testing (NOTE: adb shell input keyevent 4 is the back button)
|
||||
}
|
||||
|
||||
func currentColor(t *testing.T) string {
|
||||
file := fmt.Sprintf("app-screen-%d.png", time.Now().Unix())
|
||||
|
||||
run(t, "adb", "shell", "screencap", "-p", "/data/local/tmp/"+file)
|
||||
run(t, "adb", "pull", "/data/local/tmp/"+file)
|
||||
run(t, "adb", "shell", "rm", "/data/local/tmp/"+file)
|
||||
defer os.Remove(file)
|
||||
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
t.Errorf("currentColor: cannot open screencap: %v", err)
|
||||
return ""
|
||||
}
|
||||
m, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
t.Errorf("currentColor: cannot decode screencap: %v", err)
|
||||
return ""
|
||||
}
|
||||
var center color.Color
|
||||
{
|
||||
b := m.Bounds()
|
||||
x, y := b.Min.X+(b.Max.X-b.Min.X)/2, b.Min.Y+(b.Max.Y-b.Min.Y)/2
|
||||
center = m.At(x, y)
|
||||
}
|
||||
r, g, b, _ := center.RGBA()
|
||||
switch {
|
||||
case r == 0xffff && g == 0x0000 && b == 0x0000:
|
||||
return "red"
|
||||
case r == 0x0000 && g == 0xffff && b == 0x0000:
|
||||
return "green"
|
||||
case r == 0x0000 && g == 0x0000 && b == 0xffff:
|
||||
return "blue"
|
||||
default:
|
||||
return fmt.Sprintf("indeterminate: %v", center)
|
||||
}
|
||||
}
|
||||
|
||||
func tap(t *testing.T, x, y int) {
|
||||
run(t, "adb", "shell", "input", "tap", fmt.Sprintf("%d", x), fmt.Sprintf("%d", y))
|
||||
}
|
||||
|
||||
func run(t *testing.T, cmdName string, arg ...string) {
|
||||
cmd := exec.Command(cmdName, arg...)
|
||||
t.Log(strings.Join(cmd.Args, " "))
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%s %v: %s", strings.Join(cmd.Args, " "), err, out)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue