'''
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
exported_settings = {}
for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'GUARD_MEMORY', 'USE_TYPED_ARRAYS']:
exported_settings[setting] = eval(setting)
out = open(filename + '.o.js', 'w') if not OUTPUT_TO_SCREEN else None
timeout_run(Popen([EMSCRIPTEN, filename + '.o.ll', COMPILER_ENGINE[0], str(exported_settings).replace("'", '"')], 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, engine, filename, args=[], check_timeout=True):
return timeout_run(Popen(engine + [filename] + ([] if engine == SPIDERMONKEY_ENGINE else ['--']) + args,
stdout=PIPE, stderr=STDOUT), 30 if check_timeout else None, 'Execution')
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)
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 =