github.com/adwpc/xmobile@v0.0.0-20231212131043-3f9720cf0e99/cmd/gomobile/writer_test.go (about)

     1  // Copyright 2015 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"crypto/x509"
     9  	"encoding/pem"
    10  	"io"
    11  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"testing"
    15  )
    16  
    17  func TestWriter(t *testing.T) {
    18  	if os.Getenv("GO_BUILDER_NAME") == "linux-amd64-androidemu" {
    19  		t.Skip("skipping on linux-amd64-androidemu builder; see golang.org/issue/40290")
    20  	}
    21  
    22  	block, _ := pem.Decode([]byte(debugCert))
    23  	if block == nil {
    24  		t.Fatal("no cert")
    25  	}
    26  	privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    27  	if err != nil {
    28  		t.Fatal(err)
    29  	}
    30  
    31  	f, err := ioutil.TempFile("", "testapk-")
    32  	if err != nil {
    33  		t.Fatal(err)
    34  	}
    35  	f.Close()
    36  	defer os.Remove(f.Name())
    37  	apkPath := f.Name() + ".apk"
    38  
    39  	f, err = os.Create(apkPath)
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  	defer os.Remove(apkPath)
    44  
    45  	apkw := NewWriter(f, privKey)
    46  
    47  	w, err := apkw.Create("AndroidManifest.xml")
    48  	if err != nil {
    49  		t.Fatalf("could not create AndroidManifest.xml: %v", err)
    50  	}
    51  	if _, err := w.Write([]byte(androidManifest)); err != nil {
    52  		t.Errorf("could not write AndroidManifest.xml: %v", err)
    53  	}
    54  
    55  	w, err = apkw.Create("assets/hello_world.txt")
    56  	if err != nil {
    57  		t.Fatalf("could not create assets/hello_world.txt: %v", err)
    58  	}
    59  	if _, err := w.Write([]byte("Hello, 世界")); err != nil {
    60  		t.Errorf("could not write assets/hello_world.txt: %v", err)
    61  	}
    62  
    63  	if err := apkw.Close(); err != nil {
    64  		t.Fatal(err)
    65  	}
    66  
    67  	if exec.Command("which", "aapt").Run() != nil {
    68  		t.Skip("command aapt not found, skipping")
    69  	}
    70  
    71  	out, err := exec.Command("aapt", "list", "-a", apkPath).CombinedOutput()
    72  	aaptGot := string(out)
    73  	if err != nil {
    74  		t.Logf("aapt:\n%s", aaptGot)
    75  		t.Fatalf("aapt failed: %v", err)
    76  	}
    77  
    78  	if aaptGot != aaptWant {
    79  		t.Errorf("unexpected output from aapt")
    80  		d, err := diff(aaptGot, aaptWant)
    81  		if err != nil {
    82  			t.Errorf("diff failed: %v", err)
    83  		} else {
    84  			t.Logf("%s", d)
    85  		}
    86  	}
    87  }
    88  
    89  const aaptWant = `AndroidManifest.xml
    90  assets/hello_world.txt
    91  META-INF/MANIFEST.MF
    92  META-INF/CERT.SF
    93  META-INF/CERT.RSA
    94  
    95  Resource table:
    96  Package Groups (0)
    97  
    98  Android manifest:
    99  N: android=http://schemas.android.com/apk/res/android
   100    E: manifest (line=2)
   101      A: package="org.golang.fakeapp" (Raw: "org.golang.fakeapp")
   102      A: android:versionCode(0x0101021b)=(type 0x10)0x1
   103      A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")
   104      E: uses-sdk (line=8)
   105        A: android:minSdkVersion(0x0101020c)=(type 0x10)0xf
   106      E: application (line=9)
   107        A: android:label(0x01010001)="FakeApp" (Raw: "FakeApp")
   108        A: android:hasCode(0x0101000c)=(type 0x12)0x0
   109        A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
   110        E: activity (line=10)
   111          A: android:name(0x01010003)="android.app.NativeActivity" (Raw: "android.app.NativeActivity")
   112          A: android:label(0x01010001)="FakeApp" (Raw: "FakeApp")
   113          A: android:configChanges(0x0101001f)=(type 0x11)0xa0
   114          E: intent-filter (line=14)
   115            E: action (line=15)
   116              A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
   117            E: category (line=16)
   118              A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")
   119  `
   120  
   121  const androidManifest = `
   122  <manifest
   123  	xmlns:android="http://schemas.android.com/apk/res/android"
   124  	package="org.golang.fakeapp"
   125  	android:versionCode="1"
   126  	android:versionName="1.0">
   127  
   128  	
   129  	<application android:label="FakeApp" android:hasCode="false" android:debuggable="true">
   130  		<activity android:name="android.app.NativeActivity"
   131  			android:label="FakeApp"
   132  			android:configChanges="orientation|keyboardHidden">
   133  
   134  			<intent-filter>
   135  				<action android:name="android.intent.action.MAIN" />
   136  				<category android:name="android.intent.category.LAUNCHER" />
   137  			</intent-filter>
   138  		</activity>
   139  	</application>
   140  </manifest>
   141  `
   142  
   143  func writeTempFile(data string) (string, error) {
   144  	f, err := ioutil.TempFile("", "gofmt")
   145  	if err != nil {
   146  		return "", err
   147  	}
   148  	_, err = io.WriteString(f, data)
   149  	errc := f.Close()
   150  	if err == nil {
   151  		return f.Name(), errc
   152  	}
   153  	return f.Name(), err
   154  }
   155  
   156  func diff(got, want string) (string, error) {
   157  	wantPath, err := writeTempFile(want)
   158  	if err != nil {
   159  		return "", err
   160  	}
   161  	defer os.Remove(wantPath)
   162  
   163  	gotPath, err := writeTempFile(got)
   164  	if err != nil {
   165  		return "", err
   166  	}
   167  	defer os.Remove(gotPath)
   168  
   169  	data, err := exec.Command("diff", "-u", wantPath, gotPath).CombinedOutput()
   170  	if len(data) > 0 {
   171  		// diff exits with a non-zero status when the files don't match.
   172  		// Ignore that failure as long as we get output.
   173  		err = nil
   174  	}
   175  	return string(data), err
   176  }