github.com/cyrilou242/gomobile-java@v0.0.0-20220215185836-09daef25a210/cmd/gomobile/bind_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 "bytes" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "runtime" 14 "strings" 15 "testing" 16 "text/template" 17 ) 18 19 func TestBindAndroid(t *testing.T) { 20 androidHome := os.Getenv("ANDROID_HOME") 21 if androidHome == "" { 22 t.Skip("ANDROID_HOME not found, skipping bind") 23 } 24 platform, err := androidAPIPath() 25 if err != nil { 26 t.Skip("No android API platform found in $ANDROID_HOME, skipping bind") 27 } 28 platform = strings.Replace(platform, androidHome, "$ANDROID_HOME", -1) 29 30 defer func() { 31 xout = os.Stderr 32 buildN = false 33 buildX = false 34 buildO = "" 35 buildTarget = "" 36 bindJavaPkg = "" 37 }() 38 buildN = true 39 buildX = true 40 buildO = "asset.aar" 41 buildTarget = "android/arm" 42 43 tests := []struct { 44 javaPkg string 45 }{ 46 { 47 // Empty javaPkg 48 }, 49 { 50 javaPkg: "com.example.foo", 51 }, 52 } 53 for _, tc := range tests { 54 bindJavaPkg = tc.javaPkg 55 56 buf := new(bytes.Buffer) 57 xout = buf 58 gopath = filepath.SplitList(goEnv("GOPATH"))[0] 59 if goos == "windows" { 60 os.Setenv("HOMEDRIVE", "C:") 61 } 62 cmdBind.flag.Parse([]string{"github.com/cyrilou242/gomobile-java/asset"}) 63 err := runBind(cmdBind) 64 if err != nil { 65 t.Log(buf.String()) 66 t.Fatal(err) 67 } 68 got := filepath.ToSlash(buf.String()) 69 70 output, err := defaultOutputData("") 71 if err != nil { 72 t.Fatal(err) 73 } 74 data := struct { 75 outputData 76 AndroidPlatform string 77 JavaPkg string 78 }{ 79 outputData: output, 80 AndroidPlatform: platform, 81 JavaPkg: tc.javaPkg, 82 } 83 84 wantBuf := new(bytes.Buffer) 85 if err := bindAndroidTmpl.Execute(wantBuf, data); err != nil { 86 t.Errorf("%+v: computing diff failed: %v", tc, err) 87 continue 88 } 89 90 diff, err := diff(got, wantBuf.String()) 91 if err != nil { 92 t.Errorf("%+v: computing diff failed: %v", tc, err) 93 continue 94 } 95 if diff != "" { 96 t.Errorf("%+v: unexpected output:\n%s", tc, diff) 97 } 98 } 99 } 100 101 func TestBindApple(t *testing.T) { 102 if !xcodeAvailable() { 103 t.Skip("Xcode is missing") 104 } 105 defer func() { 106 xout = os.Stderr 107 buildN = false 108 buildX = false 109 buildO = "" 110 buildTarget = "" 111 bindPrefix = "" 112 }() 113 buildN = true 114 buildX = true 115 buildO = "Asset.xcframework" 116 buildTarget = "ios/arm64" 117 118 tests := []struct { 119 prefix string 120 out string 121 }{ 122 { 123 // empty prefix 124 }, 125 { 126 prefix: "Foo", 127 }, 128 { 129 out: "Abcde.xcframework", 130 }, 131 } 132 for _, tc := range tests { 133 bindPrefix = tc.prefix 134 if tc.out != "" { 135 buildO = tc.out 136 } 137 138 buf := new(bytes.Buffer) 139 xout = buf 140 gopath = filepath.SplitList(goEnv("GOPATH"))[0] 141 if goos == "windows" { 142 os.Setenv("HOMEDRIVE", "C:") 143 } 144 cmdBind.flag.Parse([]string{"github.com/cyrilou242/gomobile-java/asset"}) 145 if err := runBind(cmdBind); err != nil { 146 t.Log(buf.String()) 147 t.Fatal(err) 148 } 149 got := filepath.ToSlash(buf.String()) 150 151 output, err := defaultOutputData("") 152 if err != nil { 153 t.Fatal(err) 154 } 155 156 data := struct { 157 outputData 158 Output string 159 Prefix string 160 }{ 161 outputData: output, 162 Output: buildO[:len(buildO)-len(".xcframework")], 163 Prefix: tc.prefix, 164 } 165 166 wantBuf := new(bytes.Buffer) 167 if err := bindAppleTmpl.Execute(wantBuf, data); err != nil { 168 t.Errorf("%+v: computing diff failed: %v", tc, err) 169 continue 170 } 171 172 diff, err := diff(got, wantBuf.String()) 173 if err != nil { 174 t.Errorf("%+v: computing diff failed: %v", tc, err) 175 continue 176 } 177 if diff != "" { 178 t.Errorf("%+v: unexpected output:\n%s", tc, diff) 179 } 180 } 181 } 182 183 var bindAndroidTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile 184 WORK=$WORK 185 GOOS=android CGO_ENABLED=1 gobind -lang=go,java -outdir=$WORK{{if .JavaPkg}} -javapkg={{.JavaPkg}}{{end}} github.com/cyrilou242/gomobile-java/asset 186 mkdir -p $WORK/src 187 PWD=$WORK/src GOOS=android GOARCH=arm CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang++ CGO_ENABLED=1 GOARM=7 GOPATH=$WORK:$GOPATH go mod tidy 188 PWD=$WORK/src GOOS=android GOARCH=arm CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang++ CGO_ENABLED=1 GOARM=7 GOPATH=$WORK:$GOPATH go build -x -buildmode=c-shared -o=$WORK/android/src/main/jniLibs/armeabi-v7a/libgojni.so ./gobind 189 PWD=$WORK/java javac -d $WORK/javac-output -source 1.7 -target 1.7 -bootclasspath {{.AndroidPlatform}}/android.jar *.java 190 jar c -C $WORK/javac-output . 191 `)) 192 193 var bindAppleTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile 194 WORK=$WORK 195 rm -r -f "{{.Output}}.xcframework" 196 GOOS=ios CGO_ENABLED=1 gobind -lang=go,objc -outdir=$WORK/ios -tags=ios{{if .Prefix}} -prefix={{.Prefix}}{{end}} github.com/cyrilou242/gomobile-java/asset 197 mkdir -p $WORK/ios/src 198 PWD=$WORK/ios/src GOOS=ios GOARCH=arm64 GOFLAGS=-tags=ios CC=iphoneos-clang CXX=iphoneos-clang++ CGO_CFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_CXXFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_LDFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_ENABLED=1 DARWIN_SDK=iphoneos GOPATH=$WORK/ios:$GOPATH go mod tidy 199 PWD=$WORK/ios/src GOOS=ios GOARCH=arm64 GOFLAGS=-tags=ios CC=iphoneos-clang CXX=iphoneos-clang++ CGO_CFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_CXXFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_LDFLAGS=-isysroot iphoneos -miphoneos-version-min=13.0 -fembed-bitcode -arch arm64 CGO_ENABLED=1 DARWIN_SDK=iphoneos GOPATH=$WORK/ios:$GOPATH go build -x -buildmode=c-archive -o $WORK/{{.Output}}-ios-arm64.a ./gobind 200 mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers 201 ln -s A $WORK/ios/iphoneos/{{.Output}}.framework/Versions/Current 202 ln -s Versions/Current/Headers $WORK/ios/iphoneos/{{.Output}}.framework/Headers 203 ln -s Versions/Current/{{.Output}} $WORK/ios/iphoneos/{{.Output}}.framework/{{.Output}} 204 xcrun lipo $WORK/{{.Output}}-ios-arm64.a -create -o $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/{{.Output}} 205 cp $WORK/ios/src/gobind/{{.Prefix}}Asset.objc.h $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers/{{.Prefix}}Asset.objc.h 206 mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers 207 cp $WORK/ios/src/gobind/Universe.objc.h $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers/Universe.objc.h 208 mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers 209 cp $WORK/ios/src/gobind/ref.h $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers/ref.h 210 mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers 211 mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Headers 212 mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Resources 213 ln -s Versions/Current/Resources $WORK/ios/iphoneos/{{.Output}}.framework/Resources 214 mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Resources 215 mkdir -p $WORK/ios/iphoneos/{{.Output}}.framework/Versions/A/Modules 216 ln -s Versions/Current/Modules $WORK/ios/iphoneos/{{.Output}}.framework/Modules 217 xcodebuild -create-xcframework -framework $WORK/ios/iphoneos/{{.Output}}.framework -output {{.Output}}.xcframework 218 `)) 219 220 func TestBindAppleAll(t *testing.T) { 221 if !xcodeAvailable() { 222 t.Skip("Xcode is missing") 223 } 224 defer func() { 225 xout = os.Stderr 226 buildN = false 227 buildX = false 228 buildO = "" 229 buildTarget = "" 230 bindPrefix = "" 231 }() 232 buildN = true 233 buildX = true 234 buildO = "Asset.xcframework" 235 buildTarget = "ios" 236 237 buf := new(bytes.Buffer) 238 xout = buf 239 gopath = filepath.SplitList(goEnv("GOPATH"))[0] 240 if goos == "windows" { 241 os.Setenv("HOMEDRIVE", "C:") 242 } 243 cmdBind.flag.Parse([]string{"github.com/cyrilou242/gomobile-java/asset"}) 244 if err := runBind(cmdBind); err != nil { 245 t.Log(buf.String()) 246 t.Fatal(err) 247 } 248 } 249 250 func TestBindWithGoModules(t *testing.T) { 251 if runtime.GOOS == "android" || runtime.GOOS == "ios" { 252 t.Skipf("gomobile and gobind are not available on %s", runtime.GOOS) 253 } 254 255 dir, err := ioutil.TempDir("", "gomobile-test") 256 if err != nil { 257 t.Fatal(err) 258 } 259 defer os.RemoveAll(dir) 260 261 if out, err := exec.Command("go", "build", "-o="+dir, "github.com/cyrilou242/gomobile-java/cmd/gobind").CombinedOutput(); err != nil { 262 t.Fatalf("%v: %s", err, string(out)) 263 } 264 if out, err := exec.Command("go", "build", "-o="+dir, "github.com/cyrilou242/gomobile-java/cmd/gomobile").CombinedOutput(); err != nil { 265 t.Fatalf("%v: %s", err, string(out)) 266 } 267 path := dir 268 if p := os.Getenv("PATH"); p != "" { 269 path += string(filepath.ListSeparator) + p 270 } 271 272 for _, target := range []string{"android", "ios"} { 273 t.Run(target, func(t *testing.T) { 274 switch target { 275 case "android": 276 androidHome := os.Getenv("ANDROID_HOME") 277 if androidHome == "" { 278 t.Skip("ANDROID_HOME not found, skipping bind") 279 } 280 if _, err := androidAPIPath(); err != nil { 281 t.Skip("No android API platform found in $ANDROID_HOME, skipping bind") 282 } 283 case "ios": 284 if !xcodeAvailable() { 285 t.Skip("Xcode is missing") 286 } 287 } 288 289 var out string 290 switch target { 291 case "android": 292 out = filepath.Join(dir, "cgopkg.aar") 293 case "ios": 294 out = filepath.Join(dir, "Cgopkg.xcframework") 295 } 296 297 tests := []struct { 298 Name string 299 Path string 300 Dir string 301 }{ 302 { 303 Name: "Absolute Path", 304 Path: "github.com/cyrilou242/gomobile-java/bind/testdata/cgopkg", 305 }, 306 { 307 Name: "Relative Path", 308 Path: "./bind/testdata/cgopkg", 309 Dir: filepath.Join("..", ".."), 310 }, 311 } 312 313 for _, tc := range tests { 314 tc := tc 315 t.Run(tc.Name, func(t *testing.T) { 316 cmd := exec.Command(filepath.Join(dir, "gomobile"), "bind", "-target="+target, "-o="+out, tc.Path) 317 cmd.Env = append(os.Environ(), "PATH="+path, "GO111MODULE=on") 318 cmd.Dir = tc.Dir 319 if out, err := cmd.CombinedOutput(); err != nil { 320 t.Errorf("gomobile bind failed: %v\n%s", err, string(out)) 321 } 322 }) 323 } 324 }) 325 } 326 }