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 }