github.com/gotranspile/cxgo@v0.3.7/tcc_test.go (about)

     1  package cxgo
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime/debug"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/gotranspile/cxgo/internal/git"
    14  	"github.com/gotranspile/cxgo/libs"
    15  	"github.com/gotranspile/cxgo/types"
    16  )
    17  
    18  func downloadTCC(t testing.TB, dst string) {
    19  	err := os.MkdirAll(dst, 0755)
    20  	require.NoError(t, err)
    21  
    22  	const (
    23  		repo   = "https://repo.or.cz/tinycc.git"
    24  		sub    = "tests/tests2"
    25  		branch = "release_0_9_27"
    26  	)
    27  
    28  	dir := filepath.Join(os.TempDir(), "cxgo_tcc_git")
    29  	_ = os.RemoveAll(dir)
    30  
    31  	t.Log("cloning", repo, "to", dir)
    32  	err = git.Clone(repo, branch, dir)
    33  	if err != nil {
    34  		os.RemoveAll(dst)
    35  	}
    36  	require.NoError(t, err)
    37  	//defer os.RemoveAll(dir)
    38  
    39  	files, err := filepath.Glob(filepath.Join(dir, sub, "*.c"))
    40  	require.NoError(t, err)
    41  	require.NotEmpty(t, files)
    42  
    43  	for _, path := range files {
    44  		base := filepath.Base(path)
    45  		err = copyFile(path, filepath.Join(dst, base))
    46  		require.NoError(t, err)
    47  		bexp := strings.TrimSuffix(base, ".c") + ".expect"
    48  		bhdr := strings.TrimSuffix(base, ".c") + ".h"
    49  		err = copyFile(filepath.Join(filepath.Dir(path), bexp), filepath.Join(dst, bexp))
    50  		require.NoError(t, err)
    51  		_ = copyFile(filepath.Join(filepath.Dir(path), bhdr), filepath.Join(dst, bhdr))
    52  	}
    53  }
    54  
    55  func TestTCCExecute(t *testing.T) {
    56  	if testing.Short() || os.Getenv("CXGO_RUN_TESTS_TCC") != "true" {
    57  		t.SkipNow()
    58  	}
    59  	dir := filepath.Join(testDataDir, "tcc")
    60  
    61  	ignoreTests := map[string]string{
    62  		"81_types":                "incomplete types, invalid calls",
    63  		"85_asm-outside-function": "uses assembly",
    64  		"98_al_ax_extend":         "uses assembly",
    65  		"99_fastcall":             "uses assembly",
    66  	}
    67  	blacklist := map[string]struct{}{
    68  		"34_array_assignment":     {}, // CC parsing failure
    69  		"46_grep":                 {},
    70  		"51_static":               {},
    71  		"54_goto":                 {},
    72  		"55_lshift_type":          {},
    73  		"60_errors_and_warnings":  {},
    74  		"73_arm64":                {},
    75  		"75_array_in_struct_init": {}, // CC type checker failure
    76  		"77_push_pop_macro":       {}, // FIXME: cannot detect if a macro was redefined
    77  		"78_vla_label":            {},
    78  		"79_vla_continue":         {},
    79  		"87_dead_code":            {},
    80  		"88_codeopt":              {},
    81  		"89_nocode_wanted":        {},
    82  		"90_struct-init":          {},
    83  		"92_enum_bitfield":        {},
    84  		"93_integer_promotion":    {}, // TODO: some issues with char promotion
    85  		"94_generic":              {},
    86  		"95_bitfields":            {},
    87  		"95_bitfields_ms":         {},
    88  		"96_nodata_wanted":        {},
    89  		"97_utf8_string_literal":  {},
    90  	}
    91  	overrideExpect := map[string]string{
    92  		// TODO: printf("%f", 12.34 + 56.78); TCC: 69.120003, Go: 69.119995
    93  		"22_floating_point": "69.120003\n69.120000\n-44.440000\n700.665200\n0.217330\n1 1 0 0 0 1\n0 1 1 1 0 0\n0 0 0 1 1 1\n69.119995\n-44.439999\n700.665222\n0.217330\n12.340000\n-12.340000\n2.000000\n0.909297\n",
    94  		// TODO: we leave an additional whitespace after each line; probably tcc test trims them when checking output?
    95  		"38_multiple_array_index": "x=0: 1 2 3 4 \nx=1: 5 6 7 8 \nx=2: 9 10 11 12 \nx=3: 13 14 15 16 \n",
    96  		// TODO: we don't implement __TINYC__ and related extensions
    97  		"70_floating_point_literals": "0.123000\n122999996416.000000\n0.000000\n122999996416.000000\n\n123.123001\n123122997002240.000000\n0.000000\n123122997002240.000000\n\n123.000000\n123000003231744.000000\n0.000000\n123000003231744.000000\n\n123000003231744.000000\n0.000000\n123000003231744.000000\n\n\n428.000000\n0.000026\n428.000000\n\n1756112.000000\n0.104672\n1756592.000000\n\n1753088.000000\n0.104492\n1753088.000000\n\n1753088.000000\n0.104492\n1753088.000000\n\n\n",
    98  		// TODO: additional expected line break; probably trimmed by tcc test?
    99  		"71_macro_empty_arg": "17",
   100  		// TODO: additional expected line break; probably trimmed by tcc test?
   101  		"76_dollars_in_identifiers": "fred=10\njoe=20\nhenry=30\nfred2=10\njoe2=20\nhenry2=30\nfred10=100\njoe_10=2\nlocal=10\na100$=100\na$$=1000\na$c$b=2121\n$100=10000\n$$$=money",
   102  		// TODO: we don't support bitfields yet
   103  		"93_integer_promotion": " unsigned : s.ub\n unsigned : s.u\n unsigned : s.ullb\n unsigned : s.ull\n   signed : s.c\n\n unsigned : (1 ? s.ub : 1)\n unsigned : (1 ? s.u : 1)\n unsigned : (1 ? s.ullb : 1)\n unsigned : (1 ? s.ull : 1)\n   signed : (1 ? s.c : 1)\n\n unsigned : s.ub << 1\n unsigned : s.u << 1\n unsigned : s.ullb << 1\n unsigned : s.ull << 1\n   signed : s.c << 1\n\n   signed : +s.ub\n unsigned : +s.u\n unsigned : +s.ullb\n unsigned : +s.ull\n   signed : +s.c\n\n   signed : -s.ub\n unsigned : -s.u\n unsigned : -s.ullb\n unsigned : -s.ull\n   signed : -s.c\n\n   signed : ~s.ub\n unsigned : ~s.u\n unsigned : ~s.ullb\n unsigned : ~s.ull\n   signed : ~s.c\n\n   signed : !s.ub\n   signed : !s.u\n   signed : !s.ullb\n   signed : !s.ull\n   signed : !s.c\n\n unsigned : +(unsigned)s.ub\n unsigned : -(unsigned)s.ub\n unsigned : ~(unsigned)s.ub\n   signed : !(unsigned)s.ub\n",
   104  	}
   105  
   106  	if _, err := os.Stat(dir); os.IsNotExist(err) {
   107  		downloadTCC(t, dir)
   108  	}
   109  
   110  	files, err := filepath.Glob(filepath.Join(dir, "*.c"))
   111  	require.NoError(t, err)
   112  	require.NotEmpty(t, files)
   113  
   114  	wd, err := os.Getwd()
   115  	require.NoError(t, err)
   116  
   117  	out := filepath.Join(os.TempDir(), "cxgo_test_tcc")
   118  	err = os.MkdirAll(out, 0755)
   119  	require.NoError(t, err)
   120  
   121  	goProject(t, out, wd)
   122  	goProjectMod(t, out)
   123  
   124  	for _, path := range files {
   125  		path := path
   126  		tname := strings.TrimSuffix(filepath.Base(path), ".c")
   127  		_, skip := blacklist[tname]
   128  		t.Run(tname, func(t *testing.T) {
   129  			if reason, ignore := ignoreTests[tname]; ignore {
   130  				t.Skip(reason)
   131  			}
   132  			//t.Parallel()
   133  			defer func() {
   134  				if r := recover(); r != nil {
   135  					if skip {
   136  						defer debug.PrintStack()
   137  						t.Skipf("panic: %v", r)
   138  					} else {
   139  						require.Nil(t, r)
   140  					}
   141  				}
   142  				if !t.Failed() && !t.Skipped() && skip {
   143  					t.Error("blacklisted test pass")
   144  				}
   145  			}()
   146  			oname := filepath.Base(path) + ".go"
   147  			env := libs.NewEnv(types.Config32())
   148  			err = Translate(filepath.Dir(path), path, out, env, Config{
   149  				Package:     "main",
   150  				GoFile:      oname,
   151  				MaxDecls:    -1,
   152  				ForwardDecl: true,
   153  			})
   154  			failOrSkip(t, err, skip)
   155  
   156  			t.Log(path)
   157  			t.Log(filepath.Join(out, oname))
   158  
   159  			args := []string{"arg1", "arg2", "arg3", "arg4", "arg5"}
   160  			got := goRun(t, out, []string{"./" + oname}, runConfig{Arch32: true, Skip: skip}, args...)
   161  			epath := strings.TrimSuffix(path, ".c") + ".expect"
   162  			var exp []byte
   163  			if s, ok := overrideExpect[tname]; ok {
   164  				exp = []byte(s)
   165  			} else {
   166  				exp, err = ioutil.ReadFile(epath)
   167  				require.NoError(t, err)
   168  			}
   169  			if string(exp) != string(got) && skip {
   170  				t.Skipf("unexpected output:\nexpected: %q\nactual  : %q", exp, got)
   171  			}
   172  			require.Equal(t, string(exp), string(got))
   173  		})
   174  	}
   175  }