writer_test.go 4.5 KB

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