diff options
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-x | tests/runner.py | 827 |
1 files changed, 619 insertions, 208 deletions
diff --git a/tests/runner.py b/tests/runner.py index 77bcc288..f6a2c8b1 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -72,12 +72,16 @@ except: # Core test runner class, shared between normal tests and benchmarks +checked_sanity = False + class RunnerCore(unittest.TestCase): save_dir = os.environ.get('EM_SAVE_DIR') save_JS = 0 stderr_redirect = STDOUT # This avoids cluttering the test runner output, which is stderr too, with compiler warnings etc. # Change this to None to get stderr reporting, for debugging purposes + env = {} + def skipme(self): # used by tests we ask on the commandline to be skipped, see right before call to unittest.main return self.skip('requested to be skipped') @@ -238,10 +242,7 @@ process(sys.argv[1]) os.remove(f + '.o') except: pass - compiler_flags = ['-emit-llvm'] - if not f.endswith('.c'): - compiler_flags = compiler_flags + ['-std=c++03'] - args = [Building.COMPILER] + compiler_flags + COMPILER_OPTS + Building.COMPILER_TEST_OPTS + \ + args = [PYTHON, EMCC] + Building.COMPILER_TEST_OPTS + \ ['-I', dirname, '-I', os.path.join(dirname, 'include')] + \ map(lambda include: '-I' + include, includes) + \ ['-c', f, '-o', f + '.o'] @@ -290,7 +291,7 @@ process(sys.argv[1]) out = open(stdout, 'r').read() err = open(stderr, 'r').read() if engine == SPIDERMONKEY_ENGINE and Settings.ASM_JS: - if 'Successfully compiled asm.js code' in err and 'asm.js link error' not in err: + if 'uccessfully compiled asm.js code' in err and 'asm.js link error' not in err: print >> sys.stderr, "[was asm.js'ified]" elif 'asm.js' in err: # if no asm.js error, then not an odin build raise Exception("did NOT asm.js'ify") @@ -358,13 +359,14 @@ process(sys.argv[1]) build_dir = self.get_build_dir() output_dir = self.get_dir() - cache_name = name + cache_name_extra + cache_name = name + cache_name_extra + (self.env.get('EMCC_LLVM_TARGET') or '') + if self.library_cache is not None: if cache and self.library_cache.get(cache_name): print >> sys.stderr, '<load %s from cache> ' % cache_name, generated_libs = [] for basename, contents in self.library_cache[cache_name]: - bc_file = os.path.join(build_dir, basename) + bc_file = os.path.join(build_dir, cache_name + '_' + basename) f = open(bc_file, 'wb') f.write(contents) f.close() @@ -411,7 +413,7 @@ process(sys.argv[1]) int suppInt = 76; ''' - supp_name = os.path.join(self.get_dir(), 'supp.c') + supp_name = os.path.join(self.get_dir(), 'supp.cpp') open(supp_name, 'w').write(supp) main = r''' @@ -445,6 +447,8 @@ process(sys.argv[1]) sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv) +test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm2g', 'asm2x86', 's_0_0', 's_0_1', 's_1_0', 's_1_1'] + test_index = 0 if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'browser' not in str(sys.argv): @@ -452,10 +456,10 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows print "Running Emscripten tests..." - if len(sys.argv) == 2 and 'ALL.' in sys.argv[1]: + if len(sys.argv) == 2 and sys.argv[1].startswith('ALL.'): ignore, test = sys.argv[1].split('.') print 'Running all test modes on test "%s"' % test - sys.argv = [sys.argv[0], 'default.'+test, 'o1.'+test, 'o2.'+test, 'asm1.'+test, 'asm2.'+test, 'asm2g.'+test, 's_0_0.'+test, 's_0_1.'+test, 's_1_0.'+test, 's_1_1.'+test] + sys.argv = [sys.argv[0]] + map(lambda mode: mode+'.'+test, test_modes) class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline ## Does a complete test - builds, runs, checks output, etc. @@ -506,6 +510,9 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows output_nicerizer=output_nicerizer, post_build=None) # post_build was already done in ll_to_js, this do_run call is just to test the output + def is_le32(self): + return not ('i386-pc-linux-gnu' in COMPILER_OPTS or self.env.get('EMCC_LLVM_TARGET') == 'i386-pc-linux-gnu') + def test_hello_world(self): src = ''' #include <stdio.h> @@ -1133,10 +1140,11 @@ m_divisor is 1091269979 if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') src = r''' + #include <stdint.h> #include <stdio.h> int main(int argc, char ** argv){ int y=-133; - __int64_t x= ((__int64_t)((short)(y)))*(100 + argc); + int64_t x= ((int64_t)((short)(y)))*(100 + argc); if(x>0) printf(">0\n"); else @@ -1171,6 +1179,53 @@ m_divisor is 1091269979 ''' self.do_run(src, 'Succeeded!') + def test_i64_varargs(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') + + src = r''' + #include <stdio.h> + #include <stdint.h> + #include <stdarg.h> + + int64_t ccv_cache_generate_signature(char *msg, int len, int64_t sig_start, ...) { + if (sig_start < 10123) + printf("%s\n", msg+len); + va_list v; + va_start(v, sig_start); + if (sig_start > 1413) + printf("%d\n", va_arg(v, int)); + else + printf("nada\n"); + va_end(v); + return len*sig_start*(msg[0]+1); + } + + int main(int argc, char **argv) + { + for (int i = 0; i < argc; i++) { + int64_t x; + if (i % 123123 == 0) + x = ccv_cache_generate_signature(argv[i], i+2, (int64_t)argc*argc, 54.111); + else + x = ccv_cache_generate_signature(argv[i], i+2, (int64_t)argc*argc, 13); + printf("%lld\n", x); + } + }; + ''' + self.do_run(src, '''in/this.program +nada +1536 +a +nada +5760 +fl +nada +6592 +sdfasdfasdf +nada +7840 +''', 'waka fleefl asdfasdfasdfasdf'.split(' ')) + def test_i32_mul_precise(self): if self.emcc_args == None: return self.skip('needs ta2') @@ -1499,7 +1554,11 @@ Succeeded! ''' # TODO: A version of this with int64s as well - self.do_run(src, '*12 : 1 : 12\n328157500735811.0,23,416012775903557.0,99\n') + + if self.is_le32(): + return self.skip('LLVM marks the reads of s as fully aligned, making this test invalid') + else: + self.do_run(src, '*12 : 1 : 12\n328157500735811.0,23,416012775903557.0,99\n') return # TODO: continue to the next part here @@ -1533,6 +1592,62 @@ Succeeded! except Exception, e: assert 'must be aligned' in str(e), e # expected to fail without emulation + def test_align64(self): + src = r''' + #include <stdio.h> + + // inspired by poppler + + enum Type { + A = 10, + B = 20 + }; + + struct Object { + Type type; + union { + int intg; + double real; + char *name; + }; + }; + + struct Principal { + double x; + Object a; + double y; + }; + + int main(int argc, char **argv) + { + int base = argc-1; + Object *o = NULL; + printf("%d,%d\n", sizeof(Object), sizeof(Principal)); + printf("%d,%d,%d,%d\n", (int)&o[base].type, (int)&o[base].intg, (int)&o[base].real, (int)&o[base].name); + printf("%d,%d,%d,%d\n", (int)&o[base+1].type, (int)&o[base+1].intg, (int)&o[base+1].real, (int)&o[base+1].name); + Principal p, q; + p.x = p.y = q.x = q.y = 0; + p.a.type = A; + p.a.real = 123.456; + *(&q.a) = p.a; + printf("%.2f,%d,%.2f,%.2f : %.2f,%d,%.2f,%.2f\n", p.x, p.a.type, p.a.real, p.y, q.x, q.a.type, q.a.real, q.y); + return 0; + } + ''' + + if self.is_le32(): + self.do_run(src, '''16,32 +0,8,8,8 +16,24,24,24 +0.00,10,123.46,0.00 : 0.00,10,123.46,0.00 +''') + else: + self.do_run(src, '''12,28 +0,4,4,4 +12,16,16,16 +0.00,10,123.46,0.00 : 0.00,10,123.46,0.00 +''') + def test_unsigned(self): Settings.CORRECT_SIGNS = 1 # We test for exactly this sort of thing here Settings.CHECK_SIGNS = 0 @@ -1753,10 +1868,10 @@ Succeeded! int main() { printf("*%.2f,%.2f,%d", M_PI, -M_PI, (1/0.0) > 1e300); // could end up as infinity, or just a very very big number - printf(",%d", finite(NAN) != 0); - printf(",%d", finite(INFINITY) != 0); - printf(",%d", finite(-INFINITY) != 0); - printf(",%d", finite(12.3) != 0); + printf(",%d", isfinite(NAN) != 0); + printf(",%d", isfinite(INFINITY) != 0); + printf(",%d", isfinite(-INFINITY) != 0); + printf(",%d", isfinite(12.3) != 0); printf(",%d", isinf(NAN) != 0); printf(",%d", isinf(INFINITY) != 0); printf(",%d", isinf(-INFINITY) != 0); @@ -1985,8 +2100,9 @@ Succeeded! char *two = "fa la sa ho fi FI FO FUM WHEN WHERE WHY HOW WHO"; char three[1000]; strcpy(three, &one[argc*2]); - strcat(three, &two[argc*3]); + char *four = strcat(three, &two[argc*3]); printf("cat |%s|\\n", three); + printf("returned |%s|\\n", four); } return 0; @@ -1996,7 +2112,8 @@ Succeeded! print named Settings.NAMED_GLOBALS = named self.do_run(src, '''4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\nwaka ....e 1 O...wo 2 T................................ -cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too', '74']) +cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO| +returned |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too', '74']) if self.emcc_args == []: gen = open(self.in_dir('src.cpp.o.js')).read() assert ('var __str1;' in gen) == named @@ -2335,28 +2452,34 @@ cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too' static jmp_buf buf; void second(void) { - printf("second\n"); // prints - longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1 + printf("second\n"); + longjmp(buf,-1); } void first(void) { - second(); - printf("first\n"); // does not print + printf("first\n"); // prints + longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1 } int main() { volatile int x = 0; - if ( ! setjmp(buf) ) { + int jmpval = setjmp(buf); + if (!jmpval) { + x++; // should be properly restored once longjmp jumps back + first(); // when executed, setjmp returns 1 + printf("skipped\n"); // does not print + } else if (jmpval == 1) { // when first() jumps back, setjmp returns 1 + printf("result: %d %d\n", x, jmpval); // prints x++; - first(); // when executed, setjmp returns 0 - } else { // when longjmp jumps back, setjmp returns 1 - printf("main: %d\n", x); // prints + second(); // when executed, setjmp returns -1 + } else if (jmpval == -1) { // when second() jumps back, setjmp returns -1 + printf("result: %d %d\n", x, jmpval); // prints } return 0; } ''' - self.do_run(src, 'second\nmain: 1\n') + self.do_run(src, 'first\nresult: 1 1\nsecond\nresult: 2 -1') def test_longjmp2(self): src = r''' @@ -2630,6 +2753,37 @@ back 12 ''') + def test_longjmp_exc(self): + src = r''' + #include <stdlib.h> + #include <stdio.h> + #include <setjmp.h> + #include <emscripten.h> + + jmp_buf abortframe; + + void dostuff(int a) { + printf("pre\n"); + if (a != 42) emscripten_run_script("waka_waka()"); // this should fail, and never reach "never" + printf("never\n"); + + if (a == 100) { + longjmp (abortframe, -1); + } + + if (setjmp(abortframe)) { + printf("got 100"); + } + } + + int main(int argc, char **argv) { + dostuff(argc); + exit(1); + return 1; + } + ''' + self.do_run(src, 'waka_waka'); + def test_setjmp_many(self): src = r''' #include <stdio.h> @@ -3035,7 +3189,7 @@ Exiting setjmp function, level: 0, prev_jmp: -1 Settings.SAFE_HEAP = 1 - for addr in ['0', '7', 'new D2()']: + for addr in ['0', 'new D2()']: print addr src = r''' #include <stdio.h> @@ -3210,10 +3364,10 @@ Exiting setjmp function, level: 0, prev_jmp: -1 #include <stdio.h> int - main(void) { - float (*fn)(float) = &sqrtf; - float (*fn2)(float) = &fabsf; - float (*fn3)(float) = &erff; + main(int argc, char **argv) { + float (*fn)(float) = argc != 12 ? &sqrtf : &fabsf; + float (*fn2)(float) = argc != 13 ? &fabsf : &sqrtf; + float (*fn3)(float) = argc != 14 ? &erff : &fabsf; printf("fn2(-5) = %d, fn(10) = %.2f, erf(10) = %.2f\\n", (int)fn2(-5), fn(10), fn3(10)); return 0; } @@ -3240,6 +3394,36 @@ Exiting setjmp function, level: 0, prev_jmp: -1 ''' self.do_run(src, '*0x1*') + def test_funcptr_namecollide(self): + src = r''' + #include <stdio.h> + + void do_call(void (*puts)(const char *), const char *str); + + void do_print(const char *str) { + if (!str) do_call(NULL, "delusion"); + if ((int)str == -1) do_print(str+10); + puts("===="); + puts(str); + puts("===="); + } + + void do_call(void (*puts)(const char *), const char *str) { + if (!str) do_print("confusion"); + if ((int)str == -1) do_call(NULL, str-10); + (*puts)(str); + } + + int main(int argc, char **argv) + { + for (int i = 0; i < argc; i++) { + do_call(i != 10 ? do_print : NULL, i != 15 ? "waka waka" : NULL); + } + return 0; + } + ''' + self.do_run(src, 'waka', force_c=True) + def test_emptyclass(self): if self.emcc_args is None: return self.skip('requires emcc') src = ''' @@ -3273,6 +3457,35 @@ Exiting setjmp function, level: 0, prev_jmp: -1 ''' self.do_run(src, 'z:1*', force_c=True) + def test_rename(self): + src = ''' + #include <stdio.h> + #include <sys/stat.h> + #include <sys/types.h> + #include <assert.h> + + int main() { + int err; + FILE* fid; + + err = mkdir("/foo", 0777); + err = mkdir("/bar", 0777); + fid = fopen("/foo/bar", "w+"); + fclose(fid); + + err = rename("/foo/bar", "/foo/bar2"); + printf("%d\\n", err); + + err = rename("/foo", "/foo/foo"); + printf("%d\\n", err); + + err = rename("/foo", "/bar/foo"); + printf("%d\\n", err); + return 0; + } + ''' + self.do_run(src, '0\n-1\n0\n', force_c=True) + def test_alloca_stack(self): if self.emcc_args is None: return # too slow in other modes @@ -3410,7 +3623,7 @@ Exiting setjmp function, level: 0, prev_jmp: -1 [] [][][] [] -------------------------------- -''', ['1'], force_c=True) +''', ['2'], force_c=True) def test_array2(self): src = ''' @@ -3618,7 +3831,10 @@ Exiting setjmp function, level: 0, prev_jmp: -1 # Compressed memory. Note that sizeof() does give the fat sizes, however! self.do_run(src, '*0,0,0,1,2,3,4,5*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*12,20,5*') else: - self.do_run(src, '*0,0,0,4,8,12,16,20*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*12,20,20*') + if self.is_le32(): + self.do_run(src, '*0,0,0,4,8,16,20,24*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*16,24,24*') + else: + self.do_run(src, '*0,0,0,4,8,12,16,20*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*12,20,20*') def test_ptrtoint(self): if self.emcc_args is None: return self.skip('requires emcc') @@ -3985,7 +4201,7 @@ def process(filename): // Try it with copying va_list tempva; - __va_copy(tempva, v); + va_copy(tempva, v); vsnprintf(d, 20, s, tempva); puts(d); @@ -4027,7 +4243,7 @@ def process(filename): int maxxi = getMaxi(6, 2, 5, 21, 4, -10, 19); printf("maxxi:%d*\\n", maxxi); - double maxxD = getMaxD(6, (double)2.1, (double)5.1, (double)22.1, (double)4.1, (double)-10.1, (double)19.1); + double maxxD = getMaxD(6, (double)2.1, (double)5.1, (double)22.1, (double)4.1, (double)-10.1, (double)19.1, (double)2); printf("maxxD:%.2f*\\n", (float)maxxD); // And, as a function pointer @@ -4041,6 +4257,7 @@ def process(filename): def test_varargs_byval(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip('FIXME: Add support for this') + if self.is_le32(): return self.skip('clang cannot compile this code with that target yet') src = r''' #include <stdio.h> @@ -4213,9 +4430,13 @@ The current type of b is: 9 # 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' + if 'i386-pc-linux-gnu' in COMPILER_OPTS: + assert 'Casting a function pointer type to a potentially incompatible one' in output[1], 'Missing expected warning' + else: + print >> sys.stderr, 'skipping C/C++ conventions warning check, since not i386-pc-linux-gnu' def test_stdlibs(self): if self.emcc_args is None: return self.skip('requires emcc') @@ -4390,10 +4611,10 @@ The current type of b is: 9 self.do_run(src, 'ok\n') def test_statics(self): - # static initializers save i16 but load i8 for some reason + # static initializers save i16 but load i8 for some reason (or i64 and load i8) if Settings.SAFE_HEAP: Settings.SAFE_HEAP = 3 - Settings.SAFE_HEAP_LINES = ['src.cpp:19', 'src.cpp:26'] + Settings.SAFE_HEAP_LINES = ['src.cpp:19', 'src.cpp:26', 'src.cpp:28'] src = ''' #include <stdio.h> @@ -4881,6 +5102,7 @@ The current type of b is: 9 self.do_run(src, '*16,0,4,8,8,12|20,0,4,4,8,12,12,16|24,0,20,0,4,4,8,12,12,16*\n*0,0,0,1,2,64,68,69,72*\n*2*') def test_runtimelink(self): + return self.skip('shared libs are deprecated') if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize printf into puts in the parent, and the child will still look for puts') if Settings.ASM_JS: return self.skip('asm does not support runtime linking') @@ -4891,14 +5113,15 @@ The current type of b is: 9 Settings.BUILD_AS_SHARED_LIB = 2 Settings.NAMED_GLOBALS = 1 - self.build(supp, self.get_dir(), self.in_dir('supp.c')) - shutil.move(self.in_dir('supp.c.o.js'), self.in_dir('liblib.so')) + self.build(supp, self.get_dir(), self.in_dir('supp.cpp')) + shutil.move(self.in_dir('supp.cpp.o.js'), self.in_dir('liblib.so')) Settings.BUILD_AS_SHARED_LIB = 0 Settings.RUNTIME_LINKED_LIBS = ['liblib.so']; self.do_run(main, 'supp: 54,2\nmain: 56\nsupp see: 543\nmain see: 76\nok.') def test_dlfcn_basic(self): + return self.skip('shared libs are deprecated') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') Settings.NAMED_GLOBALS = 1 @@ -4953,6 +5176,7 @@ def process(filename): post_build=add_pre_run_and_checks) def test_dlfcn_qsort(self): + return self.skip('shared libs are deprecated') if self.emcc_args is None: return self.skip('requires emcc') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') @@ -5049,6 +5273,7 @@ def process(filename): post_build=add_pre_run_and_checks) def test_dlfcn_data_and_fptr(self): + return self.skip('shared libs are deprecated') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func') @@ -5153,6 +5378,7 @@ def process(filename): post_build=add_pre_run_and_checks) def test_dlfcn_alias(self): + return self.skip('shared libs are deprecated') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') Settings.LINKABLE = 1 @@ -5210,6 +5436,7 @@ def process(filename): Settings.INCLUDE_FULL_LIBRARY = 0 def test_dlfcn_varargs(self): + return self.skip('shared libs are deprecated') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') Settings.LINKABLE = 1 @@ -5475,7 +5702,7 @@ at function.:blag open(path_from_root('tests', 'printf', 'output_i64_1.txt'), 'r').read()] self.do_run(src, expected) - def test_printf_types(self): + def test_printf_2(self): src = r''' #include <stdio.h> @@ -5488,11 +5715,12 @@ at function.:blag double d = 6.6; printf("%c,%hd,%d,%lld,%.1f,%.1llf\n", c, s, i, l, f, d); + printf("%#x,%#x\n", 1, 0); return 0; } ''' - self.do_run(src, '1,2,3,4,5.5,6.6\n') + self.do_run(src, '1,2,3,4,5.5,6.6\n0x1,0\n') def test_vprintf(self): src = r''' @@ -5896,10 +6124,45 @@ Pass: 0.000012 0.000012''') ''' self.do_run(src, '''0:173,16 1:16,173 2:183,173 3:17,287 4:98,123''') + def test_sscanf_other_whitespace(self): + Settings.SAFE_HEAP = 0 # use i16s in printf + + src = r''' + #include<stdio.h> + + int main() { + short int x; + short int y; + + const char* buffer[] = { + "\t2\t3\t", /* TAB - horizontal tab */ + "\t\t5\t\t7\t\t", + "\n11\n13\n", /* LF - line feed */ + "\n\n17\n\n19\n\n", + "\v23\v29\v", /* VT - vertical tab */ + "\v\v31\v\v37\v\v", + "\f41\f43\f", /* FF - form feed */ + "\f\f47\f\f53\f\f", + "\r59\r61\r", /* CR - carrage return */ + "\r\r67\r\r71\r\r" + }; + + for (int i=0; i<10; ++i) { + x = 0; y = 0; + sscanf(buffer[i], " %d %d ", &x, &y); + printf("%d, %d, ", x, y); + } + + return 0; + } + ''' + self.do_run(src, '''2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, ''') + def test_sscanf_3(self): # i64 if not Settings.USE_TYPED_ARRAYS == 2: return self.skip('64-bit sscanf only supported in ta2') src = r''' + #include <stdint.h> #include <stdio.h> int main(){ @@ -5959,6 +6222,7 @@ Pass: 0.000012 0.000012''') if Settings.USE_TYPED_ARRAYS != 2: return self.skip("need ta2 for full i64") src = r''' + #include <stdint.h> #include <stdio.h> int main(){ @@ -6105,6 +6369,31 @@ def process(filename): self.emcc_args += ['--embed-file', 'eol.txt'] self.do_run(src, 'SUCCESS\n') + def test_fscanf(self): + if self.emcc_args is None: return self.skip('requires emcc') + open(os.path.join(self.get_dir(), 'three_numbers.txt'), 'w').write('''-1 0.1 -.1''') + src = r''' + #include <stdio.h> + #include <assert.h> + #include <float.h> + int main() + { + float x = FLT_MAX, y = FLT_MAX, z = FLT_MAX; + + FILE* fp = fopen("three_numbers.txt", "r"); + if (fp) { + int match = fscanf(fp, " %f %f %f ", &x, &y, &z); + printf("match = %d\n", match); + printf("x = %0.1f, y = %0.1f, z = %0.1f\n", x, y, z); + } else { + printf("failed to open three_numbers.txt\n"); + } + return 0; + } + ''' + self.emcc_args += ['--embed-file', 'three_numbers.txt'] + self.do_run(src, 'match = 3\nx = -1.0, y = 0.1, z = -0.1\n') + def test_folders(self): add_pre_run = ''' def process(filename): @@ -7245,6 +7534,10 @@ extern "C" { src = open(path_from_root('tests', 'fasta.cpp'), 'r').read() self.do_run(src, j, [str(i)], lambda x, err: x.replace('\n', '*'), no_build=i>1) + def test_whets(self): + if not Settings.ASM_JS: return self.skip('mainly a test for asm validation here') + self.do_run(open(path_from_root('tests', 'whets.cpp')).read(), 'Single Precision C Whetstone Benchmark') + def test_dlmalloc(self): if self.emcc_args is None: self.emcc_args = [] # dlmalloc auto-inclusion is only done if we use emcc @@ -7297,7 +7590,7 @@ operator new(size_t size) self.do_run(src, 'new 4!\n*1,0*') def test_dlmalloc_partial_2(self): - if self.emcc_args is None or 'SAFE_HEAP' in str(self.emcc_args): return self.skip('only emcc will link in dlmalloc, and we do unsafe stuff') + if self.emcc_args is None or 'SAFE_HEAP' in str(self.emcc_args) or 'CHECK_HEAP_ALIGN' in str(self.emcc_args): return self.skip('only emcc will link in dlmalloc, and we do unsafe stuff') # present part of the symbols of dlmalloc, not all. malloc is harder to link than new which is weak. src = r''' #include <stdio.h> @@ -7526,7 +7819,7 @@ void*:16 def test_cubescript(self): if self.emcc_args is None: return self.skip('requires emcc') - if self.emcc_args is not None and '-O2' in self.emcc_args: + if self.run_name == 'o2': self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage Building.COMPILER_TEST_OPTS = [] # remove -g, so we have one test without it by default @@ -7541,6 +7834,23 @@ void*:16 self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp') + assert 'asm2g' in test_modes + if self.run_name == 'asm2g': + results = {} + original = open('src.cpp.o.js').read() + results[Settings.ALIASING_FUNCTION_POINTERS] = len(original) + Settings.ALIASING_FUNCTION_POINTERS = 1 - Settings.ALIASING_FUNCTION_POINTERS + self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp') + final = open('src.cpp.o.js').read() + results[Settings.ALIASING_FUNCTION_POINTERS] = len(final) + open('original.js', 'w').write(original) + print results + assert results[1] < 0.99*results[0] + assert ' & 3]()' in original, 'small function table exists' + assert ' & 3]()' not in final, 'small function table does not exist' + assert ' & 255]()' not in original, 'big function table does not exist' + assert ' & 255]()' in final, 'big function table exists' + def test_gcc_unmangler(self): Settings.NAMED_GLOBALS = 1 # test coverage for this @@ -7560,20 +7870,14 @@ void*:16 def test_lua(self): if self.emcc_args is None: return self.skip('requires emcc') - if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work') - # Overflows in luaS_newlstr hash loop - if self.emcc_args is None: Settings.SAFE_HEAP = 0 # Has various warnings, with copied HEAP_HISTORY values (fixed if we copy 'null' as the type) - Settings.CORRECT_OVERFLOWS = 1 - Settings.CHECK_OVERFLOWS = 0 - Settings.CORRECT_SIGNS = 1 # Not sure why, but needed - - self.do_ll_run(path_from_root('tests', 'lua', 'lua.ll'), - 'hello lua world!\n17\n1\n2\n3\n4\n7', - args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''], - output_nicerizer=lambda string, err: (string + err).replace('\n\n', '\n').replace('\n\n', '\n'), - extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h']) + self.do_run('', + 'hello lua world!\n17\n1\n2\n3\n4\n7', + args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''], + libraries=self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None), + includes=[path_from_root('tests', 'lua')], + output_nicerizer=lambda string, err: (string + err).replace('\n\n', '\n').replace('\n\n', '\n')) def get_freetype(self): Settings.DEAD_FUNCTIONS += ['_inflateEnd', '_inflate', '_inflateReset', '_inflateInit2_'] @@ -7665,6 +7969,9 @@ def process(filename): force_c=True) def test_zlib(self): + if Settings.ASM_JS: + self.banned_js_engines = [NODE_JS] # TODO investigate + if self.emcc_args is not None and '-O2' in self.emcc_args: self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage @@ -7689,15 +7996,29 @@ def process(filename): Settings.SAFE_HEAP_LINES = ['btVoronoiSimplexSolver.h:40', 'btVoronoiSimplexSolver.h:41', 'btVoronoiSimplexSolver.h:42', 'btVoronoiSimplexSolver.h:43'] - self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(), - [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings - open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read(), - open(path_from_root('tests', 'bullet', 'output3.txt'), 'r').read()], - libraries=self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'), - os.path.join('src', '.libs', 'libBulletCollision.a'), - os.path.join('src', '.libs', 'libLinearMath.a')], - configure_args=['--disable-demos','--disable-dependency-tracking']), - includes=[path_from_root('tests', 'bullet', 'src')]) + def test(): + self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(), + [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings + open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read(), + open(path_from_root('tests', 'bullet', 'output3.txt'), 'r').read()], + libraries=self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'), + os.path.join('src', '.libs', 'libBulletCollision.a'), + os.path.join('src', '.libs', 'libLinearMath.a')], + configure_args=['--disable-demos','--disable-dependency-tracking']), + includes=[path_from_root('tests', 'bullet', 'src')]) + test() + + assert 'asm2g' in test_modes + if self.run_name == 'asm2g': + # Test forced alignment + print >> sys.stderr, 'testing FORCE_ALIGNED_MEMORY' + old = open('src.cpp.o.js').read() + Settings.FORCE_ALIGNED_MEMORY = 1 + test() + new = open('src.cpp.o.js').read() + print len(old), len(new), old.count('tempBigInt'), new.count('tempBigInt') + assert len(old) > len(new) + assert old.count('tempBigInt') > new.count('tempBigInt') def test_poppler(self): if self.emcc_args is None: return self.skip('very slow, we only do this in emcc runs') @@ -7878,14 +8199,14 @@ def process(filename): if self.emcc_args is None: return self.skip('requires emcc') if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work') - # Overflows in string_hash - Settings.CORRECT_OVERFLOWS = 1 - Settings.CHECK_OVERFLOWS = 0 - if self.emcc_args is None: Settings.SAFE_HEAP = 0 # Has bitfields which are false positives. Also the PyFloat_Init tries to detect endianness. - Settings.CORRECT_SIGNS = 1 # Not sure why, but needed - Settings.EXPORTED_FUNCTIONS += ['_PyRun_SimpleStringFlags'] # for the demo + #Settings.EXPORTED_FUNCTIONS += ['_PyRun_SimpleStringFlags'] # for the demo + + if self.is_le32(): + bitcode = path_from_root('tests', 'python', 'python.le32.bc') + else: + bitcode = path_from_root('tests', 'python', 'python.small.bc') - self.do_ll_run(path_from_root('tests', 'python', 'python.small.bc'), + self.do_ll_run(bitcode, 'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000', args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47''']) @@ -8319,6 +8640,10 @@ def process(filename): self.do_run(src, '''Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.''') generated = open('src.cpp.o.js').read() assert 'jsCall' not in generated + Settings.RESERVED_FUNCTION_POINTERS = 1 + + Settings.ALIASING_FUNCTION_POINTERS = 1 - Settings.ALIASING_FUNCTION_POINTERS # flip the test + self.do_run(src, '''Hello 7 from JS!''') def test_scriptaclass(self): if self.emcc_args is None: return self.skip('requires emcc') @@ -8498,7 +8823,7 @@ def process(filename): Module.Child2.prototype.runVirtualFunc(c2); c2.virtualFunc2(); -''' + ('' if Settings.ASM_JS else ''' +''' + (''' // extend the class from JS var c3 = new Module.Child2; Module.customizeVTable(c3, [{ @@ -8528,6 +8853,8 @@ def process(filename): src.close() ''' + Settings.RESERVED_FUNCTION_POINTERS = 20 + self.do_run(src, '''* 84 c1 @@ -8558,7 +8885,7 @@ Child2:9 *static* *virtualf* *virtualf* -*virtualf2*''' + ('' if Settings.ASM_JS else ''' +*virtualf2*''' + (''' Parent:9 Child2:9 *js virtualf replacement* @@ -9121,15 +9448,31 @@ finalizing 3 (global == 0) ''') # Generate tests for everything - def make_run(fullname, name=-1, compiler=-1, llvm_opts=0, embetter=0, quantum_size=0, typed_arrays=0, emcc_args=None): + def make_run(fullname, name=-1, compiler=-1, llvm_opts=0, embetter=0, quantum_size=0, typed_arrays=0, emcc_args=None, env='{}'): exec(''' class %s(T): + run_name = '%s' + env = %s + def tearDown(self): super(%s, self).tearDown() + for k, v in self.env.iteritems(): + del os.environ[k] + def setUp(self): super(%s, self).setUp() + for k, v in self.env.iteritems(): + assert k not in os.environ, k + ' should not be in environment' + os.environ[k] = v + + global checked_sanity + if not checked_sanity: + print '(checking sanity from test runner)' # do this after we set env stuff + check_sanity(force=True) + checked_sanity = True + Building.COMPILER_TEST_OPTS = ['-g'] os.chdir(self.get_dir()) # Ensure the directory exists and go there Building.COMPILER = %r @@ -9173,7 +9516,7 @@ class %s(T): Building.pick_llvm_opts(3) TT = %s -''' % (fullname, fullname, fullname, compiler, str(emcc_args), llvm_opts, embetter, quantum_size, typed_arrays, fullname)) +''' % (fullname, fullname, env, fullname, fullname, compiler, str(emcc_args), llvm_opts, embetter, quantum_size, typed_arrays, fullname)) return TT # Make one run with the defaults @@ -9186,9 +9529,10 @@ TT = %s exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0", "-s", "JS_CHUNK_SIZE=1024"])') # asm.js - exec('asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1"])') + exec('asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1", "-s", "CHECK_HEAP_ALIGN=1"])') exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2"])') exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1"])') + exec('''asm2x86 = make_run("asm2x86", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "CHECK_HEAP_ALIGN=1"], env='{"EMCC_LLVM_TARGET": "i386-pc-linux-gnu"}')''') # Make custom runs with various options for compiler, quantum, embetter, typed_arrays, llvm_opts in [ @@ -9255,7 +9599,7 @@ Options that are modified or new in %s include: self.assertContained('error: invalid preprocessing directive', |