diff options
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-x | tests/runner.py | 2150 |
1 files changed, 1796 insertions, 354 deletions
diff --git a/tests/runner.py b/tests/runner.py index 9dc7ab32..d10a7c40 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -14,9 +14,39 @@ 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, threading, platform, BaseHTTPServer, multiprocessing +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 __rootpath__ = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -49,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 @@ -63,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): @@ -135,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(''' @@ -163,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) @@ -224,12 +259,14 @@ process(sys.argv[1]) def run_native(self, filename, args): Popen([filename+'.native'] + args, stdout=PIPE).communicate()[0] - def assertIdentical(self, x, y): - if x != y: - raise Exception("Expected to have '%s' == '%s', diff:\n\n%s" % ( - limit_size(x), limit_size(y), - limit_size(''.join([a.rstrip()+'\n' for a in difflib.unified_diff(x.split('\n'), y.split('\n'), fromfile='expected', tofile='actual')])) - )) + def assertIdentical(self, values, y): + if type(values) not in [list, tuple]: values = [values] + for x in values: + if x == y: return # success + raise Exception("Expected to have '%s' == '%s', diff:\n\n%s" % ( + limit_size(values[0]), limit_size(y), + limit_size(''.join([a.rstrip()+'\n' for a in difflib.unified_diff(x.split('\n'), y.split('\n'), fromfile='expected', tofile='actual')])) + )) def assertContained(self, values, string, additional_info=''): if type(values) not in [list, tuple]: values = [values] @@ -253,7 +290,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() @@ -275,12 +318,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..." @@ -306,7 +357,6 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines) if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and settings.py and the paths therein.' % EM_CONFIG) for engine in js_engines: - engine = filter(lambda arg: arg != '-n', engine) # SpiderMonkey issue 716255 js_output = self.run_generated_code(engine, filename + '.o.js', args) if output_nicerizer is not None: js_output = output_nicerizer(js_output) @@ -569,13 +619,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' + @@ -801,6 +851,155 @@ m_divisor is 1091269979 ''' 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_i64_zextneg(self): + 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[]) + { + uint8_t byte = 0x80; + uint16_t two = byte; + uint32_t four = byte; + uint64_t eight = byte; + + printf("value: %d,%d,%d,%lld.\n", byte, two, four, eight); + + return 0; + } + ''' + self.do_run(src, 'value: 128,128,128,128.') + + def test_i64_7z(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') + + src = r''' + #include <stdint.h> + #include <stdio.h> + uint64_t a, b; + int main(int argc, char *argv[]) + { + a = argc; + b = argv[1][0]; + if (a > a + b || a > a + b + 1) { + printf("one %lld, %lld", a, b); + return 0; + } + printf("zero %lld, %lld", a, b); + return 0; + } + ''' + self.do_run(src, 'zero 2, 104', ['hallo']) + + def test_i16_emcc_intrinsic(self): + Settings.CORRECT_SIGNS = 1 # Relevant to this test + + src = r''' + #include <stdio.h> + + int test(unsigned short a, unsigned short b) { + unsigned short result = a; + result += b; + if (result < b) printf("C!"); + return result; + } + + int main(void) { + printf(",%d,", test(0, 0)); + printf(",%d,", test(1, 1)); + printf(",%d,", test(65535, 1)); + printf(",%d,", test(1, 65535)); + printf(",%d,", test(32768, 32767)); + printf(",%d,", test(32768, 32768)); + return 0; + } + ''' + self.do_run(src, ',0,,2,C!,0,C!,0,,65535,C!,0,') + + def test_sha1(self): + if self.emcc_args == None: return self.skip('needs ta2') + + self.do_run(open(path_from_root('tests', 'sha1.c')).read(), 'SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6') + + def test_cube2md5(self): + if self.emcc_args == None: return self.skip('needs emcc') + self.emcc_args += ['--embed-file', 'cube2md5.txt'] + shutil.copyfile(path_from_root('tests', 'cube2md5.txt'), os.path.join(self.get_dir(), 'cube2md5.txt')) + self.do_run(open(path_from_root('tests', 'cube2md5.cpp')).read(), open(path_from_root('tests', 'cube2md5.ok')).read()) + + 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') @@ -1011,6 +1210,35 @@ m_divisor is 1091269979 ''' self.do_run(src, '*1,10,10.5,1,1.2340,0.00*') + def test_globaldoubles(self): + src = r''' + #include <stdlib.h> + #include <stdio.h> + + double testVu, testVv, testWu, testWv; + + void Test(double _testVu, double _testVv, double _testWu, double _testWv) + { + testVu = _testVu; + testVv = _testVv; + testWu = _testWu; + testWv = _testWv; + printf("BUG?\n"); + printf("Display: Vu=%f Vv=%f Wu=%f Wv=%f\n", testVu, testVv, testWu, testWv); + } + + int main(void) + { + double v1 = 465.1; + double v2 = 465.2; + double v3 = 160.3; + double v4 = 111.4; + Test(v1, v2, v3, v4); + return 0; + } + ''' + self.do_run(src, 'BUG?\nDisplay: Vu=465.100000 Vv=465.200000 Wu=160.300000 Wv=111.400000') + def test_math(self): src = ''' #include <stdio.h> @@ -1221,6 +1449,48 @@ m_divisor is 1091269979 ''' self.do_run(src, '4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\n', ['wowie', 'too', '74']) + def test_strndup(self): + src = ''' + //--------------- + //- http://pubs.opengroup.org/onlinepubs/9699919799/functions/strndup.html + //--------------- + + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + + int main(int argc, char **argv) { + const char* source = "strndup - duplicate a specific number of bytes from a string"; + + char* strdup_val = strndup(source, 0); + printf("1:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, 7); + printf("2:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, 1000); + printf("3:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, 60); + printf("4:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, 19); + printf("5:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, -1); + printf("6:%s\\n", strdup_val); + free(strdup_val); + + return 0; + } + ''' + self.do_run(src, '1:\n2:strndup\n3:strndup - duplicate a specific number of bytes from a string\n4:strndup - duplicate a specific number of bytes from a string\n5:strndup - duplicate\n6:\n') + def test_errar(self): src = r''' #include <stdio.h> @@ -1510,6 +1780,9 @@ m_divisor is 1091269979 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> @@ -1590,6 +1863,8 @@ m_divisor is 1091269979 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 @@ -1693,6 +1968,18 @@ m_divisor is 1091269979 ''' 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> @@ -1867,75 +2154,81 @@ m_divisor is 1091269979 ''' 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 = ''' @@ -2185,10 +2478,15 @@ m_divisor is 1091269979 #include <stdio.h> #include "emscripten.h" + extern "C" { + void EMSCRIPTEN_KEEPALIVE save_me_aimee() { printf("mann\n"); } + } + int main() { // EMSCRIPTEN_COMMENT("hello from the source"); emscripten_run_script("Module.print('hello world' + '!')"); printf("*%d*\n", emscripten_run_script_int("5*20")); + emscripten_run_script("_save_me_aimee()"); return 0; } ''' @@ -2199,7 +2497,19 @@ def process(filename): # TODO: restore this (see comment in emscripten.h) assert '// hello from the source' in src ''' - self.do_run(src, 'hello world!\n*100*', post_build=check) + self.do_run(src, 'hello world!\n*100*\nmann\n', 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, @@ -2489,6 +2799,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 { @@ -2541,17 +2853,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.0*)*' 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: @@ -2653,6 +2959,45 @@ def process(filename): extra_emscripten_args=['-H', 'libc/time.h']) #extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h']) + def test_intentional_fault(self): + # Some programs intentionally segfault themselves, we should compile that into a throw + src = r''' + int main () { + *(volatile char *)0 = 0; + return 0; + } + ''' + self.do_run(src, 'fault on write to 0') + + def test_trickystring(self): + src = r''' + #include <stdio.h> + + typedef struct + { + int (*f)(void *); + void *d; + char s[16]; + } LMEXFunctionStruct; + + int f(void *user) + { + return 0; + } + + static LMEXFunctionStruct const a[] = + { + {f, (void *)(int)'a', "aa"} + }; + + int main() + { + printf("ok\n"); + return a[0].f(a[0].d); + } + ''' + self.do_run(src, 'ok\n') + def test_statics(self): # static initializers save i16 but load i8 for some reason if Settings.SAFE_HEAP: @@ -3395,9 +3740,14 @@ def process(filename): printf("%g\n", strtod("0", &endptr)); printf("%g\n", strtod("0.", &endptr)); printf("%g\n", strtod("0.0", &endptr)); + printf("%g\n", strtod("-0.0", &endptr)); printf("%g\n", strtod("1", &endptr)); printf("%g\n", strtod("1.", &endptr)); printf("%g\n", strtod("1.0", &endptr)); + printf("%g\n", strtod("z1.0", &endptr)); + printf("%g\n", strtod("0.5", &endptr)); + printf("%g\n", strtod(".5", &endptr)); + printf("%g\n", strtod(".a5", &endptr)); printf("%g\n", strtod("123", &endptr)); printf("%g\n", strtod("123.456", &endptr)); printf("%g\n", strtod("-123.456", &endptr)); @@ -3419,9 +3769,14 @@ def process(filename): 0 0 0 + 0 1 1 1 + 0 + 0.5 + 0.5 + 0 123 123.456 -123.456 @@ -3437,6 +3792,7 @@ def process(filename): ''' self.do_run(src, re.sub(r'\n\s+', '\n', expected)) + self.do_run(src.replace('strtod', 'strtold'), re.sub(r'\n\s+', '\n', expected)) # XXX add real support for long double def test_strtok(self): src = r''' @@ -3501,6 +3857,22 @@ at function.:blag src = open(path_from_root('tests', 'parseInt', 'src.c'), 'r').read() expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read() self.do_run(src, expected) + + def test_transtrcase(self): + src = ''' + #include <stdio.h> + #include <string.h> + int main() { + char szToupr[] = "hello, "; + char szTolwr[] = "EMSCRIPTEN"; + strupr(szToupr); + strlwr(szTolwr); + printf(szToupr); + printf(szTolwr); + return 0; + } + ''' + self.do_run(src, 'HELLO, emscripten') def test_printf(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2') @@ -3601,12 +3973,38 @@ 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); + + int numverts = -1; + printf("%d\n", sscanf(" numverts 1499\n", " numverts %d", &numverts)); // white space is the same, even if tab vs space + printf("%d\n", numverts); + + int index; + float u, v; + short start, count; + printf("%d\n", sscanf(" vert 87 ( 0.481565 0.059481 ) 0 1\n", " vert %d ( %f %f ) %hu %hu", &index, &u, &v, &start, &count)); + printf("%d,%.6f,%.6f,%hu,%hu\n", index, u, v, start, count); + + int neg, neg2, neg3 = 0; + printf("%d\n", sscanf("-123 -765 -34-6", "%d %u %d", &neg, &neg2, &neg3)); + printf("%d,%u,%d\n", neg, neg2, neg3); + 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|\n' + + '1\n1499\n' + + '5\n87,0.481565,0.059481,0,1\n' + + '3\n-123,4294966531,-34\n') - # Part 2: doubles + def test_sscanf_2(self): + # doubles if Settings.USE_TYPED_ARRAYS == 2: for ftype in ['float', 'double']: src = r''' @@ -3675,9 +4073,11 @@ 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); + // Test FS_* exporting + Module['FS_createDataFile']('/', 'somefile.binary', [100, 200, 50, 25, 10, 77, 123], true, false); // 200 becomes -56, since signed chars are used in memory var test_files_input = 'hi there!'; var test_files_input_index = 0; FS.init(function() { @@ -3727,6 +4127,20 @@ def process(filename): ''' self.do_run(src, 'isatty? 0,0,1\ngot: 35\ngot: 45\ngot: 25\ngot: 15\n', post_build=post) + def test_fgetc_unsigned(self): + if self.emcc_args is None: return self.skip('requires emcc') + src = r''' + #include <stdio.h> + int main() { + FILE *file = fopen("file_with_byte_234.txt", "rb"); + int c = fgetc(file); + printf("*%d\n", c); + } + ''' + open('file_with_byte_234.txt', 'wb').write('\xea') + self.emcc_args += ['--embed-file', 'file_with_byte_234.txt'] + self.do_run(src, '*234\n') + def test_folders(self): add_pre_run = ''' def process(filename): @@ -4418,6 +4832,43 @@ def process(filename): self.do_run(src, '*15,15*\n*15,10*\n*6,10*\n*10,0*\n*7,1*') + def test_phiundef(self): + src = r''' +#include <stdlib.h> +#include <stdio.h> + +static int state; + +struct my_struct { + union { + struct { + unsigned char a; + unsigned char b; + } c; + unsigned int d; + } e; + unsigned int f; +}; + +int main(int argc, char **argv) { + struct my_struct r; + + state = 0; + + for (int i=0;i<argc+10;i++) + { + if (state % 2 == 0) + r.e.c.a = 3; + else + printf("%d\n", r.e.c.a); + state++; + } + return 0; +} + ''' + + self.do_run(src, '3\n3\n3\n3\n3\n') + # libc++ tests def test_iostream(self): @@ -4518,7 +4969,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) @@ -4643,6 +5094,8 @@ def process(filename): # print opt, "FAIL" def test_lua(self): + if self.emcc_args is None and Building.LLVM_OPTS: return self.skip('llvm 3.1 and safe llvm opts break lua') + try: os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1' @@ -4663,12 +5116,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 @@ -4691,6 +5138,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(), @@ -4700,6 +5151,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') @@ -4719,7 +5193,7 @@ def process(filename): self.do_run(r''' #define SQLITE_DISABLE_LFS #define LONGDOUBLE_TYPE double - #define SQLITE_INT64_TYPE int + #define SQLITE_INT64_TYPE long long int #define SQLITE_THREADSAFE 0 ''' + open(path_from_root('tests', 'sqlite', 'sqlite3.c'), 'r').read() + open(path_from_root('tests', 'sqlite', 'benchmark.c'), 'r').read(), @@ -5066,7 +5540,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; } } @@ -5091,22 +5565,28 @@ def process(filename): 'postRun': function() { Module.print('*'); var ret; - ret = ccall('get_int', 'number'); Module.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); |