diff options
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-x | tests/runner.py | 1500 |
1 files changed, 1222 insertions, 278 deletions
diff --git a/tests/runner.py b/tests/runner.py index 26ae51f5..58a18555 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -14,7 +14,38 @@ will use 4 processes. To install nose do something like ''' from subprocess import Popen, PIPE, STDOUT -import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, difflib, webbrowser, hashlib, BaseHTTPServer, threading, platform +import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, difflib, webbrowser, hashlib, threading, platform, BaseHTTPServer, multiprocessing, functools + + +if len(sys.argv) == 1: + print ''' +============================================================================== +Running the main part of the test suite. Don't forget to run the other parts! + + sanity - tests for first run, etc., modifies ~/.emscripten + benchmark - run before and after each set of changes before pushing to + master, verify no regressions + browser - runs pages in a web browser + +To run one of those parts, do something like + + python tests/runner.py sanity + +To run a specific set of tests, you can do things like + + python tests/runner.py o1 + +(that runs the o1 (-O1) tests). You can run individual tests with + + python tests/runner.py test_hello_world + +Combinations work too, for example + + python tests/runner.py browser.test_sdl_image +============================================================================== + +''' + time.sleep(2) # Setup @@ -48,7 +79,7 @@ class RunnerCore(unittest.TestCase): if not self.save_dir: dirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR) else: - dirname = EMSCRIPTEN_TEMP_DIR + dirname = CANONICAL_TEMP_DIR if not os.path.exists(dirname): os.makedirs(dirname) self.working_dir = dirname @@ -62,6 +93,8 @@ class RunnerCore(unittest.TestCase): shutil.copy(os.path.join(self.get_dir(), name), os.path.join(TEMP_DIR, self.id().replace('__main__.', '').replace('.test_', '.')+'.'+suff)) if not self.save_dir: + # rmtree() fails on Windows if the current working directory is inside the tree. + os.chdir(os.path.join(self.get_dir(), '..')) shutil.rmtree(self.get_dir()) def skip(self, why): @@ -134,7 +167,7 @@ class RunnerCore(unittest.TestCase): transform = open(transform_filename, 'w') transform.write(''' import sys -sys.path += ['%s'] +sys.path += [%r] ''' % path_from_root('')) transform.write(post1) transform.write(''' @@ -162,6 +195,9 @@ process(sys.argv[1]) additional_files = final_additional_files else: # copy whole directory, and use a specific main .cpp file + # (rmtree() fails on Windows if the current working directory is inside the tree.) + if os.getcwd().startswith(os.path.abspath(dirname)): + os.chdir(os.path.join(dirname, '..')) shutil.rmtree(dirname) shutil.copytree(src, dirname) shutil.move(os.path.join(dirname, main_file), filename) @@ -252,7 +288,13 @@ process(sys.argv[1]) library_cache = {} - def get_library(self, name, generated_libs, configure=['./configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True): + def get_build_dir(self): + ret = os.path.join(self.get_dir(), 'building') + if not os.path.exists(ret): + os.makedirs(ret) + return ret + + def get_library(self, name, generated_libs, configure=['sh', './configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True): build_dir = self.get_build_dir() output_dir = self.get_dir() @@ -274,12 +316,20 @@ process(sys.argv[1]) return Building.build_library(name, build_dir, output_dir, generated_libs, configure, configure_args, make, make_args, self.library_cache, cache_name, copy_project=True) + def clear(self): + for name in os.listdir(self.get_dir()): + try_delete(name) + emcc_debug = os.environ.get('EMCC_DEBUG') + if emcc_debug: + for name in os.listdir(EMSCRIPTEN_TEMP_DIR): + try_delete(os.path.join(EMSCRIPTEN_TEMP_DIR, name)) + ################################################################################################### sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv) -if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): +if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'browser' not in str(sys.argv): # Tests print "Running Emscripten tests..." @@ -568,13 +618,13 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): return 0; } ''' - self.do_run(src, '*1311918518731868200\n' + + self.do_run(src, '*1311918518731868041\n' + '0,0,0,1,1\n' + '1,0,1,0,1*\n' + '*245127260211081*\n' + '*245127260209443*\n' + - '*18446744073709552000*\n' + - '*576460752303423500*\n' + + '*18446744073709551615*\n' + + '*576460752303423487*\n' + 'm1: 127\n' + '*123*\n' + '*127*\n' + @@ -689,6 +739,51 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): self.do_run(src, '*1,1,0,0,1,0*\n') + def test_i64_cmp2(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') + src = r''' + #include <inttypes.h> + #include <stdio.h> + + typedef int32_t INT32; + typedef int64_t INT64; + typedef uint8_t UINT8; + + void interface_clock_changed() + { + UINT8 m_divshift; + INT32 m_divisor; + + //INT64 attos = m_attoseconds_per_cycle; + INT64 attos = 279365114840; + m_divshift = 0; + while (attos >= (1UL << 31)) + { + m_divshift++; + printf("m_divshift is %i, on %Ld >?= %lu\n", m_divshift, attos, 1UL << 31); + attos >>= 1; + } + m_divisor = attos; + + printf("m_divisor is %i\n",m_divisor); + } + + int main() { + interface_clock_changed(); + return 0; + } + ''' + self.do_run(src, '''m_divshift is 1, on 279365114840 >?= 2147483648 +m_divshift is 2, on 139682557420 >?= 2147483648 +m_divshift is 3, on 69841278710 >?= 2147483648 +m_divshift is 4, on 34920639355 >?= 2147483648 +m_divshift is 5, on 17460319677 >?= 2147483648 +m_divshift is 6, on 8730159838 >?= 2147483648 +m_divshift is 7, on 4365079919 >?= 2147483648 +m_divshift is 8, on 2182539959 >?= 2147483648 +m_divisor is 1091269979 +''') + def test_i64_double(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') src = r''' @@ -731,6 +826,101 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): ''' self.do_run(src, '*0,0,0,0*\n*1,1,0,0*\n') # same as gcc + def test_i64_umul(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') + src = r''' + #include <inttypes.h> + #include <stdio.h> + + typedef uint32_t UINT32; + typedef uint64_t UINT64; + + int main() { + volatile UINT32 testu32a = 2375724032U; + UINT32 bigu32 = 0xffffffffU; + volatile UINT64 testu64a = 14746250828952703000U; + + while ((UINT64)testu32a * (UINT64)bigu32 < testu64a) { + printf("testu64a is %llu\n", testu64a); + testu64a /= 2; + } + + return 0; + } + ''' + self.do_run(src, 'testu64a is 14746250828952703000\n') + + def test_i64_precise(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') + + src = r''' + #include <inttypes.h> + #include <stdio.h> + + int main() { + uint64_t x = 0, y = 0; + for (int i = 0; i < 64; i++) { + x += 1ULL << i; + y += x; + x /= 3; + y *= 5; + printf("unsigned %d: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i, x, y, x+y, x-y, x*y, y ? x/y : 0, x ? y/x : 0, y ? x%y : 0, x ? y%x : 0); + } + int64_t x2 = 0, y2 = 0; + for (int i = 0; i < 64; i++) { + x2 += 1LL << i; + y2 += x2; + x2 /= 3 * (i % 7 ? -1 : 1); + y2 *= 5 * (i % 2 ? -1 : 1); + printf("signed %d: %lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld\n", i, x2, y2, x2+y2, x2-y2, x2*y2, y2 ? x2/y2 : 0, x2 ? y2/x2 : 0, y2 ? x2%y2 : 0, x2 ? y2%x2 : 0); + } + return 0; + } + ''' + self.do_run(src, open(path_from_root('tests', 'i64_precise.txt')).read()) + + # Verify that without precision, we do not include the precision code + Settings.PRECISE_I64_MATH = 0 + self.do_run(src, 'unsigned') + code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() + assert 'goog.math.Long' not in code and 'jsbn' not in code, 'i64 precise math should not have been included if not asked for' + + # Verify that even if we ask for precision, if it is not needed it is not included + Settings.PRECISE_I64_MATH = 1 + src = ''' + #include <inttypes.h> + #include <stdio.h> + + int main(int argc, char **argv) { + uint64_t x = 2125299906845564, y = 1225891506842664; + if (argc == 12) { + x = x >> 1; + y = y >> 1; + } + x = x & 12ULL; + y = y | 12ULL; + x = x ^ y; + x <<= 2; + y >>= 3; + printf("*%llu, %llu*\\n", x, y); + } + ''' + self.do_run(src, '*4903566027370624, 153236438355333*') + code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() + assert 'goog.math.Long' not in code and 'jsbn' not in code, 'i64 precise math should not have been included if not actually used' + + def test_cube2hash(self): + # A good test of i64 math + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2 C-style memory aliasing') + self.do_run('', 'Usage: hashstring <seed>', + libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None), + includes=[path_from_root('tests', 'cube2hash')]) + + for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'), + ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'), + ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670')]: + self.do_run('', 'hash value: ' + output, [text], no_build=True) + def test_unaligned(self): if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1') @@ -1440,6 +1630,9 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): if self.emcc_args is None: if Building.LLVM_OPTS: return self.skip('optimizing bitcode before emcc can confuse libcxx inclusion') self.emcc_args = [] # libc++ auto-inclusion is only done if we use emcc + else: + if '-O2' in self.emcc_args: + self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage src = ''' #include <stdio.h> @@ -1520,6 +1713,8 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): def test_uncaught_exception(self): if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc') + if '-O2' in self.emcc_args: + self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage Settings.EXCEPTION_DEBUG = 0 # Messes up expected output. Settings.DISABLE_EXCEPTION_CATCHING = 0 @@ -1623,6 +1818,18 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): ''' self.do_run(src, '*51,87,78,550,100,78,550*') + def test_isdigit_l(self): + if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc') + + src = ''' + #include <iostream> + int main() { + using namespace std; + use_facet<num_put<char> >(cout.getloc()).put(cout, cout, '0', 3.14159265); + } + ''' + self.do_run(src, '3.14159') + def test_polymorph(self): src = ''' #include <stdio.h> @@ -1797,75 +2004,81 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): ''' self.do_run(src, 'z:1*', force_c=True) - if self.emcc_args is not None: # too slow in other modes - # We should not blow up the stack with numerous allocas + def test_alloca_stack(self): + if self.emcc_args is None: return # too slow in other modes - src = ''' - #include <stdio.h> - #include <stdlib.h> + # We should not blow up the stack with numerous allocas + src = ''' + #include <stdio.h> + #include <stdlib.h> - func(int i) { - char *pc = (char *)alloca(100); - *pc = i; - (*pc)++; - return (*pc) % 10; - } - int main() { - int total = 0; - for (int i = 0; i < 1024*1024; i++) - total += func(i); - printf("ok:%d*\\n", total); - return 0; - } - ''' - self.do_run(src, 'ok:-32768*', force_c=True) + func(int i) { + char *pc = (char *)alloca(100); + *pc = i; + (*pc)++; + return (*pc) % 10; + } + int main() { + int total = 0; + for (int i = 0; i < 1024*1024; i++) + total += func(i); + printf("ok:%d*\\n", total); + return 0; + } + ''' + self.do_run(src, 'ok:-32768*', force_c=True) - # We should also not blow up the stack with byval arguments - src = r''' - #include<stdio.h> - struct vec { - int x, y, z; - vec(int x_, int y_, int z_) : x(x_), y(y_), z(z_) {} - static vec add(vec a, vec b) { - return vec(a.x+b.x, a.y+b.y, a.z+b.z); - } - }; - int main() { - int total = 0; - for (int i = 0; i < 1000; i++) { - for (int j = 0; j < 1000; j++) { - vec c(i+i%10, j*2, i%255); - vec d(j*2, j%255, i%120); - vec f = vec::add(c, d); - total += (f.x + f.y + f.z) % 100; - total %= 10240; - } + def test_stack_byval(self): + if self.emcc_args is None: return # too slow in other modes + + # We should also not blow up the stack with byval arguments + src = r''' + #include<stdio.h> + struct vec { + int x, y, z; + vec(int x_, int y_, int z_) : x(x_), y(y_), z(z_) {} + static vec add(vec a, vec b) { + return vec(a.x+b.x, a.y+b.y, a.z+b.z); + } + }; + int main() { + int total = 0; + for (int i = 0; i < 1000; i++) { + for (int j = 0; j < 1000; j++) { + vec c(i+i%10, j*2, i%255); + vec d(j*2, j%255, i%120); + vec f = vec::add(c, d); + total += (f.x + f.y + f.z) % 100; + total %= 10240; } - printf("sum:%d*\n", total); - return 1; } - ''' - self.do_run(src, 'sum:9780*') + printf("sum:%d*\n", total); + return 1; + } + ''' + self.do_run(src, 'sum:9780*') - # We should not blow up the stack with numerous varargs + def test_stack_varargs(self): + if self.emcc_args is None: return # too slow in other modes - src = r''' - #include <stdio.h> - #include <stdlib.h> + # We should not blow up the stack with numerous varargs + src = r''' + #include <stdio.h> + #include <stdlib.h> - void func(int i) { - printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", - i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i); - } - int main() { - for (int i = 0; i < 1024; i++) - func(i); - printf("ok!\n"); - return 0; - } - ''' - Settings.TOTAL_STACK = 1024 - self.do_run(src, 'ok!') + void func(int i) { + printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i); + } + int main() { + for (int i = 0; i < 1024; i++) + func(i); + printf("ok!\n"); + return 0; + } + ''' + Settings.TOTAL_STACK = 1024 + self.do_run(src, 'ok!') def test_array2(self): src = ''' @@ -2117,7 +2330,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): int main() { // EMSCRIPTEN_COMMENT("hello from the source"); - emscripten_run_script("print('hello world' + '!')"); + emscripten_run_script("Module.print('hello world' + '!')"); printf("*%d*\n", emscripten_run_script_int("5*20")); return 0; } @@ -2131,6 +2344,18 @@ def process(filename): self.do_run(src, 'hello world!\n*100*', post_build=check) + def test_inlinejs(self): + src = r''' + #include <stdio.h> + + int main() { + asm("Module.print('Inline JS is very cool')"); + return 0; + } + ''' + + self.do_run(src, 'Inline JS is very cool') + def test_memorygrowth(self): # With typed arrays in particular, it is dangerous to use more memory than TOTAL_MEMORY, # since we then need to enlarge the heap(s). @@ -2218,6 +2443,8 @@ def process(filename): self.do_run(src, '*nameA,nameB*') def test_llvmswitch(self): + Settings.CORRECT_SIGNS = 1 + src = ''' #include <stdio.h> #include <string.h> @@ -2229,18 +2456,20 @@ def process(filename): case 'b': case 'c': return p-1; - case 'd': + case 0xfffffff1: return p+1; } return p; } int main( int argc, const char *argv[] ) { - printf("*%d,%d,%d,%d,%d*\\n", switcher('a'), switcher('b'), switcher('c'), switcher('d'), switcher('e')); + unsigned int x = 0xfffffff1; + x >>= 0; // force it to be unsigned for purpose of checking our switch comparison in signed/unsigned + printf("*%d,%d,%d,%d,%d,%d*\\n", switcher('a'), switcher('b'), switcher('c'), switcher(x), switcher(-15), switcher('e')); return 0; } ''' - self.do_run(src, '*96,97,98,101,101*') + self.do_run(src, '*96,97,98,-14,-14,101*') def test_indirectbr(self): src = ''' @@ -2415,6 +2644,8 @@ def process(filename): # part 2: make sure we warn about mixing c and c++ calling conventions here + if not (self.emcc_args is None or self.emcc_args == []): return # Optimized code is missing the warning comments + header = r''' struct point { @@ -2467,17 +2698,11 @@ def process(filename): all_name = os.path.join(self.get_dir(), 'all.bc') Building.link([supp_name + '.o', main_name + '.o'], all_name) - try: - # This will fail! See explanation near the warning we check for, in the compiler source code - self.do_ll_run(all_name, 'pre: 54,2\ndump: 55,3\ndump: 55,3\npost: 54,2') - except Exception, e: - # Check for warning in the generated code - generated = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() - if self.emcc_args is None or self.emcc_args == []: # Optimized code is missing the warning comments - assert 'Casting a function pointer type to another with a different number of arguments.' in generated, 'Missing expected warning' - assert 'void (i32, i32)* ==> void (%struct.point*)*' in generated, 'Missing expected warning details' - return - raise Exception('We should not have gotten to here!') + # This will fail! See explanation near the warning we check for, in the compiler source code + output = Popen(['python', EMCC, all_name], stderr=PIPE).communicate() + # Check for warning in the generated code + generated = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() + assert 'Casting a function pointer type to another with a different number of arguments.' in output[1], 'Missing expected warning' def test_stdlibs(self): if Settings.USE_TYPED_ARRAYS == 2: @@ -3527,12 +3752,20 @@ at function.:blag sscanf("-3.03", "%f", &a); printf("%.4f\n", a); + char buffy[100]; + sscanf("cheez some thing moar 123\nyet more\n", "cheez %s", buffy); + printf("|%s|\n", buffy); + sscanf("cheez something\nmoar 123\nyet more\n", "cheez %s", buffy); + printf("|%s|\n", buffy); + sscanf("cheez somethingmoar\tyet more\n", "cheez %s", buffy); + printf("|%s|\n", buffy); return 0; } ''' - self.do_run(src, 'en-us : 2\nen-r : 99\nen : 3\n1.234567, 0.000000\n-3.0300') + self.do_run(src, 'en-us : 2\nen-r : 99\nen : 3\n1.234567, 0.000000\n-3.0300\n|some|\n|something|\n|somethingmoar|') - # Part 2: doubles + def test_sscanf_2(self): + # doubles if Settings.USE_TYPED_ARRAYS == 2: for ftype in ['float', 'double']: src = r''' @@ -3601,6 +3834,7 @@ Pass: 0.000012 0.000012''') def process(filename): src = \'\'\' var Module = { + 'noFSInit': true, 'preRun': function() { FS.createDataFile('/', 'somefile.binary', [100, 200, 50, 25, 10, 77, 123], true, false); // 200 becomes -56, since signed chars are used in memory FS.createLazyFile('/', 'test.file', 'test.file', true, false); @@ -3622,6 +3856,37 @@ def process(filename): self.do_run(src, 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\n', post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h']) + def test_files_m(self): + # Test for Module.stdin etc. + + Settings.CORRECT_SIGNS = 1 + + post = ''' +def process(filename): + src = \'\'\' + var data = [10, 20, 40, 30]; + var Module = { + stdin: function() { return data.pop() || null }, + stdout: function(x) { Module.print('got: ' + x) } + }; + \'\'\' + open(filename, 'r').read() + open(filename, 'w').write(src) +''' + src = r''' + #include <stdio.h> + #include <unistd.h> + + int main () { + char c; + fprintf(stderr, "isatty? %d,%d,%d\n", isatty(fileno(stdin)), isatty(fileno(stdout)), isatty(fileno(stderr))); + while ((c = fgetc(stdin)) != EOF) { + putc(c+5, stdout); + } + return 0; + } + ''' + self.do_run(src, 'isatty? 0,0,1\ngot: 35\ngot: 45\ngot: 25\ngot: 15\n', post_build=post) + def test_folders(self): add_pre_run = ''' def process(filename): @@ -3926,8 +4191,8 @@ def process(filename): ).replace( '// {{POST_RUN_ADDITIONS}}', \'\'\' - print('first changed: ' + (TEST_F1.timestamp == 1200000000000)); - print('second changed: ' + (TEST_F2.timestamp == 1200000000000)); + Module.print('first changed: ' + (TEST_F1.timestamp == 1200000000000)); + Module.print('second changed: ' + (TEST_F2.timestamp == 1200000000000)); \'\'\' ) open(filename, 'w').write(src) @@ -4334,7 +4599,7 @@ def process(filename): ''' # FIXME: should not have so many newlines in output here - self.do_run(src, 'hello world\n\n77.\n') + self.do_run(src, 'hello world\n77.\n') def test_stdvec(self): src = ''' @@ -4413,7 +4678,7 @@ def process(filename): # emcc should build in dlmalloc automatically, and do all the sign correction etc. for it try_delete(os.path.join(self.get_dir(), 'src.cpp.o.js')) - output = Popen([EMCC, path_from_root('tests', 'dlmalloc_test.c'), + output = Popen(['python', EMCC, path_from_root('tests', 'dlmalloc_test.c'), '-o', os.path.join(self.get_dir(), 'src.cpp.o.js')], stdout=PIPE, stderr=self.stderr_redirect).communicate() self.do_run('x', '*1,0*', ['200', '1'], no_build=True) @@ -4560,12 +4825,6 @@ def process(filename): finally: del os.environ['EMCC_LEAVE_INPUTS_RAW'] - def get_build_dir(self): - ret = os.path.join(self.get_dir(), 'building') - if not os.path.exists(ret): - os.makedirs(ret) - return ret - def get_freetype(self): Settings.INIT_STACK = 1 # TODO: Investigate why this is necessary @@ -4588,6 +4847,10 @@ def process(filename): ) open(filename, 'w').write(src) ''' + + # Not needed for js, but useful for debugging + shutil.copyfile(path_from_root('tests', 'freetype', 'LiberationSansBold.ttf'), os.path.join(self.get_dir(), 'font.ttf')) + # Main self.do_run(open(path_from_root('tests', 'freetype', 'main.c'), 'r').read(), open(path_from_root('tests', 'freetype', 'ref.txt'), 'r').read(), @@ -4597,6 +4860,29 @@ def process(filename): post_build=post) #build_ll_hook=self.do_autodebug) + # github issue 324 + print '[issue 324]' + self.do_run(open(path_from_root('tests', 'freetype', 'main_2.c'), 'r').read(), + open(path_from_root('tests', 'freetype', 'ref_2.txt'), 'r').read(), + ['font.ttf', 'w', '32', '32', '25'], + libraries=self.get_freetype(), + includes=[path_from_root('tests', 'freetype', 'include')], + post_build=post) + + print '[issue 324 case 2]' + self.do_run(open(path_from_root('tests', 'freetype', 'main_3.c'), 'r').read(), + open(path_from_root('tests', 'freetype', 'ref_3.txt'), 'r').read(), + ['font.ttf', 'W', '32', '32', '0'], + libraries=self.get_freetype(), + includes=[path_from_root('tests', 'freetype', 'include')], + post_build=post) + + print '[issue 324 case 3]' + self.do_run('', + open(path_from_root('tests', 'freetype', 'ref_4.txt'), 'r').read(), + ['font.ttf', 'ea', '40', '32', '0'], + no_build=True) + def test_sqlite(self): # gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c if self.emcc_args is None: return self.skip('Very slow without ta2, and we would also need to include dlmalloc manually without emcc') @@ -4681,9 +4967,9 @@ def process(filename): src = open(filename, 'a') src.write( \'\'\' - FS.createDataFile('/', 'paper.pdf', eval(read('paper.pdf.js')), true, false); + FS.createDataFile('/', 'paper.pdf', eval(Module.read('paper.pdf.js')), true, false); run(); - print("Data: " + JSON.stringify(FS.root.contents['filename-1.ppm'].contents.map(function(x) { return unSign(x, 8) }))); + Module.print("Data: " + JSON.stringify(FS.root.contents['filename-1.ppm'].contents.map(function(x) { return unSign(x, 8) }))); \'\'\' ) src.close() @@ -4728,7 +5014,7 @@ def process(filename): )) ).replace( '// {{POST_RUN_ADDITIONS}}', - "print('Data: ' + JSON.stringify(FS.root.contents['image.raw'].contents));" + "Module.print('Data: ' + JSON.stringify(FS.root.contents['image.raw'].contents));" ) open(filename, 'w').write(src) ''' @@ -4963,7 +5249,7 @@ Block 0: ''', post_build=post1) void KEEPALIVE print_int(int x) { printf("%d\n", x); } void KEEPALIVE print_float(float x) { printf("%.2f\n", x); } void KEEPALIVE print_string(char *x) { printf("%s\n", x); } - int KEEPALIVE multi(int x, float y, int z, char *str) { puts(str); return (x+y)*z; } + int KEEPALIVE multi(int x, float y, int z, char *str) { if (x) puts(str); return (x+y)*z; } int * KEEPALIVE pointer(int *in) { printf("%d\n", *in); static int ret = 21; return &ret; } } @@ -4986,24 +5272,30 @@ def process(filename): src = \'\'\' var Module = { 'postRun': function() { - print('*'); + Module.print('*'); var ret; - ret = ccall('get_int', 'number'); print([typeof ret, ret]); - ret = ccall('get_float', 'number'); print([typeof ret, ret.toFixed(2)]); - ret = ccall('get_string', 'string'); print([typeof ret, ret]); - ret = ccall('print_int', null, ['number'], [12]); print(typeof ret); - ret = ccall('print_float', null, ['number'], [14.56]); print(typeof ret); - ret = ccall('print_string', null, ['string'], ["cheez"]); print(typeof ret); - ret = ccall('multi', 'number', ['number', 'number', 'number', 'string'], [2, 1.4, 3, 'more']); print([typeof ret, ret]); + ret = Module['ccall']('get_int', 'number'); Module.print([typeof ret, ret]); + ret = ccall('get_float', 'number'); Module.print([typeof ret, ret.toFixed(2)]); + ret = ccall('get_string', 'string'); Module.print([typeof ret, ret]); + ret = ccall('print_int', null, ['number'], [12]); Module.print(typeof ret); + ret = ccall('print_float', null, ['number'], [14.56]); Module.print(typeof ret); + ret = ccall('print_string', null, ['string'], ["cheez"]); Module.print(typeof ret); + ret = ccall('print_string', null, ['array'], [[97, 114, 114, 45, 97, 121, 0]]); Module.print(typeof ret); + ret = ccall('multi', 'number', ['number', 'number', 'number', 'string'], [2, 1.4, 3, 'more']); Module.print([typeof ret, ret]); var p = ccall('malloc', 'pointer', ['number'], [4]); setValue(p, 650, 'i32'); - ret = ccall('pointer', 'pointer', ['pointer'], [p]); print([typeof ret, getValue(ret, 'i32')]); - print('*'); + ret = ccall('pointer', 'pointer', ['pointer'], [p]); Module.print([typeof ret, getValue(ret, 'i32')]); + Module.print('*'); // part 2: cwrap - var multi = cwrap('multi', 'number', ['number', 'number', 'number', 'string']); - print(multi(2, 1.4, 3, 'atr')); - print(multi(8, 5.4, 4, 'bret')); - print('*'); + var multi = Module['cwrap']('multi', 'number', ['number', 'number', 'number', 'string']); + Module.print(multi(2, 1.4, 3, 'atr')); + Module.print(multi(8, 5.4, 4, 'bret')); + Module.print('*'); + // part 3: avoid stack explosion + for (var i = 0; i < TOTAL_STACK/60; i++) { + ccall('multi', 'number', ['number', 'number', 'number', 'string'], [0, 0, 0, '123456789012345678901234567890123456789012345678901234567890']); + } + Module.print('stack is ok.'); } }; \'\'\' + open(filename, 'r').read() @@ -5012,7 +5304,7 @@ def process(filename): Settings.EXPORTED_FUNCTIONS = ['_get_int', '_get_float', '_get_string', '_print_int', '_print_float', '_print_string', '_multi', '_pointer', '_malloc'] - self.do_run(src, '*\nnumber,5\nnumber,3.14\nstring,hello world\n12\nundefined\n14.56\nundefined\ncheez\nundefined\nmore\nnumber,10\n650\nnumber,21\n*\natr\n10\nbret\n53\n*\n', post_build=post) + self.do_run(src, '*\nnumber,5\nnumber,3.14\nstring,hello world\n12\nundefined\n14.56\nundefined\ncheez\nundefined\narr-ay\nundefined\nmore\nnumber,10\n650\nnumber,21\n*\natr\n10\nbret\n53\n*\nstack is ok.\n', post_build=post) def test_scriptaclass(self): header_filename = os.path.join(self.get_dir(), 'header.h') @@ -5043,9 +5335,9 @@ def process(filename): script_src = ''' var sme = Module._.ScriptMe.__new__(83); // malloc(sizeof(ScriptMe)), ScriptMe::ScriptMe(sme, 83) / new ScriptMe(83) (at addr sme) Module._.ScriptMe.mulVal(sme, 2); // ScriptMe::mulVal(sme, 2) sme.mulVal(2) - print('*' + Module._.ScriptMe.getVal(sme) + '*'); + Module.print('*' + Module._.ScriptMe.getVal(sme) + '*'); _free(sme); - print('*ok*'); + Module.print('*ok*'); ''' post = ''' def process(filename): @@ -5104,7 +5396,7 @@ def process(filename): open(header_filename, 'w').write(header) basename = os.path.join(self.get_dir(), 'bindingtest') - output = Popen([BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0] + output = Popen(['python', BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0] #print output assert 'Traceback' not in output, 'Failure in binding generation: ' + output @@ -5129,55 +5421,55 @@ def process(filename): script_src_2 = \'\'\' var sme = new Module.Parent(42); sme.mulVal(2); - print('*') - print(sme.getVal()); + Module.print('*') + Module.print(sme.getVal()); - print('c1'); + Module.print('c1'); var c1 = new Module.Child1(); - print(c1.getVal()); + Module.print(c1.getVal()); c1.mulVal(2); - print(c1.getVal()); - print(c1.getValSqr()); - print(c1.getValSqr(3)); - print(c1.getValTimes()); // default argument should be 1 - print(c1.getValTimes(2)); + Module.print(c1.getVal()); + Module.print(c1.getValSqr()); + Module.print(c1.getValSqr(3)); + Module.print(c1.getValTimes()); // default argument should be 1 + Module.print(c1.getValTimes(2)); - print('c1 v2'); + Module.print('c1 v2'); c1 = new Module.Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2 - print(c1.getVal()); + Module.print(c1.getVal()); c1.mulVal(2); - print(c1.getVal()); - print(c1.getValSqr()); - print(c1.getValSqr(3)); + Module.print(c1.getVal()); + Module.print(c1.getValSqr()); + Module.print(c1.getValSqr(3)); - print('c2') + Module.print('c2') var c2 = new Module.Child2(); - print(c2.getVal()); + Module.print(c2.getVal()); c2.mulVal(2); - print(c2.getVal()); - print(c2.getValCube()); + Module.print(c2.getVal()); + Module.print(c2.getValCube()); var succeeded; try { succeeded = 0; - print(c2.doSomethingSecret()); // should fail since private + Module.print(c2.doSomethingSecret()); // should fail since private succeeded = 1; } catch(e) {} - print(succeeded); + Module.print(succeeded); try { succeeded = 0; - print(c2.getValSqr()); // function from the other class + Module.print(c2.getValSqr()); // function from the other class succeeded = 1; } catch(e) {} - print(succeeded); + Module.print(succeeded); try { succeeded = 0; c2.getValCube(); // sanity succeeded = 1; } catch(e) {} - print(succeeded); + Module.print(succeeded); Module.Child2.prototype.printStatic(); // static calls go through the prototype @@ -5191,12 +5483,12 @@ def process(filename): Module.customizeVTable(c3, [{ original: Module.Child2.prototype.virtualFunc, replacement: function() { - print('*js virtualf replacement*'); + Module.print('*js virtualf replacement*'); } }, { original: Module.Child2.prototype.virtualFunc2, replacement: function() { - print('*js virtualf2 replacement*'); + Module.print('*js virtualf2 replacement*'); } }]); c3.virtualFunc(); @@ -5207,7 +5499,7 @@ def process(filename): Module.Child2.prototype.runVirtualFunc(c2); c2.virtualFunc2(); - print('*ok*'); + Module.print('*ok*'); \'\'\' src = open(filename, 'a') src.write(script_src_2 + '\\n') @@ -5256,6 +5548,48 @@ Child2:9 *ok* ''', post_build=[post2, post3]) + def test_scriptaclass_2(self): + header_filename = os.path.join(self.get_dir(), 'header.h') + header = ''' + #include <stdio.h> + #include <string.h> + + class StringUser { + char *s; + int i; + public: + StringUser(char *string, int integer) : s(strdup(string)), i(integer) {} + void Print(int anotherInteger, char *anotherString) { + printf("|%s|%d|%s|%d|\\n", s, i, anotherString, anotherInteger); + } + void CallOther(StringUser *fr) { fr->Print(i, s); } + }; + ''' + open(header_filename, 'w').write(header) + + basename = os.path.join(self.get_dir(), 'bindingtest') + output = Popen(['python', BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0] + #print output + assert 'Traceback' not in output, 'Failure in binding generation: ' + output + + src = ''' + #include "header.h" + + #include "bindingtest.cp |