...

Source file src/cmd/cgo/internal/swig/swig_test.go

Documentation: cmd/cgo/internal/swig

     1  // Copyright 2023 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 swig
     6  
     7  import (
     8  	"cmd/internal/quoted"
     9  	"internal/testenv"
    10  	"os"
    11  	"os/exec"
    12  	"path/filepath"
    13  	"regexp"
    14  	"strconv"
    15  	"strings"
    16  	"sync"
    17  	"testing"
    18  )
    19  
    20  func TestStdio(t *testing.T) {
    21  	testenv.MustHaveCGO(t)
    22  	mustHaveSwig(t)
    23  	run(t, "testdata/stdio", false)
    24  }
    25  
    26  func TestCall(t *testing.T) {
    27  	testenv.MustHaveCGO(t)
    28  	mustHaveSwig(t)
    29  	mustHaveCxx(t)
    30  	run(t, "testdata/callback", false, "Call")
    31  	t.Run("lto", func(t *testing.T) { run(t, "testdata/callback", true, "Call") })
    32  }
    33  
    34  func TestCallback(t *testing.T) {
    35  	testenv.MustHaveCGO(t)
    36  	mustHaveSwig(t)
    37  	mustHaveCxx(t)
    38  	run(t, "testdata/callback", false, "Callback")
    39  	t.Run("lto", func(t *testing.T) { run(t, "testdata/callback", true, "Callback") })
    40  }
    41  
    42  func run(t *testing.T, dir string, lto bool, args ...string) {
    43  	runArgs := append([]string{"run", "."}, args...)
    44  	cmd := exec.Command("go", runArgs...)
    45  	cmd.Dir = dir
    46  	if lto {
    47  		const cflags = "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option"
    48  		cmd.Env = append(cmd.Environ(),
    49  			"CGO_CFLAGS="+cflags,
    50  			"CGO_CXXFLAGS="+cflags,
    51  			"CGO_LDFLAGS="+cflags)
    52  	}
    53  	out, err := cmd.CombinedOutput()
    54  	if string(out) != "OK\n" {
    55  		t.Errorf("%s", string(out))
    56  	}
    57  	if err != nil {
    58  		t.Errorf("%s", err)
    59  	}
    60  }
    61  
    62  func mustHaveCxx(t *testing.T) {
    63  	// Ask the go tool for the CXX it's configured to use.
    64  	cxx, err := exec.Command("go", "env", "CXX").CombinedOutput()
    65  	if err != nil {
    66  		t.Fatalf("go env CXX failed: %s", err)
    67  	}
    68  	args, err := quoted.Split(string(cxx))
    69  	if err != nil {
    70  		t.Skipf("could not parse 'go env CXX' output %q: %s", string(cxx), err)
    71  	}
    72  	if len(args) == 0 {
    73  		t.Skip("no C++ compiler")
    74  	}
    75  	testenv.MustHaveExecPath(t, string(args[0]))
    76  }
    77  
    78  var (
    79  	swigOnce sync.Once
    80  	haveSwig bool
    81  )
    82  
    83  func mustHaveSwig(t *testing.T) {
    84  	swigOnce.Do(func() {
    85  		mustHaveSwigOnce(t)
    86  		haveSwig = true
    87  	})
    88  	// The first call will skip t with a nice message. On later calls, we just skip.
    89  	if !haveSwig {
    90  		t.Skip("swig not found")
    91  	}
    92  }
    93  
    94  func mustHaveSwigOnce(t *testing.T) {
    95  	swig, err := exec.LookPath("swig")
    96  	if err != nil {
    97  		t.Skipf("swig not in PATH: %s", err)
    98  	}
    99  
   100  	// Check that swig was installed with Go support by checking
   101  	// that a go directory exists inside the swiglib directory.
   102  	// See https://golang.org/issue/23469.
   103  	output, err := exec.Command(swig, "-go", "-swiglib").Output()
   104  	if err != nil {
   105  		t.Skip("swig is missing Go support")
   106  	}
   107  	swigDir := strings.TrimSpace(string(output))
   108  
   109  	_, err = os.Stat(filepath.Join(swigDir, "go"))
   110  	if err != nil {
   111  		t.Skip("swig is missing Go support")
   112  	}
   113  
   114  	// Check that swig has a new enough version.
   115  	// See https://golang.org/issue/22858.
   116  	out, err := exec.Command(swig, "-version").CombinedOutput()
   117  	if err != nil {
   118  		t.Skipf("failed to get swig version:%s\n%s", err, string(out))
   119  	}
   120  
   121  	re := regexp.MustCompile(`[vV]ersion +(\d+)([.]\d+)?([.]\d+)?`)
   122  	matches := re.FindSubmatch(out)
   123  	if matches == nil {
   124  		// Can't find version number; hope for the best.
   125  		t.Logf("failed to find swig version, continuing")
   126  		return
   127  	}
   128  
   129  	var parseError error
   130  	atoi := func(s string) int {
   131  		x, err := strconv.Atoi(s)
   132  		if err != nil && parseError == nil {
   133  			parseError = err
   134  		}
   135  		return x
   136  	}
   137  	var major, minor, patch int
   138  	major = atoi(string(matches[1]))
   139  	if len(matches[2]) > 0 {
   140  		minor = atoi(string(matches[2][1:]))
   141  	}
   142  	if len(matches[3]) > 0 {
   143  		patch = atoi(string(matches[3][1:]))
   144  	}
   145  	if parseError != nil {
   146  		t.Logf("error parsing swig version %q, continuing anyway: %s", string(matches[0]), parseError)
   147  		return
   148  	}
   149  	t.Logf("found swig version %d.%d.%d", major, minor, patch)
   150  	if major < 3 || (major == 3 && minor == 0 && patch < 6) {
   151  		t.Skip("test requires swig 3.0.6 or later")
   152  	}
   153  }
   154  

View as plain text