gitlab.com/cznic/ccgo@v1.0.0/all_test.go (about)

     1  // Copyright 2017 The CCGO 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 ccgo // import "modernc.org/ccgo"
     6  
     7  import (
     8  	"bytes"
     9  	"flag"
    10  	"fmt"
    11  	"go/format"
    12  	"go/scanner"
    13  	"go/token"
    14  	"io/ioutil"
    15  	"os"
    16  	"os/exec"
    17  	"path"
    18  	"path/filepath"
    19  	"regexp"
    20  	"runtime"
    21  	"runtime/debug"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"modernc.org/cc"
    27  	"modernc.org/ccir"
    28  	"modernc.org/internal/buffer"
    29  	"modernc.org/ir"
    30  	"modernc.org/irgo"
    31  	"modernc.org/strutil"
    32  	"modernc.org/xc"
    33  )
    34  
    35  func caller(s string, va ...interface{}) {
    36  	if s == "" {
    37  		s = strings.Repeat("%v ", len(va))
    38  	}
    39  	_, fn, fl, _ := runtime.Caller(2)
    40  	fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl)
    41  	fmt.Fprintf(os.Stderr, s, va...)
    42  	fmt.Fprintln(os.Stderr)
    43  	_, fn, fl, _ = runtime.Caller(1)
    44  	fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl)
    45  	fmt.Fprintln(os.Stderr)
    46  	os.Stderr.Sync()
    47  }
    48  
    49  func dbg(s string, va ...interface{}) {
    50  	if s == "" {
    51  		s = strings.Repeat("%v ", len(va))
    52  	}
    53  	_, fn, fl, _ := runtime.Caller(1)
    54  	fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl)
    55  	fmt.Fprintf(os.Stderr, s, va...)
    56  	fmt.Fprintln(os.Stderr)
    57  	os.Stderr.Sync()
    58  }
    59  
    60  func use(...interface{}) {}
    61  
    62  func init() {
    63  	use(caller, dbg, TODO) //TODOOK
    64  	flag.BoolVar(&Testing, "testing", false, "")
    65  	flag.BoolVar(&ir.Testing, "irTesting", false, "")
    66  	flag.BoolVar(&irgo.FTrace, "irgoFTrace", false, "")
    67  	flag.BoolVar(&irgo.Testing, "irgoTesting", false, "")
    68  }
    69  
    70  // ============================================================================
    71  
    72  const (
    73  	crtQ     = "crt"
    74  	prologue = `// Code generated by ccgo DO NOT EDIT.
    75  
    76  package main
    77  
    78  import (
    79  	"fmt"
    80  	"math"
    81  	"os"
    82  	"path"
    83  	"runtime"
    84  	"unsafe"
    85  
    86  	"modernc.org/ccgo/crt"
    87  )
    88  
    89  var argv []*int8
    90  
    91  func ftrace(s string, args ...interface{}) {
    92  	_, fn, fl, _ := runtime.Caller(1)
    93  	fmt.Fprintf(os.Stderr, "# %%s:%%d: %%v\n", path.Base(fn), fl, fmt.Sprintf(s, args...))
    94  	os.Stderr.Sync()
    95  }
    96  
    97  func main() {
    98  	os.Args[0] = "./test"
    99  	for _, v := range os.Args {
   100  		argv = append(argv, (*int8)(crt.CString(v)))
   101  	}
   102  	argv = append(argv, nil)
   103  	X_start(%s.NewTLS(), int32(len(os.Args)), &argv[0])
   104  }
   105  
   106  %s`
   107  )
   108  
   109  var (
   110  	ccTestdata string
   111  
   112  	cpp      = flag.Bool("cpp", false, "")
   113  	errLimit = flag.Int("errlimit", 10, "")
   114  	filter   = flag.String("re", "", "")
   115  	ndebug   = flag.Bool("ndebug", false, "")
   116  	noexec   = flag.Bool("noexec", false, "")
   117  	oLog     = flag.Bool("log", false, "")
   118  	trace    = flag.Bool("trc", false, "")
   119  	yydebug  = flag.Int("yydebug", 0, "")
   120  )
   121  
   122  func init() {
   123  	ip, err := cc.ImportPath()
   124  	if err != nil {
   125  		panic(err)
   126  	}
   127  
   128  	for _, v := range filepath.SplitList(strutil.Gopath()) {
   129  		p := filepath.Join(v, "src", ip, "testdata")
   130  		fi, err := os.Stat(p)
   131  		if err != nil {
   132  			continue
   133  		}
   134  
   135  		if fi.IsDir() {
   136  			ccTestdata = p
   137  			break
   138  		}
   139  	}
   140  	if ccTestdata == "" {
   141  		panic("cannot find cc/testdata/")
   142  	}
   143  }
   144  
   145  func errStr(err error) string {
   146  	switch x := err.(type) {
   147  	case scanner.ErrorList:
   148  		if len(x) != 1 {
   149  			x.RemoveMultiples()
   150  		}
   151  		var b bytes.Buffer
   152  		for i, v := range x {
   153  			if i != 0 {
   154  				b.WriteByte('\n')
   155  			}
   156  			b.WriteString(v.Error())
   157  			if i == 9 {
   158  				fmt.Fprintf(&b, "\n\t... and %v more errors", len(x)-10)
   159  				break
   160  			}
   161  		}
   162  		return b.String()
   163  	default:
   164  		return err.Error()
   165  	}
   166  }
   167  
   168  func parse(src []string, opts ...cc.Opt) (_ *cc.TranslationUnit, err error) {
   169  	defer func() {
   170  		if e := recover(); e != nil && err == nil {
   171  			err = fmt.Errorf("cc.Parse: PANIC: %v\n%s", e, debug.Stack())
   172  		}
   173  	}()
   174  
   175  	model, err := ccir.NewModel()
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  
   180  	var ndbg string
   181  	if *ndebug {
   182  		ndbg = "#define NDEBUG 1"
   183  	}
   184  	ast, err := cc.Parse(fmt.Sprintf(`
   185  %s
   186  #define _CCGO 1
   187  #define __arch__ %s
   188  #define __os__ %s
   189  #include <builtin.h>
   190  
   191  #define NO_TRAMPOLINES 1
   192  `, ndbg, runtime.GOARCH, runtime.GOOS),
   193  		src,
   194  		model,
   195  		opts...,
   196  	)
   197  	if err != nil {
   198  		return nil, fmt.Errorf("cc.Parse: %v", errStr(err))
   199  	}
   200  
   201  	return ast, nil
   202  }
   203  
   204  func expect1(wd, match string, hook func(string, string) []string, ccgoOpts []Option, opts ...cc.Opt) (log buffer.Bytes, exitStatus int, err error) {
   205  	var lpos token.Position
   206  	if *cpp {
   207  		opts = append(opts, cc.Cpp(func(toks []xc.Token) {
   208  			if len(toks) != 0 {
   209  				p := toks[0].Position()
   210  				if p.Filename != lpos.Filename {
   211  					fmt.Fprintf(&log, "# %d %q\n", p.Line, p.Filename)
   212  				}
   213  				lpos = p
   214  			}
   215  			for _, v := range toks {
   216  				log.WriteString(cc.TokSrc(v))
   217  			}
   218  			log.WriteByte('\n')
   219  		}))
   220  	}
   221  	if n := *yydebug; n != -1 {
   222  		opts = append(opts, cc.YyDebug(n))
   223  	}
   224  	ast, err := parse([]string{ccir.CRT0Path, match}, opts...)
   225  	if err != nil {
   226  		return log, -1, err
   227  	}
   228  
   229  	var out, src buffer.Bytes
   230  
   231  	defer func() {
   232  		out.Close()
   233  		src.Close()
   234  	}()
   235  
   236  	if err := New([]*cc.TranslationUnit{ast}, &out, ccgoOpts...); err != nil {
   237  		return log, -1, fmt.Errorf("New: %v", err)
   238  	}
   239  
   240  	fmt.Fprintf(&src, prologue, crtQ, out.Bytes())
   241  	b, err := format.Source(src.Bytes())
   242  	if err != nil {
   243  		b = src.Bytes()
   244  	}
   245  	fmt.Fprintf(&log, "# ccgo.New\n%s", b)
   246  	if err != nil {
   247  		return log, exitStatus, err
   248  	}
   249  
   250  	if *noexec {
   251  		return log, 0, nil
   252  	}
   253  
   254  	var stdout, stderr buffer.Bytes
   255  
   256  	defer func() {
   257  		stdout.Close()
   258  		stderr.Close()
   259  	}()
   260  
   261  	if err := func() (err error) {
   262  		defer func() {
   263  			if e := recover(); e != nil && err == nil {
   264  				err = fmt.Errorf("exec: PANIC: %v", e)
   265  			}
   266  		}()
   267  
   268  		vwd, err := ioutil.TempDir("", "ccgo-test-")
   269  		if err != nil {
   270  			return err
   271  		}
   272  
   273  		if err := os.Chdir(vwd); err != nil {
   274  			return err
   275  		}
   276  
   277  		defer func() {
   278  			os.Chdir(wd)
   279  			os.RemoveAll(vwd)
   280  		}()
   281  
   282  		if err := ioutil.WriteFile("main.go", b, 0664); err != nil {
   283  			return err
   284  		}
   285  
   286  		args := hook(vwd, match)
   287  		cmd := exec.Command("go", append([]string{"run", "main.go"}, args[1:]...)...)
   288  		cmd.Stdout = &stdout
   289  		cmd.Stderr = &stderr
   290  		if err := cmd.Run(); err != nil {
   291  			if b := stdout.Bytes(); b != nil {
   292  				fmt.Fprintf(&log, "stdout:\n%s\n", b)
   293  			}
   294  			if b := stderr.Bytes(); b != nil {
   295  				fmt.Fprintf(&log, "stderr:\n%s\n", b)
   296  			}
   297  			return fmt.Errorf("go run: exit status %v, err %v", exitStatus, err)
   298  		}
   299  
   300  		return nil
   301  	}(); err != nil {
   302  		return log, 1, err
   303  	}
   304  
   305  	if b := stdout.Bytes(); b != nil {
   306  		fmt.Fprintf(&log, "stdout:\n%s\n", b)
   307  	}
   308  	if b := stderr.Bytes(); b != nil {
   309  		fmt.Fprintf(&log, "stderr:\n%s\n", b)
   310  	}
   311  
   312  	expect := match[:len(match)-len(filepath.Ext(match))] + ".expect"
   313  	if _, err := os.Stat(expect); err != nil {
   314  		if !os.IsNotExist(err) {
   315  			return log, 0, err
   316  		}
   317  
   318  		return log, 0, nil
   319  	}
   320  
   321  	buf, err := ioutil.ReadFile(expect)
   322  	if err != nil {
   323  		return log, 0, err
   324  	}
   325  
   326  	if g, e := stdout.Bytes(), buf; !bytes.Equal(g, e) {
   327  		return log, 0, fmt.Errorf("==== %v\n==== got\n%s==== exp\n%s", match, g, e)
   328  	}
   329  	return log, 0, nil
   330  }
   331  
   332  func expect(t *testing.T, dir string, skip func(string) bool, hook func(string, string) []string, ccgoOpts []Option, opts ...cc.Opt) {
   333  	wd, err := os.Getwd()
   334  	if err != nil {
   335  		t.Fatal(err)
   336  	}
   337  
   338  	matches, err := filepath.Glob(filepath.Join(dir, "*.c"))
   339  	if err != nil {
   340  		t.Fatal(err)
   341  	}
   342  
   343  	seq := 0
   344  	okSeq := 0
   345  	for _, match := range matches {
   346  		if skip(match) {
   347  			continue
   348  		}
   349  
   350  		if *trace {
   351  			fmt.Println(match)
   352  		}
   353  		seq++
   354  		doLog := *oLog
   355  		b, err := ioutil.ReadFile(match)
   356  		if err != nil {
   357  			t.Fatal(err)
   358  		}
   359  
   360  		co := ccgoOpts
   361  		co = co[:len(co):len(co)]
   362  		if bytes.Contains(b, []byte("#include")) {
   363  			co = append(co, LibcTypes())
   364  		}
   365  		log, exitStatus, err := expect1(wd, match, hook, co, opts...)
   366  		switch {
   367  		case exitStatus <= 0 && err == nil:
   368  			okSeq++
   369  		default:
   370  			if seq-okSeq == 1 {
   371  				t.Logf("%s: FAIL\n%s\n%s", match, errStr(err), log.Bytes())
   372  				doLog = false
   373  			}
   374  		}
   375  		if doLog {
   376  			t.Logf("%s:\n%s", match, log.Bytes())
   377  		}
   378  		log.Close()
   379  	}
   380  	t.Logf("%v/%v ok", okSeq, seq)
   381  	if okSeq != seq {
   382  		t.Errorf("failures: %v", seq-okSeq)
   383  	}
   384  }
   385  
   386  func TestTCC(t *testing.T) {
   387  	wd, err := os.Getwd()
   388  	if err != nil {
   389  		t.Fatal(err)
   390  	}
   391  
   392  	testdata, err := filepath.Rel(wd, ccTestdata)
   393  	if err != nil {
   394  		t.Fatal(err)
   395  	}
   396  
   397  	var re *regexp.Regexp
   398  	if s := *filter; s != "" {
   399  		re = regexp.MustCompile(s)
   400  	}
   401  
   402  	dir := filepath.Join(testdata, filepath.FromSlash("tcc-0.9.26/tests/tests2/"))
   403  	expect(
   404  		t,
   405  		dir,
   406  		func(match string) bool {
   407  			if re != nil && !re.MatchString(filepath.Base(match)) {
   408  				return true
   409  			}
   410  
   411  			return false
   412  		},
   413  		func(wd, match string) []string {
   414  			switch filepath.Base(match) {
   415  			case "31_args.c":
   416  				return []string{"./test", "-", "arg1", "arg2", "arg3", "arg4"}
   417  			case "46_grep.c":
   418  				ioutil.WriteFile(filepath.Join(wd, "test"), []byte("abc\ndef\nghi\n"), 0600)
   419  				return []string{"./grep", "[ea]", "test"}
   420  			default:
   421  				return []string{match}
   422  			}
   423  		},
   424  		nil,
   425  		cc.AllowCompatibleTypedefRedefinitions(),
   426  		cc.EnableEmptyStructs(),
   427  		cc.EnableImplicitFuncDef(),
   428  		cc.ErrLimit(-1),
   429  		cc.KeepComments(),
   430  		cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
   431  	)
   432  }
   433  
   434  func TestGCCExec(t *testing.T) {
   435  	blacklist := map[string]struct{}{
   436  		// VLA struct field.
   437  		"20020412-1.c": {},
   438  		"20040308-1.c": {},
   439  		"align-nest.c": {},
   440  		"pr41935.c":    {},
   441  
   442  		// Nested function.
   443  		"20010209-1.c":   {},
   444  		"20010605-1.c":   {},
   445  		"20030501-1.c":   {},
   446  		"20040520-1.c":   {},
   447  		"20061220-1.c":   {},
   448  		"20090219-1.c":   {},
   449  		"920612-2.c":     {},
   450  		"921017-1.c":     {},
   451  		"nest-align-1.c": {},
   452  		"nest-stdar-1.c": {},
   453  		"nestfunc-7.c":   {},
   454  		"pr22061-3.c":    {},
   455  		"pr22061-4.c":    {},
   456  		"pr71494.c":      {},
   457  
   458  		// __real__, complex integers and and friends.
   459  		"20010605-2.c": {},
   460  		"20020411-1.c": {},
   461  		"20030910-1.c": {},
   462  		"20041124-1.c": {},
   463  		"20041201-1.c": {},
   464  		"20050121-1.c": {},
   465  		"complex-1.c":  {},
   466  		"complex-6.c":  {},
   467  		"pr38151.c":    {},
   468  		"pr38969.c":    {},
   469  		"pr56837.c":    {},
   470  
   471  		// Depends on __attribute__((aligned(N)))
   472  		"20010904-1.c": {},
   473  		"20010904-2.c": {},
   474  		"align-3.c":    {},
   475  		"pr23467.c":    {},
   476  
   477  		// Depends on __attribute__ ((vector_size (N)))
   478  		"20050316-1.c":   {},
   479  		"20050316-2.c":   {},
   480  		"20050316-3.c":   {},
   481  		"20050604-1.c":   {},
   482  		"20050607-1.c":   {},
   483  		"pr23135.c":      {},
   484  		"pr53645-2.c":    {},
   485  		"pr53645.c":      {},
   486  		"pr60960.c":      {},
   487  		"pr65427.c":      {},
   488  		"pr71626-1.c":    {},
   489  		"pr71626-2.c":    {},
   490  		"scal-to-vec1.c": {},
   491  		"scal-to-vec2.c": {},
   492  		"scal-to-vec3.c": {},
   493  		"simd-1.c":       {},
   494  		"simd-2.c":       {},
   495  		"simd-4.c":       {},
   496  		"simd-5.c":       {},
   497  		"simd-6.c":       {},
   498  
   499  		// https://goo.gl/XDxJEL
   500  		"20021127-1.c": {},
   501  
   502  		// asm
   503  		"20001009-2.c": {},
   504  		"20020107-1.c": {},
   505  		"20030222-1.c": {},
   506  		"20071211-1.c": {},
   507  		"20071220-1.c": {},
   508  		"20071220-2.c": {},
   509  		"960312-1.c":   {},
   510  		"960830-1.c":   {},
   511  		"990130-1.c":   {},
   512  		"990413-2.c":   {},
   513  		"pr38533.c":    {},
   514  		"pr40022.c":    {},
   515  		"pr40657.c":    {},
   516  		"pr41239.c":    {},
   517  		"pr43385.c":    {},
   518  		"pr43560.c":    {},
   519  		"pr45695.c":    {},
   520  		"pr46309.c":    {},
   521  		"pr49279.c":    {},
   522  		"pr49390.c":    {},
   523  		"pr51877.c":    {},
   524  		"pr51933.c":    {},
   525  		"pr52286.c":    {},
   526  		"pr56205.c":    {},
   527  		"pr56866.c":    {},
   528  		"pr56982.c":    {},
   529  		"pr57344-1.c":  {},
   530  		"pr57344-2.c":  {},
   531  		"pr57344-3.c":  {},
   532  		"pr57344-4.c":  {},
   533  		"pr63641.c":    {},
   534  		"pr65053-1.c":  {},
   535  		"pr65053-2.c":  {},
   536  		"pr65648.c":    {},
   537  		"pr65956.c":    {},
   538  		"pr68328.c":    {},
   539  		"pr69320-2.c":  {},
   540  		"stkalign.c":   {},
   541  
   542  		// __label__
   543  		"920415-1.c": {},
   544  		"920721-4.c": {},
   545  		"930406-1.c": {},
   546  		"980526-1.c": {},
   547  		"pr51447.c":  {},
   548  
   549  		// attribute alias
   550  		"alias-2.c": {},
   551  		"alias-3.c": {},
   552  		"alias-4.c": {},
   553  
   554  		// _Alignas
   555  		"pr68532.c": {},
   556  
   557  		// Profiling
   558  		"eeprof-1.c": {},
   559  
   560  		// 6.5.16/4: The order of evaluation of the operands is unspecified.
   561  		"pr58943.c": {},
   562  	}
   563  
   564  	todolist := map[string]struct{}{
   565  		// long double constant out of range for double.
   566  		"960405-1.c": {},
   567  
   568  		// case range
   569  		"pr34154.c": {},
   570  
   571  		// VLA. Need to resolve https://gitlab.com/cznic/cc/issues/91 first.
   572  		"20040411-1.c":    {},
   573  		"20040423-1.c":    {},
   574  		"20040811-1.c":    {},
   575  		"20041218-2.c":    {},
   576  		"20070919-1.c":    {},
   577  		"920929-1.c":      {},
   578  		"970217-1.c":      {},
   579  		"pr22061-1.c":     {},
   580  		"pr43220.c":       {},
   581  		"vla-dealloc-1.c": {},
   582  
   583  		// Initializer
   584  		"20050613-1.c":        {}, // struct B b = { .a.j = 5 };
   585  		"20050929-1.c":        {}, // struct C e = { &(struct B) { &(struct A) { 1, 2 }, &(struct A) { 3, 4 } }, &(struct A) { 5, 6 } };
   586  		"20071029-1.c":        {}, // t = (T) { { ++i, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
   587  		"921019-1.c":          {}, // void *foo[]={(void *)&("X"[0])};
   588  		"991228-1.c":          {}, // cc.Parse: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/991228-1.c:1:51: invalid designator for type double
   589  		"compndlit-1.c":       {}, // x = (struct S) {b:0, a:0, c:({ struct S o = x; o.a == 1 ? 10 : 20;})};
   590  		"const-addr-expr-1.c": {}, // int *Upgd_minor_ID = (int *) &((Upgrade_items + 1)->uaattrid);
   591  		"pr22098-1.c":         {}, // b = (uintptr_t)(p = &(int []){0, 1, 2}[++a]);
   592  		"pr22098-2.c":         {}, // b = (uintptr_t)(p = &(int []){0, 1, 2}[1]);
   593  		"pr22098-3.c":         {}, // b = (uintptr_t)(p = &(int []){0, f(), 2}[1]);
   594  		"pr70460.c":           {}, // static int b[] = { &&lab1 - &&lab0, &&lab2 - &&lab0 };
   595  
   596  		// signal.h
   597  		"20101011-1.c": {},
   598  
   599  		// &&label expr
   600  		"comp-goto-1.c": {}, // # [100]: Verify (A): mismatched operand type, got int32, expected uint32; simulator_kernel:0x64: 	lsh             	uint32	; ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/comp-goto-1.c:83:40
   601  
   602  		// builtins
   603  		"pr47237.c":       {}, // __builtin_apply, __builtin_apply_args
   604  		"pr64006.c":       {}, // __builtin_mul_overflow
   605  		"pr68381.c":       {}, // __builtin_mul_overflow
   606  		"pr71554.c":       {}, // __builtin_mul_overflow
   607  		"va-arg-pack-1.c": {}, // __builtin_va_arg_pack
   608  
   609  		// long double
   610  		"pr39228.c": {},
   611  
   612  		// un-flatten (wips wrt cc.0506a942f3efa9b7a0a4b98dbe45bf7e8d06a542)
   613  		"20030714-1.c": {}, // cc.Parse: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20030714-1.c:102:11: assignment from incompatible type ('unsigned' = '<undefined>')
   614  		"anon-1.c":     {}, // cc.Parse: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/anon-1.c:22:7: struct{int; ;} has no member named b
   615  
   616  		// irgo -------------------------------------------------------
   617  
   618  		// statement expression
   619  		"20000703-1.c": {},
   620  		"20001203-2.c": {},
   621  		"20020206-1.c": {},
   622  		"20020320-1.c": {},
   623  		"20000917-1.c": {},
   624  
   625  		// computed goto
   626  		"20040302-1.c": {},
   627  		"20041214-1.c": {},
   628  		"20071210-1.c": {},
   629  		"920302-1.c":   {},
   630  		"920501-3.c":   {},
   631  		"920501-4.c":   {},
   632  		"920501-5.c":   {},
   633  
   634  		// __builtin_return_address
   635  		"pr17377.c":    {},
   636  		"20010122-1.c": {},
   637  
   638  		// setjmp/longjmp
   639  		"pr60003.c": {},
   640  
   641  		// alloca
   642  		"20010209-1.c":      {},
   643  		"20020314-1.c":      {},
   644  		"20020412-1.c":      {},
   645  		"20021113-1.c":      {},
   646  		"20040223-1.c":      {},
   647  		"20040308-1.c":      {},
   648  		"20070824-1.c":      {},
   649  		"921017-1.c":        {},
   650  		"941202-1.c":        {},
   651  		"align-nest.c":      {},
   652  		"alloca-1.c":        {},
   653  		"built-in-setjmp.c": {},
   654  		"frame-address.c":   {},
   655  		"pr22061-4.c":       {},
   656  		"pr36321.c":         {},
   657  
   658  		// irgo TODOs
   659  		"20010924-1.c":    {}, // irgo.go:1485: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20010924-1.c:33:3: TODO1247 int8:Int8
   660  		"20020810-1.c":    {}, // irgo.go:1546: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20020810-1.c:17:10: Struct
   661  		"20040307-1.c":    {}, // irgo.go:853: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20040307-1.c:16:11
   662  		"20040331-1.c":    {}, // irgo.go:853: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20040331-1.c:10:10
   663  		"20040629-1.c":    {}, // irgo.go:853: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20040629-1.c:124:1
   664  		"20040705-1.c":    {}, // irgo.go:853: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20040629-1.c:124:1
   665  		"20040705-2.c":    {}, // irgo.go:853: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20040629-1.c:124:1
   666  		"20070614-1.c":    {}, // irgo.go:1601: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20070614-1.c:3:10: *ir.Complex64Value
   667  		"950628-1.c":      {}, // etc.go:600: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/950628-1.c:28:12: *ir.FieldValue
   668  		"950906-1.c":      {}, // etc.go:790: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/950906-1.c:8:3: *ir.Jz 0x00005
   669  		"980602-2.c":      {}, // irgo.go:853: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/980602-2.c:16:11
   670  		"990208-1.c":      {}, // irgo.go:1116: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/990208-1.c:13:13: *ir.Const
   671  		"bitfld-3.c":      {}, // irgo.go:906: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/bitfld-3.c:51:7
   672  		"complex-2.c":     {}, // etc.go:600: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/complex-2.c:16:7: *ir.ConstC128
   673  		"complex-5.c":     {}, // irgo.go:1601: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/complex-5.c:7:20: *ir.Complex64Value
   674  		"complex-7.c":     {}, // irgo.go:1601: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/complex-7.c:5:25: *ir.Complex64Value
   675  		"pr15296.c":       {}, // irgo.go:1392: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr15296.c:65:12: *struct{}, [<nil> 111]
   676  		"pr23324.c":       {}, // irgo.go:1400: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr23324.c:25:3: int64, *ir.Int32Value(1069379046)
   677  		"pr28865.c":       {}, // irgo.go:1400: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr28865.c:3:9: struct{int32,*int8}, *ir.CompositeValue({1, "123456789012345678901234567890"+0})
   678  		"pr30185.c":       {}, // etc.go:600: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr30185.c:21:18: *ir.FieldValue
   679  		"pr33382.c":       {}, // irgo.go:1499: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr33382.c:6:12: TODO1247 int32:Int32
   680  		"pr38051.c":       {},
   681  		"pr42248.c":       {}, // etc.go:600: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr42248.c:23:15: *ir.ConstC128
   682  		"pr42691.c":       {}, // irgo.go:1400: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr42691.c:36:16: [4]uint16, *ir.CompositeValue({0, 0, 0, 32752})
   683  		"pr44164.c":       {}, // New: runtime error: index out of range
   684  		"pr49644.c":       {}, // irgo.go:1601: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr49644.c:8:34: *ir.Complex128Value
   685  		"pr53084.c":       {}, // irgo.go:1596: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr53084.c:15:21
   686  		"pr55750.c":       {}, // irgo.go:853: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr55750.c:14:3
   687  		"pr58209.c":       {},
   688  		"pr68249.c":       {}, // etc.go:420: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr68249.c:11:11: TODO stack(2): 6:			; ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/pr68249.c:11:11
   689  		"stdarg-2.c":      {}, // irgo.go:1145: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/stdarg-2.c:94:17: *ir.Field *struct{}
   690  		"va-arg-13.c":     {}, // irgo.go:1145: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/va-arg-13.c:24:18: *ir.Field *struct{}
   691  		"wchar_t-1.c":     {}, // irgo.go:1601: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/wchar_t-1.c:3:9: *ir.WideStringValue
   692  		"widechar-2.c":    {}, // irgo.go:1601: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/widechar-2.c:3:15: *ir.WideStringValue
   693  		"zero-struct-1.c": {}, // New: runtime error: index out of range
   694  
   695  		// Incorrect conversion
   696  		"20010123-1.c": {}, // 91:109: expected '==', found '='
   697  		"20010518-2.c": {}, // 90:123: expected '==', found '='
   698  		"20020215-1.c": {}, // 86:126: expected '==', found '='
   699  		"20030224-2.c": {}, // 87:125: expected '==', found '='
   700  		"20031215-1.c": {}, // ./main.go:118: cannot use str(0) (type *int8) as type [3]int8 in field value
   701  		"20041212-1.c": {}, // ./main.go:78: cannot convert Xf (type func(*crt.TLS) unsafe.Pointer) to type unsafe.Pointer
   702  		"20050502-2.c": {}, // ./main.go:82: cannot use (*int8)(unsafe.Pointer(&_x)) (type *int8) as type unsafe.Pointer in argument to crt.Xmemcmp
   703  		"20051012-1.c": {}, // ./main.go:79: too many arguments in call to Xfoo
   704  
   705  		"20060929-1.c": {}, // ./main.go:125: *postInc_1018(postInc_20561(&_p, 8), 4) evaluated but not used
   706  		"20071202-1.c": {}, // 108:140: expected '==', found '='
   707  		"20080122-1.c": {}, // ./main.go:82: cannot use str(0) (type *int8) as type [32]uint8 in assignment
   708  		"20120919-1.c": {}, // ./main.go:144: cannot use &Xvd (type *[2]float64) as type *float64 in assignment
   709  		"920501-1.c":   {}, // ./main.go:79: too many arguments in call to Xx
   710  		"921202-1.c":   {}, // ./main.go:94: too many arguments in call to Xmpn_random2
   711  		"921208-2.c":   {}, // ./main.go:95: too many arguments in call to Xg
   712  
   713  		"930608-1.c":           {}, // ./main.go:85: cannot convert Xa (type [1]func(*crt.TLS, float64) float64) to type unsafe.Pointer
   714  		"930719-1.c":           {}, // ./main.go:112: invalid indirect of nil
   715  		"941014-1.c":           {}, // ./main.go:82: cannot convert Xf (type func(*crt.TLS, int32, int32) int32) to type unsafe.Pointer
   716  		"960416-1.c":           {}, // ./main.go:106: cannot convert u64(4294967296) (type uint64) to type struct { X [0]struct { X0 uint64; X1 struct { X0 uint64; X1 uint64 } }; U [16]byte }
   717  		"980223.c":             {}, // ./main.go:126: cannot use &Xcons1 (type *[2]struct { X0 *int8; X1 int64 }) as type *int8 in field value
   718  		"991201-1.c":           {}, // ./main.go:110: cannot use &Xa_con (type *struct { X0 uint64; X1 [48]uint8 }) as type struct { X0 unsafe.Pointer } in array or slice literal
   719  		"alias-1.c":            {}, // ./main.go:109: cannot use &Xval (type *int32) as type *float32 in assignment
   720  		"bcp-1.c":              {}, // ./main.go:86: cannot convert Xbad_t0 (type [6]func(*crt.TLS) int32) to type unsafe.Pointer
   721  		"bswap-2.c":            {}, // 97:124: expected '==', found '='
   722  		"builtin-bitops-1.c":   {}, // ./main.go:92: undefined: crt.X__builtin_clz
   723  		"builtin-prefetch-2.c": {}, // ./main.go:98: &Xglob_int_arr evaluated but not used
   724  		"builtin-prefetch-3.c": {}, // ./main.go:101: &Xglob_vol_int_arr evaluated but not used
   725  		"builtin-prefetch-4.c": {}, // ./main.go:227: cannot convert uintptr(unsafe.Pointer(&Xarr)) + 80 (type uintptr) to type *int32
   726  		"builtin-prefetch-5.c": {}, // ./main.go:78: (*int16)(unsafe.Pointer(uintptr(unsafe.Pointer(unsafe.Pointer(&Xs))) + uintptr(2))) evaluated but not used
   727  		"builtin-prefetch-6.c": {}, // ./main.go:122: *(**int32)(unsafe.Pointer(uintptr(unsafe.Pointer(unsafe.Pointer(&Xbad_addr))) + 8 * uintptr(_i))) evaluated but not used
   728  		"longlong.c":           {}, // ./main.go:124: cannot use &Xb (type *[32]uint64) as type *uint64 in assignment
   729  		"lto-tbaa-1.c":         {}, // ./main.go:112: cannot use &Xb2 (type *struct { X0 *int32 }) as type **int32 in assignment
   730  		"pr43784.c":            {}, // ./main.go:116: cannot use &_v (type *struct { X [0]struct { X0 struct { X0 struct { X0 [256]uint8 }; X1 int32 }; X1 struct { X0 int32; X1 struct { X0 [256]uint8 } } }; U [260]byte }) as type *struct { X0 [256]uint8 } in assignment
   731  
   732  		"pr44555.c":       {}, // Needs a strict-semantic option to pass.
   733  		"pr53160.c":       {}, // ./main.go:86: Xb evaluated but not used
   734  		"pr57130.c":       {}, // 89:111: expected '==', found '='
   735  		"pr57281.c":       {}, // ./main.go:86: Xf evaluated but not used
   736  		"pr57568.c":       {}, // ./main.go:98: cannot convert uintptr(unsafe.Pointer(&Xa)) + 128 (type uintptr) to type *int32
   737  		"pr58277-2.c":     {}, // ./main.go:222: Xd evaluated but not used
   738  		"pr66556.c":       {}, // ./main.go:152: *(*int8)(unsafe.Pointer(uintptr(unsafe.Pointer(unsafe.Pointer(&Xe))) + 1 * uintptr(i32(0)))) evaluated but not used
   739  		"pr67037.c":       {}, // ./main.go:119: too many arguments in call to Xextfunc
   740  		"pr69691.c":       {}, // ./main.go:125: undefined: crt.X__builtin_strchr
   741  		"restrict-1.c":    {}, // 102:130: expected '==', found '='
   742  		"struct-ret-1.c":  {}, // ./main.go:132: cannot use str(64) (type *int8) as type [33]int8 in field value
   743  		"va-arg-4.c":      {}, // ./main.go:120: cannot use str(16) (type *int8) as type [32]int8 in field value
   744  		"zero-struct-2.c": {}, // 84:108: expected '==', found '='
   745  
   746  		// Compiles to Go but fails
   747  		"stdarg-3.c": {}, // y = va_arg (ap, int); but passed value is a struct (???)
   748  	}
   749  	wd, err := os.Getwd()
   750  	if err != nil {
   751  		t.Fatal(err)
   752  	}
   753  
   754  	testdata, err := filepath.Rel(wd, ccTestdata)
   755  	if err != nil {
   756  		t.Fatal(err)
   757  	}
   758  
   759  	var re *regexp.Regexp
   760  	if s := *filter; s != "" {
   761  		re = regexp.MustCompile(s)
   762  	}
   763  
   764  	dir := filepath.Join(testdata, filepath.FromSlash("gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/"))
   765  	expect(
   766  		t,
   767  		dir,
   768  		func(match string) bool {
   769  			base := filepath.Base(match)
   770  			_, skip := blacklist[base]
   771  			if _, skip2 := todolist[base]; skip2 {
   772  				skip = true
   773  			}
   774  			if re != nil {
   775  				skip = !re.MatchString(base)
   776  			}
   777  			return skip
   778  		},
   779  		func(wd, match string) []string {
   780  			return []string{match}
   781  		},
   782  		nil,
   783  		cc.AllowCompatibleTypedefRedefinitions(),
   784  		cc.EnableAlignOf(),
   785  		cc.EnableAlternateKeywords(),
   786  		cc.EnableAnonymousStructFields(),
   787  		cc.EnableAsm(),
   788  		cc.EnableBuiltinClassifyType(),
   789  		cc.EnableBuiltinConstantP(),
   790  		cc.EnableComputedGotos(),
   791  		cc.EnableDefineOmitCommaBeforeDDD(),
   792  		cc.EnableEmptyDeclarations(),
   793  		cc.EnableEmptyStructs(),
   794  		cc.EnableImaginarySuffix(),
   795  		cc.EnableImplicitFuncDef(),
   796  		cc.EnableImplicitIntType(),
   797  		cc.EnableLegacyDesignators(),
   798  		cc.EnableNonConstStaticInitExpressions(),
   799  		cc.EnableOmitConditionalOperand(),
   800  		cc.EnableOmitFuncArgTypes(),
   801  		cc.EnableOmitFuncRetType(),
   802  		cc.EnableParenthesizedCompoundStatemen(),
   803  		cc.EnableTypeOf(),
   804  		cc.EnableUnsignedEnums(),
   805  		cc.EnableWideBitFieldTypes(),
   806  		cc.ErrLimit(-1),
   807  		cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
   808  	)
   809  }
   810  
   811  func build(t *testing.T, predef string, tus [][]string, opts ...cc.Opt) ([]byte, error) {
   812  	ndbg := ""
   813  	if *ndebug {
   814  		ndbg = "#define NDEBUG 1"
   815  	}
   816  	var build []*cc.TranslationUnit
   817  	tus = append(tus, []string{ccir.CRT0Path})
   818  	for _, src := range tus {
   819  		model, err := ccir.NewModel()
   820  		if err != nil {
   821  			t.Fatal(err)
   822  		}
   823  
   824  		ast, err := cc.Parse(
   825  			fmt.Sprintf(`
   826  %s
   827  #define _CCGO 1
   828  #define __arch__ %s
   829  #define __os__ %s
   830  #include <builtin.h>
   831  %s
   832  `, ndbg, runtime.GOARCH, runtime.GOOS, predef),
   833  			src,
   834  			model,
   835  			append([]cc.Opt{
   836  				cc.AllowCompatibleTypedefRedefinitions(),
   837  				cc.EnableEmptyStructs(),
   838  				cc.EnableImplicitFuncDef(),
   839  				cc.EnableNonConstStaticInitExpressions(),
   840  				cc.ErrLimit(*errLimit),
   841  				cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
   842  			}, opts...)...,
   843  		)
   844  		if err != nil {
   845  			t.Fatal(errStr(err))
   846  		}
   847  
   848  		build = append(build, ast)
   849  	}
   850  
   851  	var out, src buffer.Bytes
   852  
   853  	defer func() {
   854  		out.Close()
   855  		src.Close()
   856  	}()
   857  
   858  	if err := New(build, &out, LibcTypes()); err != nil {
   859  		return nil, fmt.Errorf("New: %v", err)
   860  	}
   861  
   862  	fmt.Fprintf(&src, prologue, crtQ, out.Bytes())
   863  	b, err := format.Source(src.Bytes())
   864  	if err != nil {
   865  		return src.Bytes(), err
   866  	}
   867  
   868  	out.Close()
   869  	src.Close()
   870  	return b, nil
   871  }
   872  
   873  func findRepo(t *testing.T, s string) string {
   874  	s = filepath.FromSlash(s)
   875  	for _, v := range strings.Split(strutil.Gopath(), string(os.PathListSeparator)) {
   876  		p := filepath.Join(v, "src", s)
   877  		fi, err := os.Lstat(p)
   878  		if err != nil {
   879  			continue
   880  		}
   881  
   882  		if fi.IsDir() {
   883  			wd, err := os.Getwd()
   884  			if err != nil {
   885  				t.Fatal(err)
   886  			}
   887  
   888  			if p, err = filepath.Rel(wd, p); err != nil {
   889  				t.Fatal(err)
   890  			}
   891  
   892  			return p
   893  		}
   894  	}
   895  	return ""
   896  }
   897  
   898  type file struct {
   899  	name string
   900  	data []byte
   901  }
   902  
   903  func (f file) String() string { return fmt.Sprintf("%v %v", len(f.data), f.name) }
   904  
   905  func run(t *testing.T, src []byte, argv []string, inputFiles []file, errOK bool) (output []byte, resultFiles []file, duration time.Duration) {
   906  	dir, err := ioutil.TempDir("", "ccgo-test-")
   907  	if err != nil {
   908  		t.Fatal(err)
   909  	}
   910  
   911  	defer os.RemoveAll(dir)
   912  
   913  	cwd, err := os.Getwd()
   914  	if err != nil {
   915  		t.Fatal(err)
   916  	}
   917  
   918  	defer os.Chdir(cwd)
   919  
   920  	if err := os.Chdir(dir); err != nil {
   921  		t.Fatal(err)
   922  	}
   923  
   924  	if err := ioutil.WriteFile("main.go", src, 0600); err != nil {
   925  		t.Fatal(err)
   926  	}
   927  
   928  	for _, v := range inputFiles {
   929  		if err := ioutil.WriteFile(v.name, v.data, 0600); err != nil {
   930  			t.Fatal(err)
   931  		}
   932  	}
   933  
   934  	var stdout, stderr buffer.Bytes
   935  
   936  	defer func() {
   937  		stdout.Close()
   938  		stderr.Close()
   939  	}()
   940  
   941  	cmd := exec.Command("go", append([]string{"run", "main.go"}, argv[1:]...)...)
   942  	cmd.Stdout = &stdout
   943  	cmd.Stderr = &stderr
   944  	t0 := time.Now()
   945  	err = cmd.Run()
   946  	duration = time.Since(t0)
   947  	if err != nil && !errOK {
   948  		var log bytes.Buffer
   949  		if b := stdout.Bytes(); b != nil {
   950  			fmt.Fprintf(&log, "stdout:\n%s\n", b)
   951  		}
   952  		if b := stderr.Bytes(); b != nil {
   953  			fmt.Fprintf(&log, "stderr:\n%s\n", b)
   954  		}
   955  		t.Fatalf("err %v\n%s", err, log.Bytes())
   956  	}
   957  
   958  	glob, err := filepath.Glob("*")
   959  	if err != nil {
   960  		t.Fatal(err)
   961  	}
   962  
   963  	for _, m := range glob {
   964  		data, err := ioutil.ReadFile(m)
   965  		if err != nil {
   966  			t.Fatal(err)
   967  		}
   968  
   969  		resultFiles = append(resultFiles, file{m, data})
   970  	}
   971  
   972  	return bytes.TrimSpace(append(stdout.Bytes(), stderr.Bytes()...)), resultFiles, duration
   973  }
   974  
   975  func TestSelfie(t *testing.T) {
   976  	const repo = "github.com/cksystemsteaching/selfie"
   977  	pth := findRepo(t, repo)
   978  	if pth == "" {
   979  		t.Logf("repository not found, skipping: %v", repo)
   980  		return
   981  	}
   982  
   983  	src, err := build(t, "", [][]string{{filepath.Join(pth, "selfie.c")}})
   984  	if err != nil {
   985  		t.Fatal(err)
   986  	}
   987  
   988  	return //TODO Fails on 32 bit.
   989  
   990  	if m, _ := ccir.NewModel(); m.Items[cc.Ptr].Size != 4 {
   991  		return
   992  	}
   993  
   994  	args := []string{"./selfie"}
   995  	out, _, d := run(t, src, args, nil, false)
   996  	if g, e := out, []byte("./selfie: usage: selfie { -c { source } | -o binary | -s assembly | -l binary } [ ( -m | -d | -y | -min | -mob ) size ... ]"); !bytes.Equal(g, e) {
   997  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
   998  	}
   999  
  1000  	t.Logf("%s\n%s\n%v", args, out, d)
  1001  
  1002  	args = []string{"./selfie", "-c", "hello.c", "-m", "1"}
  1003  	out, _, d = run(t, src, args, []file{{"hello.c", []byte(`
  1004  int *foo;
  1005  
  1006  int main() {
  1007  	foo = "Hello world!";
  1008  	while (*foo!=0) { 
  1009  		write(1, foo, 4);
  1010  		foo = foo + 1;
  1011  	}
  1012  	*foo = 10;
  1013  	write(1, foo, 1);
  1014  }
  1015  `)}}, false)
  1016  	if g, e := out, []byte(`./selfie: this is selfie's starc compiling hello.c
  1017  ./selfie: 141 characters read in 12 lines and 0 comments
  1018  ./selfie: with 102(72.46%) characters in 52 actual symbols
  1019  ./selfie: 1 global variables, 1 procedures, 1 string literals
  1020  ./selfie: 2 calls, 3 assignments, 1 while, 0 if, 0 return
  1021  ./selfie: 660 bytes generated with 159 instructions and 24 bytes of data
  1022  ./selfie: this is selfie's mipster executing hello.c with 1MB of physical memory
  1023  Hello world!
  1024  hello.c: exiting with exit code 0 and 0.00MB of mallocated memory
  1025  ./selfie: this is selfie's mipster terminating hello.c with exit code 0 and 0.01MB of mapped memory
  1026  ./selfie: profile: total,max(ratio%)@addr(line#),2max(ratio%)@addr(line#),3max(ratio%)@addr(line#)
  1027  ./selfie: calls: 5,4(80.00%)@0x88(~1),1(20.00%)@0x17C(~5),0(0.00%)
  1028  ./selfie: loops: 3,3(100.00%)@0x198(~6),0(0.00%),0(0.00%)
  1029  ./selfie: loads: 32,4(12.50%)@0x88(~1),3(9.38%)@0x1D4(~7),1(3.12%)@0x24(~1)
  1030  ./selfie: stores: 20,3(15.01%)@0x1D0(~7),1(5.00%)@0x4C(~1),0(0.00%)`); !bytes.Equal(g, e) {
  1031  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1032  	}
  1033  
  1034  	t.Logf("%s\n%s\n%v", args, out, d)
  1035  
  1036  	selfie, err := ioutil.ReadFile(filepath.Join(pth, "selfie.c"))
  1037  	if err != nil {
  1038  		t.Fatal(err)
  1039  	}
  1040  
  1041  	args = []string{"./selfie", "-c", "selfie.c"}
  1042  	out, _, d = run(t, src, args, []file{{"selfie.c", selfie}}, false)
  1043  	if g, e := out, []byte(`./selfie: this is selfie's starc compiling selfie.c
  1044  ./selfie: 176362 characters read in 7086 lines and 970 comments
  1045  ./selfie: with 97764(55.55%) characters in 28916 actual symbols
  1046  ./selfie: 260 global variables, 290 procedures, 450 string literals
  1047  ./selfie: 1960 calls, 722 assignments, 57 while, 571 if, 241 return
  1048  ./selfie: 121676 bytes generated with 28783 instructions and 6544 bytes of data`); !bytes.Equal(g, e) {
  1049  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1050  	}
  1051  
  1052  	t.Logf("%s\n%s\n%v", args, out, d)
  1053  }
  1054  
  1055  func TestSQLite(t *testing.T) {
  1056  	const repo = "sqlite.org/sqlite-amalgamation-3190300/"
  1057  	pth := findRepo(t, repo)
  1058  	if pth == "" {
  1059  		t.Logf("repository not found, skipping: %v", repo)
  1060  		return
  1061  	}
  1062  
  1063  	src, err := build(
  1064  		t,
  1065  		`
  1066  		#define HAVE_MALLOC_H 1
  1067  		#define HAVE_MALLOC_USABLE_SIZE 1
  1068  		#define SQLITE_DEBUG 1
  1069  		#define SQLITE_ENABLE_API_ARMOR 1
  1070  		#define SQLITE_WITHOUT_MSIZE 1
  1071  		`,
  1072  		[][]string{
  1073  			{"testdata/sqlite/test.c"},
  1074  			{filepath.Join(pth, "sqlite3.c")},
  1075  		},
  1076  		cc.EnableAnonymousStructFields(),
  1077  		cc.EnableWideBitFieldTypes(),
  1078  		cc.IncludePaths([]string{pth}),
  1079  	)
  1080  	if *oLog {
  1081  		t.Logf("\n%s", src)
  1082  	}
  1083  	if err != nil {
  1084  		t.Fatal(err)
  1085  	}
  1086  
  1087  	args := []string{"./test"}
  1088  	out, f, d := run(t, src, args, nil, true)
  1089  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1090  	if g, e := out, []byte(`Usage: ./test DATABASE SQL-STATEMENT
  1091  exit status 1`); !bytes.Equal(g, e) {
  1092  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1093  	}
  1094  
  1095  	args = []string{"./test", "foo"}
  1096  	out, f, d = run(t, src, args, nil, true)
  1097  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1098  	if g, e := out, []byte(`Usage: ./test DATABASE SQL-STATEMENT
  1099  exit status 1`); !bytes.Equal(g, e) {
  1100  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1101  	}
  1102  
  1103  	args = []string{"./test", "foo", "bar"}
  1104  	out, f, d = run(t, src, args, nil, true)
  1105  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1106  	if g, e := out, []byte(`FAIL (1) near "bar": syntax error
  1107  SQL error: near "bar": syntax error`); !bytes.Equal(g, e) {
  1108  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1109  	}
  1110  
  1111  	args = []string{"./test", "foo", "select * from t"}
  1112  	out, f, d = run(t, src, args, nil, false)
  1113  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1114  	if g, e := out, []byte(`FAIL (1) no such table: t
  1115  SQL error: no such table: t`); !bytes.Equal(g, e) {
  1116  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1117  	}
  1118  
  1119  	args = []string{"./test", "foo", "select name from sqlite_master where type='table'"}
  1120  	out, f, d = run(t, src, args, nil, false)
  1121  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1122  	if g, e := out, []byte(""); !bytes.Equal(g, e) {
  1123  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1124  	}
  1125  
  1126  	args = []string{"./test", "foo", "create table t(i int)"}
  1127  	out, f, d = run(t, src, args, nil, false)
  1128  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1129  	if g, e := out, []byte(""); !bytes.Equal(g, e) {
  1130  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1131  	}
  1132  
  1133  	args = []string{"./test", "foo", `
  1134  		create table t(i int);
  1135  		select name from sqlite_master where type='table';
  1136  		`}
  1137  	out, f, d = run(t, src, args, nil, false)
  1138  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1139  	if g, e := out, []byte("name = t"); !bytes.Equal(g, e) {
  1140  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1141  	}
  1142  
  1143  	args = []string{"./test", "foo", `
  1144  		create table t(i int);
  1145  		select name from sqlite_master where type='table';
  1146  		insert into t values(42), (314);
  1147  		select * from t order by i asc;
  1148  		select * from t order by i desc;
  1149  		`}
  1150  	out, f, d = run(t, src, args, nil, false)
  1151  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1152  	if g, e := out, []byte(`name = t
  1153  i = 42
  1154  i = 314
  1155  i = 314
  1156  i = 42`); !bytes.Equal(g, e) {
  1157  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1158  	}
  1159  }
  1160  
  1161  func TestOther(t *testing.T) {
  1162  	var re *regexp.Regexp
  1163  	if s := *filter; s != "" {
  1164  		re = regexp.MustCompile(s)
  1165  	}
  1166  
  1167  	expect(
  1168  		t,
  1169  		"testdata",
  1170  		func(match string) bool {
  1171  			if re != nil && !re.MatchString(filepath.Base(match)) {
  1172  				return true
  1173  			}
  1174  
  1175  			return false
  1176  		},
  1177  		func(wd, match string) []string {
  1178  			return []string{match}
  1179  		},
  1180  		nil,
  1181  		cc.EnableEmptyStructs(),
  1182  		cc.EnableImplicitFuncDef(),
  1183  		cc.ErrLimit(-1),
  1184  		cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
  1185  	)
  1186  }