'''
Simple test runner
See settings.py file for options¶ms. Edit as needed.
'''
from subprocess import Popen, PIPE, STDOUT
import os, unittest, tempfile, shutil, time, inspect, sys, math
# Params
abspath = os.path.abspath(os.path.dirname(__file__))
def path_from_root(pathelems):
return os.path.join(os.path.sep, *(abspath.split(os.sep)[:-1] + pathelems))
EMSCRIPTEN = path_from_root(['emscripten.py'])
exec(open(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'settings.py'), 'r').read())
def timeout_run(proc, timeout, note):
start = time.time()
if timeout is not None:
while time.time() - start < timeout and proc.poll() is None:
time.sleep(0.1)
if proc.poll() is None:
proc.kill() # XXX bug: killing emscripten.py does not kill it's child process!
raise Exception("Timed out: " + note)
return proc.communicate()[0]
class RunnerCore(unittest.TestCase):
def get_dir(self):
dirname = TEMP_DIR + '/tmp' # tempfile.mkdtemp(dir=TEMP_DIR)
if not os.path.exists(dirname):
os.makedirs(dirname)
return dirname
## Build JavaScript code from source code
def build(self, src, dirname, filename, output_processor=None, main_file=None):
# Copy over necessary files for compiling the source
if main_file is None:
f = open(filename, 'w')
f.write(src)
f.close()
else:
# copy whole directory, and use a specific main .cpp file
for f in os.listdir(src):
shutil.copy(os.path.join(src, f), dirname)
shutil.move(os.path.join(dirname, main_file), filename)
# Copy Emscripten C++ API
shutil.copy(path_from_root(['src', 'include', 'emscripten.h']), dirname)
# C++ => LLVM binary
try:
# Make sure we notice if compilation steps failed
os.remove(filename + '.o')
os.remove(filename + '.o.ll')
except:
pass
os.chdir(dirname)
cwd = os.getcwd()
output = Popen([COMPILER, '-DEMSCRIPTEN', '-emit-llvm'] + COMPILER_OPTS + ['-c', filename, '-o', filename + '.o'], stdout=PIPE, stderr=STDOUT).communicate()[0]
os.chdir(cwd)
if not os.path.exists(filename + '.o'):
print "Failed to compile C/C++ source:\n\n", output
raise Exception("Compilation error");
# LLVM binary ==> LLVM assembly
output = Popen([LLVM_DIS, filename + '.o'] + LLVM_DIS_OPTS + ['-o=' + filename + '.o.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
# Run Emscripten
emscripten_settings = ['{ "QUANTUM_SIZE": %d, "RELOOP": %d, "OPTIMIZE": %d, "GUARD_MEMORY": %d }' % (QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY)]
out = open(filename + '.o.js', 'w') if not OUTPUT_TO_SCREEN else None
timeout_run(Popen([EMSCRIPTEN, filename + '.o.ll', PARSER_ENGINE] + emscripten_settings, stdout=out, stderr=STDOUT), 240, 'Compiling')
output = open(filename + '.o.js').read()
if output_processor is not None:
output_processor(output)
if output is not None and 'Traceback' in output: print output; assert 0
def run_generated_code(self, filename, args=[], check_timeout=True):
return timeout_run(Popen([JS_ENGINE] + JS_ENGINE_OPTS + [filename] + ([] if JS_ENGINE == SPIDERMONKEY_ENGINE else ['--']) + args,
stdout=PIPE, stderr=STDOUT), 120 if check_timeout else None, 'Execution')
if 'benchmark' not in sys.argv:
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_test(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None):
if not no_build:
print 'Running test:', inspect.stack()[1][3].replace('test_', ''), '[%s%s]' % (COMPILER.split(os.sep)[-1], ',reloop&optimize' if RELOOP else '')
dirname = self.get_dir()
filename = os.path.join(dirname, 'src.cpp')
if not no_build:
self.build(src, dirname, filename, output_processor, main_file)
# Run
js_output = self.run_generated_code(filename + '.o.js', args)
if output_nicerizer is not None:
js_output = output_nicerizer(js_output)
self.assertContained(expected_output, js_output)
self.assertNotContained('ERROR', js_output)
#shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging
def assertContained(self, value, string):
if value not in string:
print "Expected to find '%s' in '%s'" % (value, string)
self.assertTrue(value in string)
def assertNotContained(self, value, string):
if value in string:
print "Expected to NOT find '%s' in '%s'" % (value, string)
self.assertTrue(value not in string)
def test_hello_world(self):
src =