Files
sanderling/internal/permissions/permissions_test.go
T
pj d856c40d7c feat(permissions): grant dangerous permissions via aapt + adb
Inspector parses uses-permission entries from `aapt dump permissions`
and the granter shells out to `adb shell pm grant`. Both are pluggable
so tests can drive logic without aapt or a device. Granter failures
become warnings rather than errors — Android refuses non-runtime
permissions and we'd rather keep going than abort the run.
2026-04-17 23:57:17 +07:00

128 lines
3.9 KiB
Go

package permissions
import (
"context"
"errors"
"slices"
"testing"
)
func TestGrantDangerous_FiltersAndCallsGranter(t *testing.T) {
declared := []string{
"android.permission.INTERNET", // not dangerous
"android.permission.CAMERA", // dangerous
"android.permission.WAKE_LOCK", // not dangerous
"android.permission.ACCESS_FINE_LOCATION", // dangerous
"android.permission.READ_EXTERNAL_STORAGE", // dangerous
"android.permission.SYSTEM_ALERT_WINDOW", // not dangerous
}
inspector := func(_ context.Context, _ string) ([]string, error) { return declared, nil }
var requested []string
granter := func(_ context.Context, packageName, permission string) error {
if packageName != "com.example" {
t.Errorf("granter received wrong package: %q", packageName)
}
requested = append(requested, permission)
return nil
}
granted, warnings, err := GrantDangerous(context.Background(), "/path/to/apk", "com.example", inspector, granter)
if err != nil {
t.Fatal(err)
}
want := []string{
"android.permission.CAMERA",
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.READ_EXTERNAL_STORAGE",
}
if !slices.Equal(granted, want) {
t.Errorf("granted permissions: got %v, want %v", granted, want)
}
if !slices.Equal(requested, want) {
t.Errorf("granter calls: got %v, want %v", requested, want)
}
if len(warnings) != 0 {
t.Errorf("expected no warnings, got %v", warnings)
}
}
func TestGrantDangerous_CollectsGranterFailuresAsWarnings(t *testing.T) {
declared := []string{"android.permission.CAMERA", "android.permission.RECORD_AUDIO"}
inspector := func(_ context.Context, _ string) ([]string, error) { return declared, nil }
granter := func(_ context.Context, _, permission string) error {
if permission == "android.permission.CAMERA" {
return errors.New("device denied")
}
return nil
}
granted, warnings, err := GrantDangerous(context.Background(), "/x", "com.example", inspector, granter)
if err != nil {
t.Fatal(err)
}
if !slices.Equal(granted, []string{"android.permission.RECORD_AUDIO"}) {
t.Errorf("granted: %v", granted)
}
if len(warnings) != 1 || warnings[0] != "android.permission.CAMERA: device denied" {
t.Errorf("warnings: %v", warnings)
}
}
func TestGrantDangerous_InspectorErrorBubbles(t *testing.T) {
inspector := func(_ context.Context, _ string) ([]string, error) {
return nil, errors.New("aapt missing")
}
_, _, err := GrantDangerous(context.Background(), "/x", "com.example", inspector, nil)
if err == nil || err.Error() == "" {
t.Errorf("expected wrapped inspector error, got %v", err)
}
}
func TestIsDangerous_KnownPermissions(t *testing.T) {
dangerous := []string{
"android.permission.CAMERA",
"android.permission.RECORD_AUDIO",
"android.permission.POST_NOTIFICATIONS",
}
for _, permission := range dangerous {
if !IsDangerous(permission) {
t.Errorf("expected %q to be dangerous", permission)
}
}
normal := []string{
"android.permission.INTERNET",
"android.permission.WAKE_LOCK",
"android.permission.SYSTEM_ALERT_WINDOW",
}
for _, permission := range normal {
if IsDangerous(permission) {
t.Errorf("expected %q not to be dangerous", permission)
}
}
}
func TestAaptInspector_ParsesFixtureOutput(t *testing.T) {
// Direct test of the regex; avoids spawning aapt.
output := `
package: com.example
sdkVersion:'24'
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.CAMERA'
uses-permission: name='android.permission.WAKE_LOCK'
`
matches := aaptPermissionPattern.FindAllStringSubmatch(output, -1)
got := make([]string, 0, len(matches))
for _, match := range matches {
got = append(got, match[1])
}
want := []string{
"android.permission.INTERNET",
"android.permission.CAMERA",
"android.permission.WAKE_LOCK",
}
if !slices.Equal(got, want) {
t.Errorf("got %v, want %v", got, want)
}
}