aboutsummaryrefslogtreecommitdiff
path: root/tests/runner.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-xtests/runner.py2150
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);