github.com/mixinnetwork/mobile@v0.0.0-20231204065441-5f786fcd11c7/cmd/gobind/gobind_test.go (about)

     1  // Copyright 2016 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  	"fmt"
    10  	"os"
    11  	"os/exec"
    12  	"runtime"
    13  	"strings"
    14  	"testing"
    15  
    16  	"golang.org/x/tools/go/packages/packagestest"
    17  )
    18  
    19  func TestMain(m *testing.M) {
    20  	// To avoid recompiling the gobind command (and to support compiler options
    21  	// like -race and -coverage), allow the test binary itself to re-exec itself
    22  	// as the gobind command by setting an environment variable.
    23  	if os.Getenv("GOBIND_TEST_IS_GOBIND") != "" {
    24  		main()
    25  		os.Exit(0)
    26  	}
    27  	os.Setenv("GOBIND_TEST_IS_GOBIND", "1")
    28  
    29  	os.Exit(m.Run())
    30  }
    31  
    32  var tests = []struct {
    33  	name string
    34  	lang string
    35  	pkg  string
    36  	goos string
    37  	// reverse is true if the test needs to generate reverse bindings using
    38  	// external tools such as javap.
    39  	reverse bool
    40  }{
    41  	{
    42  		name: "ObjC-Testpkg",
    43  		lang: "objc",
    44  		pkg:  "github.com/mixinnetwork/mobile/bind/testdata/testpkg",
    45  	},
    46  	{
    47  		name: "Java-Testpkg",
    48  		lang: "java",
    49  		pkg:  "github.com/mixinnetwork/mobile/bind/testdata/testpkg",
    50  	},
    51  	{
    52  		name: "Go-Testpkg",
    53  		lang: "go",
    54  		pkg:  "github.com/mixinnetwork/mobile/bind/testdata/testpkg",
    55  	},
    56  	{
    57  		name:    "Java-Javapkg",
    58  		lang:    "java",
    59  		pkg:     "github.com/mixinnetwork/mobile/bind/testdata/testpkg/javapkg",
    60  		goos:    "android",
    61  		reverse: true,
    62  	},
    63  	{
    64  		name:    "Go-Javapkg",
    65  		lang:    "go",
    66  		pkg:     "github.com/mixinnetwork/mobile/bind/testdata/testpkg/javapkg",
    67  		goos:    "android",
    68  		reverse: true,
    69  	},
    70  	{
    71  		name: "Go-Cgopkg",
    72  		lang: "go,java,objc",
    73  		pkg:  "github.com/mixinnetwork/mobile/bind/testdata/cgopkg",
    74  		goos: "android",
    75  	},
    76  }
    77  
    78  func mustHaveBindTestdata(t testing.TB) {
    79  	switch runtime.GOOS {
    80  	case "android", "ios":
    81  		t.Skipf("skipping: test cannot access ../../bind/testdata on %s/%s", runtime.GOOS, runtime.GOARCH)
    82  	}
    83  }
    84  
    85  func gobindBin(t testing.TB) string {
    86  	switch runtime.GOOS {
    87  	case "js", "ios":
    88  		t.Skipf("skipping: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH)
    89  	}
    90  
    91  	p, err := os.Executable()
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  	return p
    96  }
    97  
    98  func runGobind(t testing.TB, lang, pkg, goos string, exported *packagestest.Exported) error {
    99  	cmd := exec.Command(gobindBin(t), "-lang", lang, pkg)
   100  	cmd.Dir = exported.Config.Dir
   101  	cmd.Env = exported.Config.Env
   102  	if goos != "" {
   103  		// Add CGO_ENABLED=1 explicitly since Cgo is disabled when GOOS is different from host OS.
   104  		cmd.Env = append(cmd.Env, "GOOS="+goos, "CGO_ENABLED=1")
   105  	}
   106  	stderr := new(strings.Builder)
   107  	cmd.Stderr = stderr
   108  	stdout := new(strings.Builder)
   109  	cmd.Stdout = stdout
   110  	err := cmd.Run()
   111  	if testing.Verbose() && stdout.Len() > 0 {
   112  		t.Logf("stdout (%v):\n%s", cmd, stderr)
   113  	}
   114  	if stderr.Len() > 0 {
   115  		t.Logf("stderr (%v):\n%s", cmd, stderr)
   116  	}
   117  	if err != nil {
   118  		return fmt.Errorf("%v: %w", cmd, err)
   119  	}
   120  	return nil
   121  }
   122  
   123  func TestGobind(t *testing.T) { packagestest.TestAll(t, testGobind) }
   124  func testGobind(t *testing.T, exporter packagestest.Exporter) {
   125  	mustHaveBindTestdata(t)
   126  
   127  	_, javapErr := exec.LookPath("javap")
   128  	exported := packagestest.Export(t, exporter, []packagestest.Module{{
   129  		Name:  "github.com/mixinnetwork/mobile",
   130  		Files: packagestest.MustCopyFileTree("../.."),
   131  	}})
   132  	defer exported.Cleanup()
   133  
   134  	for _, test := range tests {
   135  		t.Run(test.name, func(t *testing.T) {
   136  			if exporter == packagestest.Modules && test.reverse {
   137  				t.Skip("reverse binding does't work with Go modules")
   138  			}
   139  			if test.reverse && javapErr != nil {
   140  				t.Skip("reverse bind test requires javap which is not available")
   141  			}
   142  			if err := runGobind(t, test.lang, test.pkg, test.goos, exported); err != nil {
   143  				t.Error(err)
   144  			}
   145  		})
   146  	}
   147  }
   148  
   149  func TestDocs(t *testing.T) { packagestest.TestAll(t, testDocs) }
   150  func testDocs(t *testing.T, exporter packagestest.Exporter) {
   151  	mustHaveBindTestdata(t)
   152  
   153  	const docsrc = `
   154  package doctest
   155  
   156  // This is a comment.
   157  type Struct struct{
   158  }`
   159  
   160  	exported := packagestest.Export(t, exporter, []packagestest.Module{
   161  		{
   162  			Name: "example.com/doctest",
   163  			Files: map[string]interface{}{
   164  				"doc.go": docsrc,
   165  			},
   166  		},
   167  		{
   168  			// gobind requires golang.org/x/mobile to generate code for reverse bindings.
   169  			Name:  "github.com/mixinnetwork/mobile",
   170  			Files: packagestest.MustCopyFileTree("../.."),
   171  		},
   172  	})
   173  	defer exported.Cleanup()
   174  
   175  	const comment = "This is a comment."
   176  	for _, lang := range []string{"java", "objc"} {
   177  		cmd := exec.Command(gobindBin(t), "-lang", lang, "example.com/doctest")
   178  		cmd.Dir = exported.Config.Dir
   179  		cmd.Env = exported.Config.Env
   180  		out, err := cmd.CombinedOutput()
   181  		if err != nil {
   182  			t.Errorf("gobind -lang %s failed: %v: %s", lang, err, out)
   183  			continue
   184  		}
   185  		if bytes.Index(out, []byte(comment)) == -1 {
   186  			t.Errorf("gobind output for language %s did not contain the comment %q", lang, comment)
   187  		}
   188  	}
   189  }
   190  
   191  func BenchmarkGobind(b *testing.B) {
   192  	packagestest.BenchmarkAll(b, benchmarkGobind)
   193  }
   194  
   195  func benchmarkGobind(b *testing.B, exporter packagestest.Exporter) {
   196  	_, javapErr := exec.LookPath("javap")
   197  	exported := packagestest.Export(b, exporter, []packagestest.Module{{
   198  		Name:  "github.com/mixinnetwork/mobile",
   199  		Files: packagestest.MustCopyFileTree("../.."),
   200  	}})
   201  	defer exported.Cleanup()
   202  
   203  	for _, test := range tests {
   204  		b.Run(test.name, func(b *testing.B) {
   205  			if exporter == packagestest.Modules && test.reverse {
   206  				b.Skip("reverse binding does't work with Go modules")
   207  			}
   208  			if test.reverse && javapErr != nil {
   209  				b.Skip("reverse bind test requires javap which is not available")
   210  			}
   211  			for i := 0; i < b.N; i++ {
   212  				if err := runGobind(b, test.lang, test.pkg, test.goos, exported); err != nil {
   213  					b.Error(err)
   214  				}
   215  			}
   216  		})
   217  	}
   218  }