From 8d3994c9eb604408fb0a325712c63b96827dee90 Mon Sep 17 00:00:00 2001 From: Anthony Pesch Date: Sun, 11 Aug 2013 21:48:58 -0700 Subject: initial work on splitting up runner.py --- tests/runner.py | 15237 ++---------------------------------------------------- 1 file changed, 339 insertions(+), 14898 deletions(-) (limited to 'tests/runner.py') diff --git a/tests/runner.py b/tests/runner.py index 9a8670b6..b9b92445 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -18,47 +18,6 @@ so you may prefer to use fewer cores here. from subprocess import Popen, PIPE, STDOUT import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, re, difflib, webbrowser, hashlib, threading, platform, BaseHTTPServer, multiprocessing, functools, stat, string -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 - -There are also commands to run specific subsets of the test suite: - - browser sockets - runs websocket networking tests - browser audio - runs audio tests in a web browser (requires human verification) - -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 - -In the main test suite, you can run all variations (O0, O1, O2, etc.) of -an individual test with - - python tests/runner.py ALL.test_hello_world - -============================================================================== - -''' - time.sleep(2) - # Setup __rootpath__ = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -76,10 +35,13 @@ except: raise Exception('Cannot find "COMPILER_OPTS" definition. Is %s set up properly? You may need to copy the template settings file into it.' % EM_CONFIG) # Core test runner class, shared between normal tests and benchmarks - checked_sanity = False +test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm2g', 'asm2x86', 's_0_0', 's_0_1'] +test_index = 0 +js_engine_override = None class RunnerCore(unittest.TestCase): + emcc_args = None 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. @@ -91,9 +53,7 @@ class RunnerCore(unittest.TestCase): return self.skip('requested to be skipped') def setUp(self): - global Settings Settings.reset() - Settings = tools.shared.Settings self.banned_js_engines = [] if not self.save_dir: dirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR) @@ -441,14895 +401,376 @@ process(sys.argv[1]) return 0; } ''' - return (main, supp) -################################################################################################### - -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'] - -test_index = 0 - -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..." - - 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]] + 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. - def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]): - if force_c or (main_file is not None and main_file[-2:]) == '.c': - basename = 'src.c' - Building.COMPILER = to_cc(Building.COMPILER) - - dirname = self.get_dir() - filename = os.path.join(dirname, basename) - if not no_build: - self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes, - build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build) - - # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays) - if js_engines is None: - js_engines = JS_ENGINES - if Settings.USE_TYPED_ARRAYS: - js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822 - 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 the paths therein.' % EM_CONFIG) - for engine in js_engines: - js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer) - self.assertContained(expected_output, js_output.replace('\r\n', '\n')) - self.assertNotContained('ERROR', js_output) - - #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging - - if self.save_JS: - global test_index - self.hardcode_arguments(filename + '.o.js', args) - shutil.copyfile(filename + '.o.js', os.path.join(TEMP_DIR, str(test_index) + '.js')) - test_index += 1 - - # No building - just process an existing .ll file (or .bc, which we turn into .ll) - def do_ll_run(self, ll_file, expected_output=None, args=[], js_engines=None, output_nicerizer=None, post_build=None, force_recompile=False, build_ll_hook=None, extra_emscripten_args=[]): - filename = os.path.join(self.get_dir(), 'src.cpp') - - self.prep_ll_run(filename, ll_file, force_recompile, build_ll_hook) - - self.ll_to_js(filename, extra_emscripten_args, post_build) - - self.do_run(None, - expected_output, - args, - no_build=True, - js_engines=js_engines, - 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 - int main() - { - printf("hello, world!\\n"); - return 0; - } - ''' - self.do_run(src, 'hello, world!') + ## Does a complete test - builds, runs, checks output, etc. + def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]): + if force_c or (main_file is not None and main_file[-2:]) == '.c': + basename = 'src.c' + Building.COMPILER = to_cc(Building.COMPILER) + + dirname = self.get_dir() + filename = os.path.join(dirname, basename) + if not no_build: + self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes, + build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build) + + # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays) + if js_engines is None: + js_engines = JS_ENGINES + if Settings.USE_TYPED_ARRAYS: + js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822 + 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 the paths therein.' % EM_CONFIG) + for engine in js_engines: + js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer) + self.assertContained(expected_output, js_output.replace('\r\n', '\n')) + self.assertNotContained('ERROR', js_output) + + #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging + + if self.save_JS: + global test_index + self.hardcode_arguments(filename + '.o.js', args) + shutil.copyfile(filename + '.o.js', os.path.join(TEMP_DIR, str(test_index) + '.js')) + test_index += 1 + + # No building - just process an existing .ll file (or .bc, which we turn into .ll) + def do_ll_run(self, ll_file, expected_output=None, args=[], js_engines=None, output_nicerizer=None, post_build=None, force_recompile=False, build_ll_hook=None, extra_emscripten_args=[]): + filename = os.path.join(self.get_dir(), 'src.cpp') + + self.prep_ll_run(filename, ll_file, force_recompile, build_ll_hook) - assert 'EMSCRIPTEN_GENERATED_FUNCTIONS' not in open(self.in_dir('src.cpp.o.js')).read(), 'must not emit this unneeded internal thing' - - def test_intvars(self): - if self.emcc_args == None: return self.skip('needs ta2') - - src = ''' - #include - int global = 20; - int *far; - int main() - { - int x = 5; - int y = x+17; - int z = (y-1)/2; // Should stay an integer after division! - y += 1; - int w = x*3+4; - int k = w < 15 ? 99 : 101; - far = &k; - *far += global; - int i = k > 100; // Should be an int, not a bool! - int j = i << 6; - j >>= 1; - j = j ^ 5; - int h = 1; - h |= 0; - int p = h; - p &= 0; - printf("*%d,%d,%d,%d,%d,%d,%d,%d,%d*\\n", x, y, z, w, k, i, j, h, p); - - long hash = -1; - size_t perturb; - int ii = 0; - for (perturb = hash; ; perturb >>= 5) { - printf("%d:%d", ii, perturb); - ii++; - if (ii == 9) break; - printf(","); - } - printf("*\\n"); - printf("*%.1d,%.2d*\\n", 56, 9); - - // Fixed-point math on 64-bit ints. Tricky to support since we have no 64-bit shifts in JS - { - struct Fixed { - static int Mult(int a, int b) { - return ((long long)a * (long long)b) >> 16; - } - }; - printf("fixed:%d\\n", Fixed::Mult(150000, 140000)); - } - - printf("*%ld*%p\\n", (long)21, &hash); // The %p should not enter an infinite loop! - return 0; - } - ''' - self.do_run(src, '*5,23,10,19,121,1,37,1,0*\n0:-1,1:134217727,2:4194303,3:131071,4:4095,5:127,6:3,7:0,8:0*\n*56,09*\nfixed:320434\n*21*') - - def test_sintvars(self): - Settings.CORRECT_SIGNS = 1 # Relevant to this test - src = ''' - #include - struct S { - char *match_start; - char *strstart; - }; - int main() - { - struct S _s; - struct S *s = &_s; - unsigned short int sh; - - s->match_start = (char*)32522; - s->strstart = (char*)(32780); - printf("*%d,%d,%d*\\n", (int)s->strstart, (int)s->match_start, (int)(s->strstart - s->match_start)); - sh = s->strstart - s->match_start; - printf("*%d,%d*\\n", sh, sh>>7); - - s->match_start = (char*)32999; - s->strstart = (char*)(32780); - printf("*%d,%d,%d*\\n", (int)s->strstart, (int)s->match_start, (int)(s->strstart - s->match_start)); - sh = s->strstart - s->match_start; - printf("*%d,%d*\\n", sh, sh>>7); - } - ''' - output = '*32780,32522,258*\n*258,2*\n*32780,32999,-219*\n*65317,510*' - Settings.CORRECT_OVERFLOWS = 0 # We should not need overflow correction to get this right - self.do_run(src, output, force_c=True) - - def test_i64(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2') - - src = ''' - #include - int main() - { - long long a = 0x2b00505c10; - long long b = a >> 29; - long long c = a >> 32; - long long d = a >> 34; - printf("*%Ld,%Ld,%Ld,%Ld*\\n", a, b, c, d); - unsigned long long ua = 0x2b00505c10; - unsigned long long ub = ua >> 29; - unsigned long long uc = ua >> 32; - unsigned long long ud = ua >> 34; - printf("*%Ld,%Ld,%Ld,%Ld*\\n", ua, ub, uc, ud); - - long long x = 0x0000def123450789ULL; // any bigger than this, and we - long long y = 0x00020ef123456089ULL; // start to run into the double precision limit! - printf("*%Ld,%Ld,%Ld,%Ld,%Ld*\\n", x, y, x | y, x & y, x ^ y, x >> 2, y << 2); - - printf("*"); - long long z = 13; - int n = 0; - while (z > 1) { - printf("%.2f,", (float)z); // these must be integers! - z = z >> 1; - n++; - } - printf("*%d*\\n", n); - return 0; - } - ''' - self.do_run(src, '*184688860176,344,43,10*\n*184688860176,344,43,10*\n*245127260211081,579378795077769,808077213656969,16428841631881,791648372025088*\n*13.00,6.00,3.00,*3*') + self.ll_to_js(filename, extra_emscripten_args, post_build) - src = r''' - #include - #include - #include + self.do_run(None, + expected_output, + args, + no_build=True, + js_engines=js_engines, + 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 + + +# Run a server and a web page. When a test runs, we tell the server about it, +# which tells the web page, which then opens a window with the test. Doing +# it this way then allows the page to close() itself when done. +def harness_server_func(q): + class TestServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): + def do_GET(s): + s.send_response(200) + s.send_header("Content-type", "text/html") + s.end_headers() + if s.path == '/run_harness': + s.wfile.write(open(path_from_root('tests', 'browser_harness.html')).read()) + else: + result = 'False' + if not q.empty(): + result = q.get() + s.wfile.write(result) + s.wfile.close() + def log_request(code=0, size=0): + # don't log; too noisy + pass + httpd = BaseHTTPServer.HTTPServer(('localhost', 9999), TestServerHandler) + httpd.serve_forever() # test runner will kill us + +def server_func(dir, q): + class TestServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): + def do_GET(s): + if 'report_' in s.path: + q.put(s.path) + else: + filename = s.path[1:] + if os.path.exists(filename): + s.send_response(200) + s.send_header("Content-type", "text/html") + s.end_headers() + s.wfile.write(open(filename).read()) + s.wfile.close() + else: + s.send_response(500) + s.send_header("Content-type", "text/html") + s.end_headers() + def log_request(code=0, size=0): + # don't log; too noisy + pass + os.chdir(dir) + httpd = BaseHTTPServer.HTTPServer(('localhost', 8888), TestServerHandler) + httpd.serve_forever() # test runner will kill us + +class BrowserCore(RunnerCore): + def __init__(self, *args, **kwargs): + super(BrowserCore, self).__init__(*args, **kwargs) + + @classmethod + def setUpClass(self): + super(BrowserCore, self).setUpClass() + self.harness_queue = multiprocessing.Queue() + self.harness_server = multiprocessing.Process(target=harness_server_func, args=(self.harness_queue,)) + self.harness_server.start() + print '[Browser harness server on process %d]' % self.harness_server.pid + webbrowser.open_new('http://localhost:9999/run_harness') + + @classmethod + def tearDownClass(self): + super(BrowserCore, self).tearDownClass() + self.harness_server.terminate() + print '[Browser harness server terminated]' + # On Windows, shutil.rmtree() in tearDown() raises this exception if we do not wait a bit: + # WindowsError: [Error 32] The process cannot access the file because it is being used by another process. + time.sleep(0.1) + + def run_browser(self, html_file, message, expectedResult=None): + if expectedResult is not None: + try: + queue = multiprocessing.Queue() + server = multiprocessing.Process(target=functools.partial(server_func, self.get_dir()), args=(queue,)) + server.start() + self.harness_queue.put('http://localhost:8888/' + html_file) + output = '[no http server activity]' + start = time.time() + while time.time() - start < 60: + if not queue.empty(): + output = queue.get() + break + time.sleep(0.1) - int64_t returner1() { return 0x0000def123450789ULL; } - int64_t returner2(int test) { - while (test > 10) test /= 2; // confuse the compiler so it doesn't eliminate this function - return test > 5 ? 0x0000def123450123ULL : 0ULL; - } + self.assertIdentical(expectedResult, output) + finally: + server.terminate() + time.sleep(0.1) # see comment about Windows above + else: + webbrowser.open_new(os.path.abspath(html_file)) + print 'A web browser window should have opened a page containing the results of a part of this test.' + print 'You need to manually look at the page to see that it works ok: ' + message + print '(sleeping for a bit to keep the directory alive for the web browser..)' + time.sleep(5) + print '(moving on..)' + + def with_report_result(self, code): + return r''' + #if EMSCRIPTEN + #include + #define REPORT_RESULT_INTERNAL(sync) \ + char output[1000]; \ + sprintf(output, \ + "xhr = new XMLHttpRequest();" \ + "xhr.open('GET', 'http://localhost:8888/report_result?%d'%s);" \ + "xhr.send();", result, sync ? ", false" : ""); \ + emscripten_run_script(output); \ + emscripten_run_script("setTimeout(function() { window.close() }, 1000)"); // comment this out to keep the test runner window open to debug + #define REPORT_RESULT() REPORT_RESULT_INTERNAL(0) + #endif +''' + code - void modifier1(int64_t t) { - t |= 12; - printf("m1: %Ld\n", t); - } - void modifier2(int64_t &t) { - t |= 12; - } + def reftest(self, expected): + # make sure the pngs used here have no color correction, using e.g. + # pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB infile outfile + basename = os.path.basename(expected) + shutil.copyfile(expected, os.path.join(self.get_dir(), basename)) + open(os.path.join(self.get_dir(), 'reftest.js'), 'w').write(''' + var Module = eval('Module'); + function doReftest() { + if (doReftest.done) return; + doReftest.done = true; + var img = new Image(); + img.onload = function() { + assert(img.width == Module.canvas.width, 'Invalid width: ' + Module.canvas.width + ', should be ' + img.width); + assert(img.height == Module.canvas.height, 'Invalid height: ' + Module.canvas.height + ', should be ' + img.height); + + var canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + var ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + var expected = ctx.getImageData(0, 0, img.width, img.height).data; + + var actualUrl = Module.canvas.toDataURL(); + var actualImage = new Image(); + actualImage.onload = function() { + /* + document.body.appendChild(img); // for comparisons + var div = document.createElement('div'); + div.innerHTML = '^=expected, v=actual'; + document.body.appendChild(div); + document.body.appendChild(actualImage); // to grab it for creating the test reference + */ - int truthy() { - int x = time(0); - while (x > 10) { - x |= 7; - x /= 2; + var actualCanvas = document.createElement('canvas'); + actualCanvas.width = actualImage.width; + actualCanvas.height = actualImage.height; + var actualCtx = actualCanvas.getContext('2d'); + actualCtx.drawImage(actualImage, 0, 0); + var actual = actualCtx.getImageData(0, 0, actualImage.width, actualImage.height).data; + + var total = 0; + var width = img.width; + var height = img.height; + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + total += Math.abs(expected[y*width*4 + x*4 + 0] - actual[y*width*4 + x*4 + 0]); + total += Math.abs(expected[y*width*4 + x*4 + 1] - actual[y*width*4 + x*4 + 1]); + total += Math.abs(expected[y*width*4 + x*4 + 2] - actual[y*width*4 + x*4 + 2]); + } } - return x < 3; - } + var wrong = Math.floor(total / (img.width*img.height*3)); // floor, to allow some margin of error for antialiasing - struct IUB { - int c; - long long d; + xhr = new XMLHttpRequest(); + xhr.open('GET', 'http://localhost:8888/report_result?' + wrong); + xhr.send(); + setTimeout(function() { window.close() }, 1000); }; - - IUB iub[] = { - { 55, 17179869201 }, - { 122, 25769803837 }, - }; - - int main(int argc, char **argv) - { - int64_t x1 = 0x1234def123450789ULL; - int64_t x2 = 0x1234def123450788ULL; - int64_t x3 = 0x1234def123450789ULL; - printf("*%Ld\n%d,%d,%d,%d,%d\n%d,%d,%d,%d,%d*\n", x1, x1==x2, x1x2, x1>=x2, // note: some rounding in the printing! - x1==x3, x1x3, x1>=x3); - printf("*%Ld*\n", returner1()); - printf("*%Ld*\n", returner2(30)); - - uint64_t maxx = -1ULL; - printf("*%Lu*\n*%Lu*\n", maxx, maxx >> 5); - - // Make sure params are not modified if they shouldn't be - int64_t t = 123; - modifier1(t); - printf("*%Ld*\n", t); - modifier2(t); - printf("*%Ld*\n", t); - - // global structs with i64s - printf("*%d,%Ld*\n*%d,%Ld*\n", iub[0].c, iub[0].d, iub[1].c, iub[1].d); - - // Bitshifts - { - int64_t a = -1; - int64_t b = a >> 29; - int64_t c = a >> 32; - int64_t d = a >> 34; - printf("*%Ld,%Ld,%Ld,%Ld*\n", a, b, c, d); - uint64_t ua = -1; - int64_t ub = ua >> 29; - int64_t uc = ua >> 32; - int64_t ud = ua >> 34; - printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud); - } - - // Nonconstant bitshifts - { - int64_t a = -1; - int64_t b = a >> (29 - argc + 1); - int64_t c = a >> (32 - argc + 1); - int64_t d = a >> (34 - argc + 1); - printf("*%Ld,%Ld,%Ld,%Ld*\n", a, b, c, d); - uint64_t ua = -1; - int64_t ub = ua >> (29 - argc + 1); - int64_t uc = ua >> (32 - argc + 1); - int64_t ud = ua >> (34 - argc + 1); - printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud); - } - - // Math mixtures with doubles - { - uint64_t a = 5; - double b = 6.8; - uint64_t c = a * b; - if (truthy()) printf("*%d,%d,%d*\n", (int)&a, (int)&b, (int)&c); // printing addresses prevents optimizations - printf("*prod:%llu*\n", c); - } - - // Basic (rounded, for now) math. Just check compilation. - int64_t a = 0x1234def123450789ULL; - a--; if (truthy()) a--; // confuse optimizer - int64_t b = 0x1234000000450789ULL; - b++; if (truthy()) b--; // confuse optimizer - printf("*%Ld,%Ld,%Ld,%Ld*\n", (a+b)/5000, (a-b)/5000, (a*3)/5000, (a/5)/5000); - - a -= 17; if (truthy()) a += 5; // confuse optimizer - b -= 17; if (truthy()) b += 121; // confuse optimizer - printf("*%Lx,%Lx,%Lx,%Lx*\n", b - a, b - a/2, b/2 - a, b - 20); - - if (truthy()) a += 5/b; // confuse optimizer - if (truthy()) b += 121*(3+a/b); // confuse optimizer - printf("*%Lx,%Lx,%Lx,%Lx*\n", a - b, a - b/2, a/2 - b, a - 20); - - return 0; - } - ''' - self.do_run(src, '*1311918518731868041\n' + - '0,0,0,1,1\n' + - '1,0,1,0,1*\n' + - '*245127260211081*\n' + - '*245127260209443*\n' + - '*18446744073709551615*\n' + - '*576460752303423487*\n' + - 'm1: 127\n' + - '*123*\n' + - '*127*\n' + - '*55,17179869201*\n' + - '*122,25769803837*\n' + - '*-1,-1,-1,-1*\n' + - '*-1,34359738367,4294967295,1073741823*\n' + - '*-1,-1,-1,-1*\n' + - '*-1,34359738367,4294967295,1073741823*\n' + - '*prod:34*\n' + - '*524718382041609,49025451137,787151111239120,52476740749274*\n' + - '*ffff210edd000002,91990876ea283be,f6e5210edcdd7c45,1234000000450765*\n' + - '*def122fffffe,91adef1232283bb,f6e66f78915d7c42,1234def123450763*\n') - - src = r''' - #include - #include - - int main() - { - long long i,j,k; - - i = 0; - j = -1, - k = 1; - - printf( "*\n" ); - printf( "%s\n", i > j ? "Ok": "Fail" ); - printf( "%s\n", k > i ? "Ok": "Fail" ); - printf( "%s\n", k > j ? "Ok": "Fail" ); - printf( "%s\n", i < j ? "Fail": "Ok" ); - printf( "%s\n", k < i ? "Fail": "Ok" ); - printf( "%s\n", k < j ? "Fail": "Ok" ); - printf( "%s\n", (i-j) >= k ? "Ok": "Fail" ); - printf( "%s\n", (i-j) <= k ? "Ok": "Fail" ); - printf( "%s\n", i > std::numeric_limits::min() ? "Ok": "Fail" ); - printf( "%s\n", i < std::numeric_limits::max() ? "Ok": "Fail" ); - printf( "*\n" ); - } - ''' - - self.do_run(src, '*\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\n*') - - # stuff that also needs sign corrections - - Settings.CORRECT_SIGNS = 1 - - src = r''' - #include - #include - - int main() - { - // i32 vs i64 - int32_t small = -1; - int64_t large = -1; - printf("*%d*\n", small == large); - small++; - printf("*%d*\n", small == large); - uint32_t usmall = -1; - uint64_t ularge = -1; - printf("*%d*\n", usmall == ularge); - return 0; - } - ''' - - self.do_run(src, '*1*\n*0*\n*0*\n') - - def test_i64_b(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - - src = r''' - #include - #include - - typedef long long int64; - - #define PRMJ_USEC_PER_SEC 1000000L - - int main(int argc, char * argv[]) { - int64 sec = 1329409675 + argc; - int64 usec = 2329509675; - int64 mul = int64(sec) * PRMJ_USEC_PER_SEC; - int64 add = mul + int64(usec); - int add_low = add; - int add_high = add >> 32; - printf("*%lld,%lld,%u,%u*\n", mul, add, add_low, add_high); - int64 x = sec + (usec << 25); - x >>= argc*3; - printf("*%llu*\n", x); - return 0; - } - ''' - - self.do_run(src, '*1329409676000000,1329412005509675,3663280683,309527*\n*9770671914067409*\n') - - def test_i64_cmp(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - - src = r''' - #include - - typedef long long int64; - - bool compare(int64 val) { - return val == -12; - } - - bool compare2(int64 val) { - return val < -12; - } - - int main(int argc, char * argv[]) { - printf("*%d,%d,%d,%d,%d,%d*\n", argc, compare(argc-1-12), compare(1000+argc), compare2(argc-1-10), compare2(argc-1-14), compare2(argc+1000)); - return 0; - } - ''' - - self.do_run(src, '*1,1,0,0,1,0*\n') - - def test_i64_cmp2(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - - src = r''' - #include - #include - - typedef int32_t INT32; - typedef int64_t INT64; - typedef uint8_t UINT8; - - void interface_clock_changed() - { - UINT8 m_divshift; - INT32 m_divisor; - - //INT64 attos = m_attoseconds_per_cycle; - INT64 attos = 279365114840; - m_divshift = 0; - while (attos >= (1UL << 31)) - { - m_divshift++; - printf("m_divshift is %i, on %Ld >?= %lu\n", m_divshift, attos, 1UL << 31); - attos >>= 1; - } - m_divisor = attos; - - printf("m_divisor is %i\n",m_divisor); - } - - int main() { - interface_clock_changed(); - return 0; - } - ''' - self.do_run(src, '''m_divshift is 1, on 279365114840 >?= 2147483648 -m_divshift is 2, on 139682557420 >?= 2147483648 -m_divshift is 3, on 69841278710 >?= 2147483648 -m_divshift is 4, on 34920639355 >?= 2147483648 -m_divshift is 5, on 17460319677 >?= 2147483648 -m_divshift is 6, on 8730159838 >?= 2147483648 -m_divshift is 7, on 4365079919 >?= 2147483648 -m_divshift is 8, on 2182539959 >?= 2147483648 -m_divisor is 1091269979 -''') - - def test_i64_double(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - - - src = r''' - #include - - typedef long long int64; - #define JSDOUBLE_HI32_SIGNBIT 0x80000000 - - bool JSDOUBLE_IS_NEGZERO(double d) - { - union { - struct { - unsigned int lo, hi; - } s; - double d; - } x; - if (d != 0) - return false; - x.d = d; - return (x.s.hi & JSDOUBLE_HI32_SIGNBIT) != 0; - } - - bool JSINT64_IS_NEGZERO(int64 l) - { - union { - int64 i; - double d; - } x; - if (l != 0) - return false; - x.i = l; - return x.d == -0; - } - - int main(int argc, char * argv[]) { - printf("*%d,%d,%d,%d*\n", JSDOUBLE_IS_NEGZERO(0), JSDOUBLE_IS_NEGZERO(-0), JSDOUBLE_IS_NEGZERO(-1), JSDOUBLE_IS_NEGZERO(+1)); - printf("*%d,%d,%d,%d*\n", JSINT64_IS_NEGZERO(0), JSINT64_IS_NEGZERO(-0), JSINT64_IS_NEGZERO(-1), JSINT64_IS_NEGZERO(+1)); - return 0; - } - ''' - self.do_run(src, '*0,0,0,0*\n*1,1,0,0*\n') # same as gcc - - def test_i64_umul(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - - src = r''' - #include - #include - - typedef uint32_t UINT32; - typedef uint64_t UINT64; - - int main() { - volatile UINT32 testu32a = 2375724032U; - UINT32 bigu32 = 0xffffffffU; - volatile UINT64 testu64a = 14746250828952703000U; - - while ((UINT64)testu32a * (UINT64)bigu32 < testu64a) { - printf("testu64a is %llu\n", testu64a); - testu64a /= 2; - } - - return 0; - } - ''' - self.do_run(src, 'testu64a is 14746250828952703000\n') - - def test_i64_precise(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - - src = r''' - #include - #include - - 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 even if we ask for precision, if it is not needed it is not included - Settings.PRECISE_I64_MATH = 1 - src = ''' - #include - #include - - 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, 'i64 precise math should not have been included if not actually used' - - # But if we force it to be included, it is. First, a case where we don't need it - Settings.PRECISE_I64_MATH = 2 - self.do_run(open(path_from_root('tests', 'hello_world.c')).read(), 'hello') - code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() - assert 'goog.math.Long' in code, 'i64 precise math should be included if forced' - - # and now one where we do - self.do_run(r''' - #include - - int main( int argc, char ** argv ) - { - unsigned long a = 0x60DD1695U; - unsigned long b = 0xCA8C4E7BU; - unsigned long long c = (unsigned long long)a * b; - printf( "c = %016llx\n", c ); - - return 0; - } - ''', 'c = 4ca38a6bd2973f97') - - def test_i64_llabs(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - Settings.PRECISE_I64_MATH = 2 - self.do_run(r''' - #include - #include - - int main(int argc, char ** argv) { - printf("%lld,%lld\n", llabs(-576460752303423489), llabs(576460752303423489)); - return 0; - } - ''', '576460752303423489,576460752303423489') - - def test_i64_zextneg(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - - src = r''' - #include - #include - - 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 - #include - uint64_t a, b; - int main(int argc, char *argv[]) - { - a = argc; - b = argv[1][0]; - printf("%d,%d\n", a, b); - 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_i64_i16(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - - src = r''' - #include - #include - int main(int argc, char ** argv){ - int y=-133; - int64_t x= ((int64_t)((short)(y)))*(100 + argc); - if(x>0) - printf(">0\n"); - else - printf("<=0\n"); - } - ''' - self.do_run(src, '<=0') - - def test_i64_qdouble(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') - - src = r''' - #include - typedef long long qint64; /* 64 bit signed */ - typedef double qreal; - - - int main(int argc, char **argv) - { - qreal c = 111; - qint64 d = -111 + (argc - 1); - c += d; - if (c < -1 || c > 1) - { - printf("Failed!\n"); - } - else - { - printf("Succeeded!\n"); - } - }; - ''' - 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 - #include - #include - - 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); + actualImage.src = actualUrl; } + img.src = '%s'; + }; + Module['postRun'] = doReftest; + Module['preRun'].push(function() { + setTimeout(doReftest, 1000); // if run() throws an exception and postRun is not called, this will kick in + }); +''' % basename) - 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') - - src = r''' - #include + def btest(self, filename, expected=None, reference=None, force_c=False, reference_slack=0, + args=[], outfile='test.html', message='.'): # TODO: use in all other tests + # if we are provided the source and not a path, use that + filename_is_src = '\n' in filename + src = filename if filename_is_src else '' + filepath = path_from_root('tests', filename) if not filename_is_src else ('main.c' if force_c else 'main.cpp') + temp_filepath = os.path.join(self.get_dir(), os.path.basename(filepath)) + if filename_is_src: + with open(temp_filepath, 'w') as f: f.write(src) + if not reference: + if not src: + with open(filepath) as f: src = f.read() + with open(temp_filepath, 'w') as f: f.write(self.with_report_result(src)) + else: + expected = [str(i) for i in range(0, reference_slack+1)] + shutil.copyfile(filepath, temp_filepath) + self.reftest(path_from_root('tests', reference)) + args = args + ['--pre-js', 'reftest.js', '-s', 'GL_TESTING=1'] + Popen([PYTHON, EMCC, temp_filepath, '-o', outfile] + args).communicate() + if type(expected) is str: expected = [expected] + self.run_browser(outfile, message, ['/report_result?' + e for e in expected]) - int main(int argc, char **argv) { - unsigned long d1 = 0x847c9b5d; - unsigned long q = 0x549530e1; - if (argc > 1000) { q += argc; d1 -= argc; } // confuse optimizer - printf("%lu\n", d1*q); - return 0; - } - ''' - self.do_run(src, '3217489085') +################################################################################################### - def test_i32_mul_semiprecise(self): - if Settings.ASM_JS: return self.skip('asm is always fully precise') +if __name__ == '__main__': + # The runner module is imported by the tests, add the current module + # instance into the cache so global variables such as js_engine_override + # are shared correctly with the test suite modules. + sys.modules['runner'] = sys.modules[__name__] - Settings.PRECISE_I32_MUL = 0 # we want semiprecise here + # Sanity checks + total_engines = len(JS_ENGINES) + JS_ENGINES = filter(check_engine, JS_ENGINES) + if len(JS_ENGINES) == 0: + print 'WARNING: None of the JS engines in JS_ENGINES appears to work.' + elif len(JS_ENGINES) < total_engines: + print 'WARNING: Not all the JS engines in JS_ENGINES appears to work, ignoring those.' - src = r''' - #include + # If an argument comes in as test_*, treat it as a test of the default suite + sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv) - typedef unsigned int uint; + # If no tests were specified, run the core suite + if len(sys.argv) == 1: + sys.argv = [sys.argv[0]] + map(lambda mode: mode, test_modes) + print ''' +============================================================================== +Running the main part of the test suite. Don't forget to run the other parts! - // from cube2, zlib licensed + 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 + sockets - runs websocket networking tests - #define N (624) - #define M (397) - #define K (0x9908B0DFU) +There are also commands to run specific subsets of the test suite: - static uint state[N]; - static int next = N; + browser.audio - runs audio tests in a web browser (requires human verification) - void seedMT(uint seed) - { - state[0] = seed; - for(uint i = 1; i < N; i++) // if we do not do this precisely, at least we should coerce to int immediately, not wait - state[i] = seed = 1812433253U * (seed ^ (seed >> 30)) + i; - next = 0; - } +To run one of those parts, do something like - int main() { - seedMT(5497); - for (int i = 0; i < 10; i++) printf("%d: %u\n", i, state[i]); - return 0; - } - ''' - self.do_run(src, '''0: 5497 -1: 2916432318 -2: 2502517762 -3: 3151524867 -4: 2323729668 -5: 2053478917 -6: 2409490438 -7: 848473607 -8: 691103752 -9: 3915535113 -''') + python tests/runner.py sanity - def test_i16_emcc_intrinsic(self): - Settings.CORRECT_SIGNS = 1 # Relevant to this test +To run a specific set of tests, you can do things like - src = r''' - #include + python tests/runner.py o1 - int test(unsigned short a, unsigned short b) { - unsigned short result = a; - result += b; - if (result < b) printf("C!"); - return result; - } +(that runs the o1 (-O1) tests). You can run individual tests with - 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,') + python tests/runner.py test_hello_world - def test_negative_zero(self): - src = r''' - #include - #include +Combinations work too, for example - int main() { - #define TEST(x, y) \ - printf("%.2f, %.2f ==> %.2f\n", x, y, copysign(x, y)); - TEST( 5.0f, 5.0f); - TEST( 5.0f, -5.0f); - TEST(-5.0f, 5.0f); - TEST(-5.0f, -5.0f); - TEST( 5.0f, 4.0f); - TEST( 5.0f, -4.0f); - TEST(-5.0f, 4.0f); - TEST(-5.0f, -4.0f); - TEST( 0.0f, 5.0f); - TEST( 0.0f, -5.0f); - TEST(-0.0f, 5.0f); - TEST(-0.0f, -5.0f); - TEST( 5.0f, 0.0f); - TEST( 5.0f, -0.0f); - TEST(-5.0f, 0.0f); - TEST(-5.0f, -0.0f); - TEST( 0.0f, 0.0f); - TEST( 0.0f, -0.0f); - TEST(-0.0f, 0.0f); - TEST(-0.0f, -0.0f); - return 0; - } - ''' - self.do_run(src, '''5.00, 5.00 ==> 5.00 -5.00, -5.00 ==> -5.00 --5.00, 5.00 ==> 5.00 --5.00, -5.00 ==> -5.00 -5.00, 4.00 ==> 5.00 -5.00, -4.00 ==> -5.00 --5.00, 4.00 ==> 5.00 --5.00, -4.00 ==> -5.00 -0.00, 5.00 ==> 0.00 -0.00, -5.00 ==> -0.00 --0.00, 5.00 ==> 0.00 --0.00, -5.00 ==> -0.00 -5.00, 0.00 ==> 5.00 -5.00, -0.00 ==> -5.00 --5.00, 0.00 ==> 5.00 --5.00, -0.00 ==> -5.00 -0.00, 0.00 ==> 0.00 -0.00, -0.00 ==> -0.00 --0.00, 0.00 ==> 0.00 --0.00, -0.00 ==> -0.00 -''') + python tests/runner.py browser.test_sdl_image - def test_llvm_intrinsics(self): - if self.emcc_args == None: return self.skip('needs ta2') +In the main test suite, you can run all variations (O0, O1, O2, etc.) of +an individual test with - Settings.PRECISE_I64_MATH = 2 # for bswap64 + python tests/runner.py ALL.test_hello_world - src = r''' - #include - #include +============================================================================== - extern "C" { - extern unsigned short llvm_bswap_i16(unsigned short x); - extern unsigned int llvm_bswap_i32(unsigned int x); - extern int32_t llvm_ctlz_i32(int32_t x); - extern int64_t llvm_ctlz_i64(int64_t x); - extern int32_t llvm_cttz_i32(int32_t x); - extern int64_t llvm_cttz_i64(int64_t x); - extern int32_t llvm_ctpop_i32(int32_t x); - extern int64_t llvm_ctpop_i64(int64_t x); - extern int llvm_expect_i32(int x, int y); - } +''' + time.sleep(2) - int main(void) { - unsigned short x = 0xc8ef; - printf("%x,%x\n", x&0xff, x >> 8); - x = llvm_bswap_i16(x); - printf("%x,%x\n", x&0xff, x >> 8); + # If a test (e.g. test_html) is specified as ALL.test_html, add an entry for each test_mode + 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]] + map(lambda mode: mode+'.'+test, test_modes) - unsigned int y = 0xc5de158a; - printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff); - y = llvm_bswap_i32(y); - printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff); + # Skip requested tests + for i in range(len(sys.argv)): + arg = sys.argv[i] + if arg.startswith('skip:'): + which = arg.split('skip:')[1] + if which.startswith('ALL.'): + ignore, test = which.split('.') + which = map(lambda mode: mode+'.'+test, test_modes) + else: + which = [which] - printf("%d,%d\n", (int)llvm_ctlz_i64(((int64_t)1) << 40), llvm_ctlz_i32(1<<10)); - printf("%d,%d\n", (int)llvm_cttz_i64(((int64_t)1) << 40), llvm_cttz_i32(1<<10)); - printf("%d,%d\n", (int)llvm_ctpop_i64((0x3101ULL << 32) | 1), llvm_ctpop_i32(0x3101)); - printf("%d\n", (int)llvm_ctpop_i32(-594093059)); + print >> sys.stderr, ','.join(which) + for test in which: + print >> sys.stderr, 'will skip "%s"' % test + exec(test + ' = RunnerCore.skipme') - printf("%d\n", llvm_expect_i32(x % 27, 3)); + sys.argv[i] = '' + sys.argv = filter(lambda arg: arg, sys.argv) - int64_t a = 1; - a = __builtin_bswap64(a); - printf("%lld\n", a); + # Extract the JS engine override from the arguments (used by benchmarks) + for i in range(1, len(sys.argv)): + arg = sys.argv[i] + if arg.isupper(): + print 'Interpreting all capital argument "%s" as JS_ENGINE override' % arg + js_engine_override = eval(arg) + sys.argv[i] = None + sys.argv = filter(lambda arg: arg is not None, sys.argv) - return 0; - } - ''' - self.do_run(src, '''ef,c8 -c8,ef -8a,15,de,c5 -c5,de,15,8a -23,21 -40,10 -5,4 -22 -13 -72057594037927936 -''') - - def test_bswap64(self): - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2') - - src = r''' - #include - #include - - #include - #include - #include - - typedef unsigned long long quint64; - - using namespace std; - - inline quint64 qbswap(quint64 source) - { - return 0 - | ((source & quint64(0x00000000000000ffLL)) << 56) - | ((source & quint64(0x000000000000ff00LL)) << 40) - | ((source & quint64(0x0000000000ff0000LL)) << 24) - | ((source & quint64(0x00000000ff000000LL)) << 8) - | ((source & quint64(0x000000ff00000000LL)) >> 8) - | ((source & quint64(0x0000ff0000000000LL)) >> 24) - | ((source & quint64(0x00ff000000000000LL)) >> 40) - | ((source & quint64(0xff00000000000000LL)) >> 56); - } - - int main() - { - quint64 v = strtoull("4433ffeeddccbb00", NULL, 16); - printf("%lld\n", v); - - const string string64bitInt = "4433ffeeddccbb00"; - stringstream s(string64bitInt); - quint64 int64bitInt = 0; - printf("1\n"); - s >> hex >> int64bitInt; - printf("2\n"); - - stringstream out; - out << hex << qbswap(int64bitInt); - - cout << out.str() << endl; - cout << hex << int64bitInt << endl; - cout << string64bitInt << endl; - - if (out.str() != "bbccddeeff3344") - { - cout << "Failed!" << endl; - } - else - { - cout << "Succeeded!" << endl; - } - - return 0; - } - ''' - self.do_run(src, '''4914553019779824384 -1 -2 -bbccddeeff3344 -4433ffeeddccbb00 -4433ffeeddccbb00 -Succeeded! -''') - - 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): - - try: - old_chunk_size = os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or '' - os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = '1' # test splitting out each function to a chunk in emscripten.py (21 functions here) - - # 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 ', - 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) - finally: - os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = old_chunk_size - - def test_unaligned(self): - if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1') - - src = r''' - #include - - struct S { - double x; - int y; - }; - - int main() { - // the 64-bit value here will not be 8-byte aligned - S s0[3] = { {0x12a751f430142, 22}, {0x17a5c85bad144, 98}, {1, 1}}; - char buffer[10*sizeof(S)]; - int b = int(buffer); - S *s = (S*)(b + 4-b%8); - s[0] = s0[0]; - s[1] = s0[1]; - s[2] = s0[2]; - - printf("*%d : %d : %d\n", sizeof(S), ((unsigned int)&s[0]) % 8 != ((unsigned int)&s[1]) % 8, - ((unsigned int)&s[1]) - ((unsigned int)&s[0])); - s[0].x++; - s[0].y++; - s[1].x++; - s[1].y++; - printf("%.1f,%d,%.1f,%d\n", s[0].x, s[0].y, s[1].x, s[1].y); - return 0; - } - ''' - - # TODO: A version of this with int64s as well - - 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 - - # Test for undefined behavior in C. This is not legitimate code, but does exist - - if Settings.USE_TYPED_ARRAYS != 2: return self.skip('No meaning to unaligned addresses without t2') - - src = r''' - #include - - int main() - { - int x[10]; - char *p = (char*)&x[0]; - p++; - short *q = (short*)p; - *q = 300; - printf("*%d:%d*\n", *q, ((int)q)%2); - int *r = (int*)p; - *r = 515559; - printf("*%d*\n", *r); - long long *t = (long long*)p; - *t = 42949672960; - printf("*%Ld*\n", *t); - return 0; - } - ''' - - try: - self.do_run(src, '*300:1*\n*515559*\n*42949672960*\n') - except Exception, e: - assert 'must be aligned' in str(e), e # expected to fail without emulation - - def test_align64(self): - src = r''' - #include - - // 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 - src = ''' - #include - const signed char cvals[2] = { -1, -2 }; // compiler can store this is a string, so -1 becomes \FF, and needs re-signing - int main() - { - { - unsigned char x = 200; - printf("*%d*\\n", x); - unsigned char y = -22; - printf("*%d*\\n", y); - } - - int varey = 100; - unsigned int MAXEY = -1, MAXEY2 = -77; - printf("*%u,%d,%u*\\n", MAXEY, varey >= MAXEY, MAXEY2); // 100 >= -1? not in unsigned! - - int y = cvals[0]; - printf("*%d,%d,%d,%d*\\n", cvals[0], cvals[0] < 0, y, y < 0); - y = cvals[1]; - printf("*%d,%d,%d,%d*\\n", cvals[1], cvals[1] < 0, y, y < 0); - - // zext issue - see mathop in jsifier - unsigned char x8 = -10; - unsigned long hold = 0; - hold += x8; - int y32 = hold+50; - printf("*%u,%u*\\n", hold, y32); - - // Comparisons - x8 = 0; - for (int i = 0; i < 254; i++) x8++; // make it an actual 254 in JS - not a -2 - printf("*%d,%d*\\n", x8+1 == 0xff, x8+1 != 0xff); // 0xff may be '-1' in the bitcode - - return 0; - } - ''' - self.do_run(src, '*4294967295,0,4294967219*\n*-1,1,-1,1*\n*-2,1,-2,1*\n*246,296*\n*1,0*') - - # Now let's see some code that should just work in USE_TYPED_ARRAYS == 2, but requires - # corrections otherwise - if Settings.USE_TYPED_ARRAYS == 2: - Settings.CORRECT_SIGNS = 0 - Settings.CHECK_SIGNS = 1 if not Settings.ASM_JS else 0 - else: - Settings.CORRECT_SIGNS = 1 - Settings.CHECK_SIGNS = 0 - - src = ''' - #include - int main() - { - { - unsigned char x; - unsigned char *y = &x; - *y = -1; - printf("*%d*\\n", x); - } - { - unsigned short x; - unsigned short *y = &x; - *y = -1; - printf("*%d*\\n", x); - } - /*{ // This case is not checked. The hint for unsignedness is just the %u in printf, and we do not analyze that - unsigned int x; - unsigned int *y = &x; - *y = -1; - printf("*%u*\\n", x); - }*/ - { - char x; - char *y = &x; - *y = 255; - printf("*%d*\\n", x); - } - { - char x; - char *y = &x; - *y = 65535; - printf("*%d*\\n", x); - } - { - char x; - char *y = &x; - *y = 0xffffffff; - printf("*%d*\\n", x); - } - return 0; - } - ''' - self.do_run(src, '*255*\n*65535*\n*-1*\n*-1*\n*-1*') - - def test_bitfields(self): - if self.emcc_args is None: Settings.SAFE_HEAP = 0 # bitfields do loads on invalid areas, by design - src = ''' - #include - struct bitty { - unsigned x : 1; - unsigned y : 1; - unsigned z : 1; - }; - int main() - { - bitty b; - printf("*"); - for (int i = 0; i <= 1; i++) - for (int j = 0; j <= 1; j++) - for (int k = 0; k <= 1; k++) { - b.x = i; - b.y = j; - b.z = k; - printf("%d,%d,%d,", b.x, b.y, b.z); - } - printf("*\\n"); - return 0; - } - ''' - self.do_run(src, '*0,0,0,0,0,1,0,1,0,0,1,1,1,0,0,1,0,1,1,1,0,1,1,1,*') - - def test_floatvars(self): - src = ''' - #include - - // headers test, see issue #1013 - #include - #include - - int main(int argc, char **argv) - { - float x = 1.234, y = 3.5, q = 0.00000001; - y *= 3; - int z = x < y; - printf("*%d,%d,%.1f,%d,%.4f,%.2f*\\n", z, int(y), y, (int)x, x, q); - - printf("%.2f, %.2f, %.2f, %.2f\\n", fmin(0.5, 3.3), fmin(NAN, 3.3), fmax(0.5, 3.3), fmax(NAN, 3.3)); - - printf("small: %.10f\\n", argc * 0.000001); - - /* - // Rounding behavior - float fs[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 }; - double ds[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 }; - for (int i = 0; i < 6; i++) - printf("*int(%.2f)=%d,%d*\\n", fs[i], int(fs[i]), int(ds[i])); - */ - - return 0; - } - ''' - self.do_run(src, '*1,10,10.5,1,1.2340,0.00*\n0.50, 3.30, 3.30, 3.30\nsmall: 0.0000010000\n') - - def test_isnan(self): - src = r''' - #include - - int IsNaN(double x){ - int rc; /* The value return */ - volatile double y = x; - volatile double z = y; - rc = (y!=z); - return rc; - } - - int main() { - double tests[] = { 1.0, 3.333, 1.0/0.0, 0.0/0.0, -1.0/0.0, -0, 0, -123123123, 12.0E200 }; - for (int i = 0; i < sizeof(tests)/sizeof(double); i++) - printf("%d - %f - %d\n", i, tests[i], IsNaN(tests[i])); - } - ''' - self.do_run(src, '''0 - 1.000000 - 0 -1 - 3.333000 - 0 -2 - inf - 0 -3 - nan - 1 -4 - -inf - 0 -5 - 0.000000 - 0 -6 - 0.000000 - 0 -7 - -123123123.000000 - 0 -8 - 1.2e+201 - 0 -''') - - def test_globaldoubles(self): - src = r''' - #include - #include - - double testVu, testVv, testWu, testWv; - - void Test(double _testVu, double _testVv, double _testWu, double _testWv) - { - testVu = _testVu; -