Home | History | Annotate | Download | only in gccgoimporter
      1 // Copyright 2013 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 gccgoimporter
      6 
      7 import (
      8 	"go/types"
      9 	"internal/testenv"
     10 	"io/ioutil"
     11 	"os"
     12 	"os/exec"
     13 	"path/filepath"
     14 	"runtime"
     15 	"testing"
     16 )
     17 
     18 type importerTest struct {
     19 	pkgpath, name, want, wantval string
     20 	wantinits                    []string
     21 }
     22 
     23 func runImporterTest(t *testing.T, imp Importer, initmap map[*types.Package]InitData, test *importerTest) {
     24 	pkg, err := imp(make(map[string]*types.Package), test.pkgpath)
     25 	if err != nil {
     26 		t.Error(err)
     27 		return
     28 	}
     29 
     30 	if test.name != "" {
     31 		obj := pkg.Scope().Lookup(test.name)
     32 		if obj == nil {
     33 			t.Errorf("%s: object not found", test.name)
     34 			return
     35 		}
     36 
     37 		got := types.ObjectString(obj, types.RelativeTo(pkg))
     38 		if got != test.want {
     39 			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
     40 		}
     41 
     42 		if test.wantval != "" {
     43 			gotval := obj.(*types.Const).Val().String()
     44 			if gotval != test.wantval {
     45 				t.Errorf("%s: got val %q; want val %q", test.name, gotval, test.wantval)
     46 			}
     47 		}
     48 	}
     49 
     50 	if len(test.wantinits) > 0 {
     51 		initdata := initmap[pkg]
     52 		found := false
     53 		// Check that the package's own init function has the package's priority
     54 		for _, pkginit := range initdata.Inits {
     55 			if pkginit.InitFunc == test.wantinits[0] {
     56 				if initdata.Priority != pkginit.Priority {
     57 					t.Errorf("%s: got self priority %d; want %d", test.pkgpath, pkginit.Priority, initdata.Priority)
     58 				}
     59 				found = true
     60 				break
     61 			}
     62 		}
     63 
     64 		if !found {
     65 			t.Errorf("%s: could not find expected function %q", test.pkgpath, test.wantinits[0])
     66 		}
     67 
     68 		// Each init function in the list other than the first one is a
     69 		// dependency of the function immediately before it. Check that
     70 		// the init functions appear in descending priority order.
     71 		priority := initdata.Priority
     72 		for _, wantdepinit := range test.wantinits[1:] {
     73 			found = false
     74 			for _, pkginit := range initdata.Inits {
     75 				if pkginit.InitFunc == wantdepinit {
     76 					if priority <= pkginit.Priority {
     77 						t.Errorf("%s: got dep priority %d; want less than %d", test.pkgpath, pkginit.Priority, priority)
     78 					}
     79 					found = true
     80 					priority = pkginit.Priority
     81 					break
     82 				}
     83 			}
     84 
     85 			if !found {
     86 				t.Errorf("%s: could not find expected function %q", test.pkgpath, wantdepinit)
     87 			}
     88 		}
     89 	}
     90 }
     91 
     92 var importerTests = [...]importerTest{
     93 	{pkgpath: "pointer", name: "Int8Ptr", want: "type Int8Ptr *int8"},
     94 	{pkgpath: "complexnums", name: "NN", want: "const NN untyped complex", wantval: "(-1/1 + -1/1i)"},
     95 	{pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1/1 + 1/1i)"},
     96 	{pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1/1 + -1/1i)"},
     97 	{pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1/1 + 1/1i)"},
     98 	// TODO: enable this entry once bug has been tracked down
     99 	//{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
    100 }
    101 
    102 func TestGoxImporter(t *testing.T) {
    103 	testenv.MustHaveGoBuild(t)
    104 
    105 	initmap := make(map[*types.Package]InitData)
    106 	imp := GetImporter([]string{"testdata"}, initmap)
    107 
    108 	for _, test := range importerTests {
    109 		runImporterTest(t, imp, initmap, &test)
    110 	}
    111 }
    112 
    113 func TestObjImporter(t *testing.T) {
    114 	testenv.MustHaveGoBuild(t)
    115 
    116 	// This test relies on gccgo being around, which it most likely will be if we
    117 	// were compiled with gccgo.
    118 	if runtime.Compiler != "gccgo" {
    119 		t.Skip("This test needs gccgo")
    120 		return
    121 	}
    122 
    123 	tmpdir, err := ioutil.TempDir("", "")
    124 	if err != nil {
    125 		t.Fatal(err)
    126 	}
    127 	initmap := make(map[*types.Package]InitData)
    128 	imp := GetImporter([]string{tmpdir}, initmap)
    129 
    130 	artmpdir, err := ioutil.TempDir("", "")
    131 	if err != nil {
    132 		t.Fatal(err)
    133 	}
    134 	arinitmap := make(map[*types.Package]InitData)
    135 	arimp := GetImporter([]string{artmpdir}, arinitmap)
    136 
    137 	for _, test := range importerTests {
    138 		gofile := filepath.Join("testdata", test.pkgpath+".go")
    139 		ofile := filepath.Join(tmpdir, test.pkgpath+".o")
    140 		afile := filepath.Join(artmpdir, "lib"+test.pkgpath+".a")
    141 
    142 		cmd := exec.Command("gccgo", "-fgo-pkgpath="+test.pkgpath, "-c", "-o", ofile, gofile)
    143 		out, err := cmd.CombinedOutput()
    144 		if err != nil {
    145 			t.Logf("%s", out)
    146 			t.Fatalf("gccgo %s failed: %s", gofile, err)
    147 		}
    148 
    149 		runImporterTest(t, imp, initmap, &test)
    150 
    151 		cmd = exec.Command("ar", "cr", afile, ofile)
    152 		out, err = cmd.CombinedOutput()
    153 		if err != nil {
    154 			t.Logf("%s", out)
    155 			t.Fatalf("ar cr %s %s failed: %s", afile, ofile, err)
    156 		}
    157 
    158 		runImporterTest(t, arimp, arinitmap, &test)
    159 
    160 		if err = os.Remove(ofile); err != nil {
    161 			t.Fatal(err)
    162 		}
    163 		if err = os.Remove(afile); err != nil {
    164 			t.Fatal(err)
    165 		}
    166 	}
    167 
    168 	if err = os.Remove(tmpdir); err != nil {
    169 		t.Fatal(err)
    170 	}
    171 }
    172