2012-01-13 02:08:09 +04:00
#!/usr/bin/env python
2010-08-26 08:01:10 +04:00
'''
Simple test runner
2010-09-05 08:32:35 +04:00
See settings . py file for options & params . Edit as needed .
2011-10-14 04:33:04 +04:00
These tests can be run in parallel using nose , for example
2011-10-16 20:48:15 +04:00
nosetests - - processes = 4 - v - s tests / runner . py
2011-10-14 04:33:04 +04:00
will use 4 processes . To install nose do something like
| pip install nose | or | sudo apt - get install python - nose | .
2010-08-26 08:01:10 +04:00
'''
from subprocess import Popen , PIPE , STDOUT
2012-01-31 06:21:19 +04:00
import os , unittest , tempfile , shutil , time , inspect , sys , math , glob , tempfile , re , difflib , webbrowser , hashlib , BaseHTTPServer , threading , platform
2010-08-26 08:01:10 +04:00
2011-01-15 09:44:52 +03:00
# Setup
2010-08-26 08:01:10 +04:00
2012-01-31 02:10:57 +04:00
__rootpath__ = os . path . dirname ( os . path . dirname ( os . path . abspath ( __file__ ) ) )
2011-01-15 09:44:52 +03:00
def path_from_root ( * pathelems ) :
2011-10-05 21:50:13 +04:00
return os . path . join ( __rootpath__ , * pathelems )
2011-12-21 09:22:05 +04:00
sys . path + = [ path_from_root ( ' ' ) ]
2012-01-31 23:07:55 +04:00
import tools . shared
2012-01-31 02:10:57 +04:00
from tools . shared import *
2011-12-21 09:22:05 +04:00
2011-01-15 09:44:52 +03:00
# Sanity check for config
2010-09-10 07:03:24 +04:00
2011-01-15 09:44:52 +03:00
try :
2011-03-19 20:00:57 +03:00
assert COMPILER_OPTS != None
2011-01-15 09:44:52 +03:00
except :
2012-01-29 00:29:43 +04:00
raise Exception ( ' Cannot find " COMPILER_OPTS " definition. Is %s set up properly? You may need to copy the template from settings.py into it. ' % EM_CONFIG )
2010-08-26 08:01:10 +04:00
2011-01-30 08:52:21 +03:00
# Core test runner class, shared between normal tests and benchmarks
2010-10-10 03:54:23 +04:00
class RunnerCore ( unittest . TestCase ) :
2011-11-25 08:50:45 +04:00
save_dir = os . environ . get ( ' EM_SAVE_DIR ' )
2011-10-23 00:13:51 +04:00
save_JS = 0
2012-01-03 07:21:57 +04:00
stderr_redirect = STDOUT # This avoids cluttering the test runner output, which is stderr too, with compiler warnings etc.
# Change this to None to get stderr reporting, for debugging purposes
2011-10-23 00:13:51 +04:00
2011-10-13 03:36:50 +04:00
def setUp ( self ) :
2012-01-31 23:07:55 +04:00
global Settings
2011-12-06 22:39:21 +04:00
Settings . reset ( )
2012-01-31 23:07:55 +04:00
Settings = tools . shared . Settings
2011-12-04 08:09:11 +04:00
self . banned_js_engines = [ ]
2011-10-23 00:13:51 +04:00
if not self . save_dir :
2011-12-23 05:59:33 +04:00
dirname = tempfile . mkdtemp ( prefix = ' emscripten_test_ ' + self . __class__ . __name__ + ' _ ' , dir = TEMP_DIR )
2011-10-16 20:48:15 +04:00
else :
2011-12-23 05:59:33 +04:00
dirname = EMSCRIPTEN_TEMP_DIR
2011-10-13 03:36:50 +04:00
if not os . path . exists ( dirname ) :
os . makedirs ( dirname )
self . working_dir = dirname
2011-11-20 01:37:26 +04:00
os . chdir ( dirname )
2011-10-13 03:36:50 +04:00
2011-04-23 04:25:01 +04:00
def tearDown ( self ) :
2011-10-23 00:13:51 +04:00
if self . save_JS :
2011-04-23 04:25:01 +04:00
for name in os . listdir ( self . get_dir ( ) ) :
2011-04-25 04:57:01 +04:00
if name . endswith ( ( ' .o.js ' , ' .cc.js ' ) ) :
suff = ' . ' . join ( name . split ( ' . ' ) [ - 2 : ] )
2011-04-23 04:25:01 +04:00
shutil . copy ( os . path . join ( self . get_dir ( ) , name ) ,
2011-04-25 04:57:01 +04:00
os . path . join ( TEMP_DIR , self . id ( ) . replace ( ' __main__. ' , ' ' ) . replace ( ' .test_ ' , ' . ' ) + ' . ' + suff ) )
2011-10-23 00:13:51 +04:00
if not self . save_dir :
2011-10-16 20:48:15 +04:00
shutil . rmtree ( self . get_dir ( ) )
2011-04-23 04:25:01 +04:00
2011-09-03 03:03:33 +04:00
def skip ( self , why ) :
print >> sys . stderr , ' <skipping: %s > ' % why ,
2011-04-23 00:23:37 +04:00
2010-10-10 03:54:23 +04:00
def get_dir ( self ) :
2011-10-13 03:36:50 +04:00
return self . working_dir
2010-10-10 03:54:23 +04:00
2012-01-31 06:21:19 +04:00
def get_shared_library_name ( self , linux_name ) :
if platform . system ( ) == ' Linux ' :
return linux_name
elif platform . system ( ) == ' Darwin ' :
return linux_name . replace ( ' .so ' , ' ' ) + ' .dylib '
else :
print >> sys . stderr , ' get_shared_library_name needs to be implemented on %s ' % platform . system ( )
return linux_name
2011-11-17 22:16:42 +04:00
def get_stdout_path ( self ) :
return os . path . join ( self . get_dir ( ) , ' stdout ' )
2011-10-13 18:40:29 +04:00
def prep_ll_run ( self , filename , ll_file , force_recompile = False , build_ll_hook = None ) :
2011-04-25 04:57:01 +04:00
if ll_file . endswith ( ( ' .bc ' , ' .o ' ) ) :
if ll_file != filename + ' .o ' :
shutil . copy ( ll_file , filename + ' .o ' )
2011-10-27 07:21:11 +04:00
Building . llvm_dis ( filename )
2011-04-25 04:57:01 +04:00
else :
shutil . copy ( ll_file , filename + ' .o.ll ' )
2011-11-27 22:48:06 +04:00
#force_recompile = force_recompile or os.stat(filename + '.o.ll').st_size > 50000 # if the file is big, recompile just to get ll_opts # Recompiling just for dfe in ll_opts is too costly
2011-04-25 04:57:01 +04:00
2011-10-27 07:41:51 +04:00
if Building . LLVM_OPTS or force_recompile or build_ll_hook :
2011-10-27 07:21:11 +04:00
Building . ll_opts ( filename )
2011-04-25 04:57:01 +04:00
if build_ll_hook :
2011-11-12 05:21:20 +04:00
need_post = build_ll_hook ( filename )
Building . llvm_as ( filename )
shutil . move ( filename + ' .o.ll ' , filename + ' .o.ll.pre ' ) # for comparisons later
2011-12-14 00:20:45 +04:00
if Building . LLVM_OPTS :
Building . llvm_opts ( filename )
2011-10-27 07:21:11 +04:00
Building . llvm_dis ( filename )
2011-11-12 05:21:20 +04:00
if build_ll_hook and need_post :
build_ll_hook ( filename )
Building . llvm_as ( filename )
shutil . move ( filename + ' .o.ll ' , filename + ' .o.ll.post ' ) # for comparisons later
Building . llvm_dis ( filename )
2011-04-25 04:57:01 +04:00
2011-12-22 03:15:25 +04:00
# Generate JS from ll, and optionally modify the generated JS with a post_build function. Note
# that post_build is called on unoptimized JS, so we send it to emcc (otherwise, if run after
# emcc, it would not apply on the optimized/minified JS)
def ll_to_js ( self , filename , extra_emscripten_args , post_build ) :
2012-02-04 03:00:45 +04:00
if type ( post_build ) in ( list , tuple ) :
post1 , post2 = post_build
else :
post1 = post_build
post2 = None
def run_post ( post ) :
if not post : return
exec post in locals ( )
shutil . copyfile ( filename + ' .o.js ' , filename + ' .o.js.prepost.js ' )
process ( filename + ' .o.js ' )
2011-12-22 03:15:25 +04:00
if self . emcc_args is None :
Building . emscripten ( filename , append_ext = True , extra_args = extra_emscripten_args )
2012-02-04 03:00:45 +04:00
run_post ( post1 )
run_post ( post2 )
2011-12-22 03:15:25 +04:00
else :
2012-01-05 02:36:02 +04:00
transform_args = [ ]
2012-02-04 03:00:45 +04:00
if post1 :
2012-01-05 02:36:02 +04:00
transform_filename = os . path . join ( self . get_dir ( ) , ' transform.py ' )
transform = open ( transform_filename , ' w ' )
transform . write ( '''
import sys
2012-01-05 03:15:49 +04:00
sys . path + = [ ' %s ' ]
''' % path_from_root( ' ' ))
2012-02-04 03:00:45 +04:00
transform . write ( post1 )
2012-01-05 02:36:02 +04:00
transform . write ( '''
process ( sys . argv [ 1 ] )
''' )
transform . close ( )
transform_args = [ ' --js-transform ' , " python %s " % transform_filename ]
Building . emcc ( filename + ' .o.ll ' , Settings . serialize ( ) + self . emcc_args + transform_args , filename + ' .o.js ' )
2012-02-04 03:00:45 +04:00
run_post ( post2 )
2011-12-22 03:15:25 +04:00
2011-01-08 07:44:14 +03:00
# Build JavaScript code from source code
2011-12-21 06:49:42 +04:00
def build ( self , src , dirname , filename , output_processor = None , main_file = None , additional_files = [ ] , libraries = [ ] , includes = [ ] , build_ll_hook = None , extra_emscripten_args = [ ] , post_build = None ) :
2011-12-22 03:15:25 +04:00
2012-01-24 02:11:41 +04:00
Building . pick_llvm_opts ( 3 ) # pick llvm opts here, so we include changes to Settings in the test case code
2012-01-21 22:33:08 +04:00
2010-10-10 03:54:23 +04:00
# Copy over necessary files for compiling the source
if main_file is None :
f = open ( filename , ' w ' )
f . write ( src )
f . close ( )
2012-01-17 07:30:57 +04:00
final_additional_files = [ ]
for f in additional_files :
final_additional_files . append ( os . path . join ( dirname , os . path . basename ( f ) ) )
shutil . copyfile ( f , final_additional_files [ - 1 ] )
additional_files = final_additional_files
2010-10-10 03:54:23 +04:00
else :
# copy whole directory, and use a specific main .cpp file
2011-01-18 02:36:26 +03:00
shutil . rmtree ( dirname )
shutil . copytree ( src , dirname )
2010-10-10 03:54:23 +04:00
shutil . move ( os . path . join ( dirname , main_file ) , filename )
2011-01-18 02:36:26 +03:00
# the additional files were copied; alter additional_files to point to their full paths now
additional_files = map ( lambda f : os . path . join ( dirname , f ) , additional_files )
2012-01-20 04:18:57 +04:00
os . chdir ( self . get_dir ( ) )
2010-10-10 03:54:23 +04:00
# C++ => LLVM binary
2011-09-04 21:52:59 +04:00
2011-01-18 02:36:26 +03:00
for f in [ filename ] + additional_files :
try :
# Make sure we notice if compilation steps failed
os . remove ( f + ' .o ' )
except :
pass
2012-01-03 00:44:49 +04:00
args = [ Building . COMPILER , ' -emit-llvm ' ] + COMPILER_OPTS + Building . COMPILER_TEST_OPTS + \
[ ' -I ' , dirname , ' -I ' , os . path . join ( dirname , ' include ' ) ] + \
map ( lambda include : ' -I ' + include , includes ) + \
[ ' -c ' , f , ' -o ' , f + ' .o ' ]
2012-01-03 07:21:57 +04:00
output = Popen ( args , stdout = PIPE , stderr = self . stderr_redirect ) . communicate ( ) [ 0 ]
2011-02-28 03:55:53 +03:00
assert os . path . exists ( f + ' .o ' ) , ' Source compilation error: ' + output
2011-01-18 02:36:26 +03:00
# Link all files
2011-01-24 05:23:44 +03:00
if len ( additional_files ) + len ( libraries ) > 0 :
2011-01-18 02:36:26 +03:00
shutil . move ( filename + ' .o ' , filename + ' .o.alone ' )
2011-10-27 07:16:22 +04:00
Building . link ( [ filename + ' .o.alone ' ] + map ( lambda f : f + ' .o ' , additional_files ) + libraries ,
2011-10-25 02:20:01 +04:00
filename + ' .o ' )
2011-01-18 02:36:26 +03:00
if not os . path . exists ( filename + ' .o ' ) :
print " Failed to link LLVM binaries: \n \n " , output
raise Exception ( " Linkage error " ) ;
# Finalize
2011-10-13 18:40:29 +04:00
self . prep_ll_run ( filename , filename + ' .o ' , build_ll_hook = build_ll_hook )
2011-03-03 18:39:33 +03:00
2011-12-21 04:38:14 +04:00
# BC => JS
2011-12-22 03:15:25 +04:00
self . ll_to_js ( filename , extra_emscripten_args , post_build )
2011-12-21 04:38:14 +04:00
if output_processor is not None :
output_processor ( open ( filename + ' .o.js ' ) . read ( ) )
2010-10-10 03:54:23 +04:00
2010-10-11 09:52:54 +04:00
def run_generated_code ( self , engine , filename , args = [ ] , check_timeout = True ) :
2011-02-28 03:54:21 +03:00
stdout = os . path . join ( self . get_dir ( ) , ' stdout ' ) # use files, as PIPE can get too full and hang us
stderr = os . path . join ( self . get_dir ( ) , ' stderr ' )
2011-03-17 01:31:12 +03:00
try :
cwd = os . getcwd ( )
except :
cwd = None
os . chdir ( self . get_dir ( ) )
2011-12-12 06:31:10 +04:00
run_js ( filename , engine , args , check_timeout , stdout = open ( stdout , ' w ' ) , stderr = open ( stderr , ' w ' ) )
2011-03-17 01:31:12 +03:00
if cwd is not None :
os . chdir ( cwd )
2011-02-28 03:54:21 +03:00
ret = open ( stdout , ' r ' ) . read ( ) + open ( stderr , ' r ' ) . read ( )
assert ' strict warning: ' not in ret , ' We should pass all strict mode checks: ' + ret
2011-02-21 06:03:14 +03:00
return ret
2010-10-10 03:54:23 +04:00
2011-11-17 23:57:15 +04:00
def build_native ( self , filename ) :
2011-11-18 02:44:42 +04:00
Popen ( [ CLANG , ' -O2 ' , filename , ' -o ' , filename + ' .native ' ] , stdout = PIPE ) . communicate ( ) [ 0 ]
2011-06-12 00:52:03 +04:00
def run_native ( self , filename , args ) :
2011-11-18 02:44:42 +04:00
Popen ( [ filename + ' .native ' ] + args , stdout = PIPE ) . communicate ( ) [ 0 ]
2011-06-12 00:52:03 +04:00
2011-11-01 04:38:27 +04:00
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 ' ) ] ) )
) )
2011-12-11 23:54:22 +04:00
def assertContained ( self , values , string , additional_info = ' ' ) :
2011-12-08 03:36:35 +04:00
if type ( values ) not in [ list , tuple ] : values = [ values ]
for value in values :
if type ( string ) is not str : string = string ( )
if value in string : return # success
2011-12-11 23:54:22 +04:00
raise Exception ( " Expected to find ' %s ' in ' %s ' , diff: \n \n %s \n %s " % (
2011-12-08 03:36:35 +04:00
limit_size ( values [ 0 ] ) , limit_size ( string ) ,
2011-12-11 23:54:22 +04:00
limit_size ( ' ' . join ( [ a . rstrip ( ) + ' \n ' for a in difflib . unified_diff ( values [ 0 ] . split ( ' \n ' ) , string . split ( ' \n ' ) , fromfile = ' expected ' , tofile = ' actual ' ) ] ) ) ,
additional_info
2011-12-08 03:36:35 +04:00
) )
2010-10-15 10:07:23 +04:00
def assertNotContained ( self , value , string ) :
2011-03-16 06:13:57 +03:00
if type ( value ) is not str : value = value ( ) # lazy loading
if type ( string ) is not str : string = string ( )
2010-10-15 10:07:23 +04:00
if value in string :
2011-09-07 07:40:20 +04:00
raise Exception ( " Expected to NOT find ' %s ' in ' %s ' , diff: \n \n %s " % (
limit_size ( value ) , limit_size ( string ) ,
limit_size ( ' ' . join ( [ a . rstrip ( ) + ' \n ' for a in difflib . unified_diff ( value . split ( ' \n ' ) , string . split ( ' \n ' ) , fromfile = ' expected ' , tofile = ' actual ' ) ] ) )
) )
2010-10-15 10:07:23 +04:00
2011-10-27 07:16:22 +04:00
library_cache = { }
def get_library ( self , name , generated_libs , configure = [ ' ./configure ' ] , configure_args = [ ] , make = [ ' make ' ] , make_args = [ ' -j ' , ' 2 ' ] , cache = True ) :
build_dir = self . get_build_dir ( )
output_dir = self . get_dir ( )
2011-10-27 07:41:51 +04:00
cache_name = name + ' | ' + Building . COMPILER
2011-10-27 07:16:22 +04:00
if self . library_cache is not None :
if cache and self . library_cache . get ( cache_name ) :
print >> sys . stderr , ' <load build from cache> ' ,
bc_file = os . path . join ( output_dir , ' lib ' + name + ' .bc ' )
f = open ( bc_file , ' wb ' )
f . write ( self . library_cache [ cache_name ] )
f . close ( )
return bc_file
print >> sys . stderr , ' <building and saving into cache> ' ,
2011-10-27 07:41:51 +04:00
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 )
2011-10-27 07:16:22 +04:00
2011-01-02 09:59:55 +03:00
###################################################################################################
2011-12-07 03:57:25 +04:00
sys . argv = map ( lambda arg : arg if not arg . startswith ( ' test_ ' ) else ' default. ' + arg , sys . argv )
2012-01-21 05:58:23 +04:00
Cache . erase ( ) # Wipe the cache, so that we always test populating it in the tests, benchmarks, etc.
2011-12-18 23:34:19 +04:00
if ' benchmark ' not in str ( sys . argv ) and ' sanity ' not in str ( sys . argv ) :
2011-01-02 09:59:55 +03:00
# Tests
print " Running Emscripten tests... "
2010-10-10 03:54:23 +04:00
class T ( RunnerCore ) : # Short name, to make it more fun to use manually on the commandline
2010-10-08 07:00:52 +04:00
## Does a complete test - builds, runs, checks output, etc.
2012-01-27 22:22:14 +04:00
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 = [ ] ) :
2011-01-31 18:43:01 +03:00
if force_c or ( main_file is not None and main_file [ - 2 : ] ) == ' .c ' :
basename = ' src.c '
2011-10-27 07:41:51 +04:00
Building . COMPILER = to_cc ( Building . COMPILER )
2011-01-31 18:43:01 +03:00
2010-10-10 03:54:23 +04:00
dirname = self . get_dir ( )
2010-11-17 07:05:51 +03:00
filename = os . path . join ( dirname , basename )
2010-08-26 08:01:10 +04:00
if not no_build :
2011-03-03 18:39:33 +03:00
self . build ( src , dirname , filename , main_file = main_file , additional_files = additional_files , libraries = libraries , includes = includes ,
2011-12-21 06:49:42 +04:00
build_ll_hook = build_ll_hook , extra_emscripten_args = extra_emscripten_args , post_build = post_build )
2010-11-06 06:48:19 +03:00
2010-10-11 09:52:54 +04:00
# Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
2010-10-27 06:13:01 +04:00
if js_engines is None :
2011-12-04 08:09:11 +04:00
js_engines = JS_ENGINES
2011-11-14 08:45:14 +04:00
if Settings . USE_TYPED_ARRAYS :
2011-12-04 08:09:11 +04:00
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 )
2012-01-29 00:29:43 +04:00
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 )
2010-10-27 06:13:01 +04:00
for engine in js_engines :
2012-01-14 05:28:22 +04:00
engine = filter ( lambda arg : arg != ' -n ' , engine ) # SpiderMonkey issue 716255
2010-10-11 09:52:54 +04:00
js_output = self . run_generated_code ( engine , 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 )
2010-09-24 07:21:03 +04:00
2010-10-02 23:03:07 +04:00
#shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging
2010-08-26 08:01:10 +04:00
2011-01-24 05:23:44 +03:00
# No building - just process an existing .ll file (or .bc, which we turn into .ll)
2011-10-13 18:40:29 +04:00
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 = [ ] ) :
2011-01-24 05:23:44 +03:00
filename = os . path . join ( self . get_dir ( ) , ' src.cpp ' )
2011-10-13 18:40:29 +04:00
self . prep_ll_run ( filename , ll_file , force_recompile , build_ll_hook )
2011-12-22 03:15:25 +04:00
self . ll_to_js ( filename , extra_emscripten_args , post_build )
2011-10-13 18:40:29 +04:00
self . do_run ( None ,
2011-03-03 06:12:13 +03:00
expected_output ,
2010-11-21 05:38:44 +03:00
args ,
2010-11-21 02:43:17 +03:00
no_build = True ,
2011-01-08 07:44:14 +03:00
js_engines = js_engines ,
2011-01-17 10:22:57 +03:00
output_nicerizer = output_nicerizer ,
2011-12-22 03:15:25 +04:00
post_build = None ) # post_build was already done in ll_to_js, this do_run call is just to test the output
2010-11-21 02:43:17 +03:00
2010-08-26 08:01:10 +04:00
def test_hello_world ( self ) :
src = '''
#include <stdio.h>
int main ( )
{
printf ( " hello, world! \\ n " ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' hello, world! ' )
2010-08-26 08:01:10 +04:00
def test_intvars ( self ) :
src = '''
#include <stdio.h>
2010-09-04 10:04:23 +04:00
int global = 20 ;
2010-09-04 10:18:37 +04:00
int * far ;
2010-08-26 08:01:10 +04:00
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 ;
2010-09-04 10:18:37 +04:00
far = & k ;
* far + = global ;
2010-08-26 08:01:10 +04:00
int i = k > 100 ; / / Should be an int , not a bool !
2010-09-03 07:05:14 +04:00
int j = i << 6 ;
j >> = 1 ;
2010-09-03 07:27:29 +04:00
j = j ^ 5 ;
2010-09-03 07:37:30 +04:00
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 ) ;
2010-12-05 07:26:28 +03:00
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 " ) ;
2010-12-26 10:48:05 +03:00
printf ( " * %.1d , %.2d * \\ n " , 56 , 9 ) ;
2011-02-05 07:58:35 +03:00
2011-05-24 18:33:53 +04:00
/ / 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 ) ) ;
}
2010-12-12 05:39:03 +03:00
printf ( " * %ld * % p \\ n " , ( long ) 21 , & hash ) ; / / The % p should not enter an infinite loop !
2010-08-26 08:01:10 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *5,23,10,19,121,1,37,1,0* \n 0:-1,1:134217727,2:4194303,3:131071,4:4095,5:127,6:3,7:0,8:0* \n *56,09* \n fixed:320434 \n *21* ' )
2010-08-26 08:01:10 +04:00
2011-02-06 07:06:11 +03:00
def test_sintvars ( self ) :
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 1 # Relevant to this test
2011-02-06 07:06:11 +03:00
src = '''
#include <stdio.h>
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* '
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 0 # We should not need overflow correction to get this right
2011-10-13 18:40:29 +04:00
self . do_run ( src , output , force_c = True )
2011-02-06 07:06:11 +03:00
2011-11-10 05:48:15 +04:00
def test_i64 ( self ) :
2011-11-11 01:01:44 +04:00
for i64_mode in [ 0 , 1 ] :
if i64_mode == 0 and Settings . USE_TYPED_ARRAYS != 0 : continue # Typed arrays truncate i64
2011-11-13 22:34:00 +04:00
if i64_mode == 1 and Settings . QUANTUM_SIZE == 1 : continue # TODO: i64 mode 1 for q1
2011-11-10 05:48:15 +04:00
Settings . I64_MODE = i64_mode
src = '''
#include <stdio.h>
int main ( )
{
2012-01-25 04:03:47 +04:00
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 ) ;
2011-11-10 05:48:15 +04:00
long long x = 0x0000def123450789 ULL ; / / any bigger than this , and we
long long y = 0x00020ef123456089 ULL ; / / 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 ;
2011-09-11 05:52:35 +04:00
}
2011-11-10 05:48:15 +04:00
'''
2012-01-25 04:03:47 +04:00
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* ' )
2011-11-10 05:48:15 +04:00
2011-11-13 22:34:00 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' TODO: i64 mode 1 for q1 ' )
2011-11-10 05:48:15 +04:00
# Stuff that only works in i64_mode = 1
2011-11-11 01:01:44 +04:00
Settings . I64_MODE = 1
2011-11-18 08:28:32 +04:00
2011-11-11 01:26:35 +04:00
src = r '''
2011-11-12 03:30:21 +04:00
#include <time.h>
2011-11-11 01:01:44 +04:00
#include <stdio.h>
#include <stdint.h>
2011-11-11 01:26:35 +04:00
int64_t returner1 ( ) { return 0x0000def123450789 ULL ; }
int64_t returner2 ( int test ) {
while ( test > 10 ) test / = 2 ; / / confuse the compiler so it doesn ' t eliminate this function
return test > 5 ? 0x0000def123450123 ULL : 0 ULL ;
}
2011-11-11 01:01:44 +04:00
2011-11-11 01:36:13 +04:00
void modifier1 ( int64_t t ) {
t | = 12 ;
printf ( " m1: %Ld \n " , t ) ;
}
void modifier2 ( int64_t & t ) {
t | = 12 ;
}
2011-11-12 03:30:21 +04:00
int truthy ( ) {
int x = time ( 0 ) ;
while ( x > 10 ) {
x | = 7 ;
x / = 2 ;
}
return x < 3 ;
}
2011-11-27 09:14:00 +04:00
struct IUB {
int c ;
long long d ;
} ;
IUB iub [ ] = {
2011-11-27 09:52:01 +04:00
{ 55 , 17179869201 } ,
{ 122 , 25769803837 } ,
2011-11-27 09:14:00 +04:00
} ;
2012-02-02 04:54:44 +04:00
int main ( int argc , char * * argv )
2011-11-11 01:01:44 +04:00
{
int64_t x1 = 0x1234def123450789 ULL ;
int64_t x2 = 0x1234def123450788 ULL ;
int64_t x3 = 0x1234def123450789 ULL ;
2011-11-11 01:26:35 +04:00
printf ( " * %Ld \n %d , %d , %d , %d , %d \n %d , %d , %d , %d , %d * \n " , x1 , x1 == x2 , x1 < x2 , x1 < = x2 , x1 > x2 , x1 > = x2 , / / note : some rounding in the printing !
x1 == x3 , x1 < x3 , x1 < = x3 , x1 > x3 , x1 > = x3 ) ;
printf ( " * %Ld * \n " , returner1 ( ) ) ;
2011-11-11 01:36:13 +04:00
printf ( " * %Ld * \n " , returner2 ( 30 ) ) ;
2011-11-11 03:30:01 +04:00
uint64_t maxx = - 1 ULL ;
printf ( " * %Lu * \n * %Lu * \n " , maxx , maxx >> 5 ) ;
2011-11-11 02:46:47 +04:00
/ / Make sure params are not modified if they shouldn ' t be
2011-11-11 01:36:13 +04:00
int64_t t = 123 ;
modifier1 ( t ) ;
printf ( " * %Ld * \n " , t ) ;
modifier2 ( t ) ;
printf ( " * %Ld * \n " , t ) ;
2011-11-11 02:46:47 +04:00
2011-11-27 09:14:00 +04:00
/ / global structs with i64s
printf ( " * %d , %Ld * \n * %d , %Ld * \n " , iub [ 0 ] . c , iub [ 0 ] . d , iub [ 1 ] . c , iub [ 1 ] . d ) ;
2012-01-25 04:03:47 +04:00
/ / 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 ) ;
}
2012-02-02 04:54:44 +04:00
/ / 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 ) ;
}
2011-11-28 00:45:00 +04:00
/ / Math mixtures with doubles
{
uint64_t a = 5 ;
double b = 6.8 ;
uint64_t c = a * b ;
2012-01-25 04:03:47 +04:00
printf ( " *prod: % llu* \n * %d , %d , %d * \n " , c , ( int ) & a , ( int ) & b , ( int ) & c ) ; / / printing addresses prevents optimizations
2011-11-28 00:45:00 +04:00
}
2011-11-13 07:59:42 +04:00
/ / Basic ( rounded , for now ) math . Just check compilation .
2011-11-12 03:30:21 +04:00
int64_t a = 0x1234def123450789 ULL ;
a - - ; if ( truthy ( ) ) a - - ; / / confuse optimizer
int64_t b = 0x1234000000450789 ULL ;
b + + ; if ( truthy ( ) ) b - - ; / / confuse optimizer
2011-11-13 07:59:42 +04:00
printf ( " * %Ld , %Ld , %Ld , %Ld * \n " , ( a + b ) / 5000 , ( a - b ) / 5000 , ( a * 3 ) / 5000 , ( a / 5 ) / 5000 ) ;
2011-11-12 03:30:21 +04:00
2011-11-11 01:01:44 +04:00
return 0 ;
}
'''
2012-01-25 04:03:47 +04:00
self . do_run ( src , ' *1311918518731868200 \n ' +
' 0,0,0,1,1 \n ' +
' 1,0,1,0,1* \n ' +
' *245127260211081* \n ' +
' *245127260209443* \n ' +
' *18446744073709552000* \n ' +
' *576460752303423500* \n ' +
' m1: 127 \n ' +
' *123* \n ' +
' *127* \n ' +
' *55,17179869201* \n ' +
' *122,25769803837* \n ' +
' *-1,-1,-1,-1* \n ' +
' *-1,34359738367,4294967295,1073741823* \n ' +
2012-02-02 04:54:44 +04:00
' *-1,-1,-1,-1* \n ' +
' *-1,34359738367,4294967295,1073741823* \n ' +
2012-01-25 04:03:47 +04:00
' *prod:34* ' )
2011-05-25 18:16:26 +04:00
2012-02-03 04:05:57 +04:00
src = r '''
#include <stdio.h>
#include <limits>
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 < long long > : : min ( ) ? " Ok " : " Fail " ) ;
printf ( " %s \n " , i < std : : numeric_limits < long long > : : max ( ) ? " Ok " : " Fail " ) ;
printf ( " * \n " ) ;
}
'''
self . do_run ( src , ' * \n Ok \n Ok \n Ok \n Ok \n Ok \n Ok \n Ok \n Ok \n Ok \n Ok \n * ' )
# stuff that also needs sign corrections
2011-11-18 08:28:32 +04:00
Settings . CORRECT_SIGNS = 1
src = r '''
#include <stdio.h>
#include <stdint.h>
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 ;
}
'''
2011-11-22 04:59:37 +04:00
self . do_run ( src , ' *1* \n *0* \n *0* \n ' )
2011-11-18 08:28:32 +04:00
2011-11-17 00:49:07 +04:00
def test_unaligned ( self ) :
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' No meaning to unaligned addresses in q1 ' )
2011-12-07 03:16:09 +04:00
src = r '''
#include<stdio.h>
struct S {
double x ;
int y ;
} ;
int main ( ) {
/ / the 64 - bit value here will not always be 8 - byte aligned
S s [ 3 ] = { { 0x12a751f430142 , 22 } , { 0x17a5c85bad144 , 98 } , { 1 , 1 } } ;
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
self . do_run ( src , ' *12 : 1 : 12 \n 328157500735811.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
2011-11-17 00:49:07 +04:00
if Settings . USE_TYPED_ARRAYS != 2 : return self . skip ( ' No meaning to unaligned addresses without t2 ' )
src = r '''
#include <stdio.h>
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 ;
}
'''
Settings . EMULATE_UNALIGNED_ACCESSES = 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
# XXX TODO Settings.EMULATE_UNALIGNED_ACCESSES = 1
#self.do_run(src, '*300:1*\n*515559*\n*42949672960*\n') # but succeeds with it
2010-10-01 08:02:30 +04:00
def test_unsigned ( self ) :
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 1 # We test for exactly this sort of thing here
Settings . CHECK_SIGNS = 0
2010-10-01 08:02:30 +04:00
src = '''
#include <stdio.h>
2011-01-28 08:31:20 +03:00
const signed char cvals [ 2 ] = { - 1 , - 2 } ; / / compiler can store this is a string , so - 1 becomes \FF , and needs re - signing
2010-10-01 08:02:30 +04:00
int main ( )
{
2011-09-15 05:08:52 +04:00
{
unsigned char x = 200 ;
printf ( " * %d * \\ n " , x ) ;
unsigned char y = - 22 ;
printf ( " * %d * \\ n " , y ) ;
}
2010-10-01 08:02:30 +04:00
int varey = 100 ;
unsigned int MAXEY = - 1 , MAXEY2 = - 77 ;
printf ( " * %u , %d , %u * \\ n " , MAXEY , varey > = MAXEY , MAXEY2 ) ; / / 100 > = - 1 ? not in unsigned !
2011-01-28 08:31:20 +03:00
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 ) ;
2011-02-07 00:57:13 +03:00
/ / 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 ) ;
2011-03-05 19:02:38 +03:00
/ / 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
2010-10-01 08:02:30 +04:00
return 0 ;
}
'''
2012-01-27 22:22:14 +04:00
self . do_run ( src , ' *4294967295,0,4294967219* \n *-1,1,-1,1* \n *-2,1,-2,1* \n *246,296* \n *1,0* ' )
2010-10-01 08:02:30 +04:00
2011-06-09 06:11:25 +04:00
# Now let's see some code that should just work in USE_TYPED_ARRAYS == 2, but requires
# corrections otherwise
2011-10-21 23:08:44 +04:00
if Settings . USE_TYPED_ARRAYS == 2 :
Settings . CORRECT_SIGNS = 0
Settings . CHECK_SIGNS = 1
2011-06-09 06:11:25 +04:00
else :
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 1
Settings . CHECK_SIGNS = 0
2011-06-09 06:11:25 +04:00
src = '''
#include <stdio.h>
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 ) ;
}
2011-06-10 02:53:55 +04:00
/ * { / / This case is not checked . The hint for unsignedness is just the % u in printf , and we do not analyze that
2011-06-09 06:11:25 +04:00
unsigned int x ;
unsigned int * y = & x ;
* y = - 1 ;
printf ( " * %u * \\ n " , x ) ;
2011-06-10 02:53:55 +04:00
} * /
2011-06-09 06:11:25 +04:00
{
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 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *255* \n *65535* \n *-1* \n *-1* \n *-1* ' )
2011-06-09 06:11:25 +04:00
2010-12-10 07:09:11 +03:00
def test_bitfields ( self ) :
2012-01-24 08:22:07 +04:00
if self . emcc_args is None : Settings . SAFE_HEAP = 0 # bitfields do loads on invalid areas, by design
2010-12-10 07:09:11 +03:00
src = '''
#include <stdio.h>
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 ;
}
'''
2011-10-13 18:40:29 +04:00
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,* ' )
2010-12-10 07:09:11 +03:00
2010-08-29 00:38:43 +04:00
def test_floatvars ( self ) :
src = '''
#include <stdio.h>
int main ( )
{
2011-04-21 21:45:57 +04:00
float x = 1.234 , y = 3.5 , q = 0.00000001 ;
2010-08-29 00:38:43 +04:00
y * = 3 ;
2010-08-29 05:24:52 +04:00
int z = x < y ;
2011-04-21 21:45:57 +04:00
printf ( " * %d , %d , %.1f , %d , %.4f , %.2f * \\ n " , z , int ( y ) , y , ( int ) x , x , q ) ;
2011-02-28 07:36:30 +03:00
/ *
/ / 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 ] ) ) ;
* /
2010-08-29 00:38:43 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *1,10,10.5,1,1.2340,0.00* ' )
2010-08-29 00:38:43 +04:00
2010-09-25 07:04:29 +04:00
def test_math ( self ) :
src = '''
#include <stdio.h>
2012-01-25 09:46:51 +04:00
#include <stdlib.h>
2010-09-25 07:04:29 +04:00
#include <cmath>
int main ( )
{
2011-12-07 04:32:03 +04:00
printf ( " * %.2f , %.2f , %d " , M_PI , - M_PI , ( 1 / 0.0 ) > 1e300 ) ; / / could end up as infinity , or just a very very big number
2011-07-14 00:34:00 +04:00
printf ( " , %d " , finite ( NAN ) != 0 ) ;
printf ( " , %d " , finite ( INFINITY ) != 0 ) ;
printf ( " , %d " , finite ( - INFINITY ) != 0 ) ;
printf ( " , %d " , finite ( 12.3 ) != 0 ) ;
printf ( " , %d " , isinf ( NAN ) != 0 ) ;
printf ( " , %d " , isinf ( INFINITY ) != 0 ) ;
printf ( " , %d " , isinf ( - INFINITY ) != 0 ) ;
printf ( " , %d " , isinf ( 12.3 ) != 0 ) ;
2012-01-25 09:46:51 +04:00
div_t div_result = div ( 23 , 10 ) ;
printf ( " , %d " , div_result . quot ) ;
printf ( " , %d " , div_result . rem ) ;
double sine = - 1.0 , cosine = - 1.0 ;
sincos ( 0.0 , & sine , & cosine ) ;
printf ( " , %1.1lf " , sine ) ;
printf ( " , %1.1lf " , cosine ) ;
float fsine = - 1.0 f , fcosine = - 1.0 f ;
sincosf ( 0.0 , & fsine , & fcosine ) ;
printf ( " , %1.1f " , fsine ) ;
printf ( " , %1.1f " , fcosine ) ;
2011-07-14 00:25:44 +04:00
printf ( " * \\ n " ) ;
2010-09-25 07:04:29 +04:00
return 0 ;
}
'''
2012-01-25 09:46:51 +04:00
self . do_run ( src , ' *3.14,-3.14,1,0,0,0,1,0,1,1,0,2,3,0.0,1.0,0.0,1.0* ' )
2010-09-25 07:04:29 +04:00
2011-07-08 12:46:20 +04:00
def test_math_hyperbolic ( self ) :
src = open ( path_from_root ( ' tests ' , ' hyperbolic ' , ' src.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' hyperbolic ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-08 12:46:20 +04:00
2011-04-18 05:39:00 +04:00
def test_getgep ( self ) :
# Generated code includes getelementptr (getelementptr, 0, 1), i.e., GEP as the first param to GEP
src = '''
#include <stdio.h>
struct {
int y [ 10 ] ;
int z [ 10 ] ;
} commonblock ;
int main ( )
{
for ( int i = 0 ; i < 10 ; + + i ) {
commonblock . y [ i ] = 1 ;
commonblock . z [ i ] = 2 ;
}
printf ( " * %d %d * \\ n " , commonblock . y [ 0 ] , commonblock . z [ 0 ] ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *1 2* ' )
2011-04-18 05:39:00 +04:00
2010-08-26 08:01:10 +04:00
def test_if ( self ) :
src = '''
#include <stdio.h>
int main ( )
{
int x = 5 ;
if ( x > 3 ) {
printf ( " *yes* \\ n " ) ;
}
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *yes* ' )
2010-08-26 08:01:10 +04:00
2010-10-17 01:38:27 +04:00
def test_if_else ( self ) :
src = '''
#include <stdio.h>
int main ( )
{
int x = 5 ;
if ( x > 10 ) {
printf ( " *yes* \\ n " ) ;
} else {
printf ( " *no* \\ n " ) ;
}
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *no* ' )
2010-10-17 01:38:27 +04:00
2010-08-26 08:01:10 +04:00
def test_loop ( self ) :
src = '''
#include <stdio.h>
int main ( )
{
int x = 5 ;
2012-01-02 03:46:33 +04:00
for ( int i = 0 ; i < 6 ; i + + ) {
2010-08-26 08:01:10 +04:00
x + = x * i ;
2012-01-02 03:46:33 +04:00
if ( x > 1000 ) {
if ( x % 7 == 0 ) printf ( " cheez \\ n " ) ;
x / = 2 ;
break ;
}
}
2010-08-26 08:01:10 +04:00
printf ( " * %d * \\ n " , x ) ;
return 0 ;
}
'''
2012-01-02 03:46:33 +04:00
2012-01-27 22:22:14 +04:00
self . do_run ( src , ' *1800* ' )
2012-01-02 03:46:33 +04:00
generated = open ( ' src.cpp.o.js ' , ' r ' ) . read ( )
assert ' __label__ == ' not in generated , ' We should hoist into the loop '
2010-08-26 08:01:10 +04:00
2010-09-29 06:58:22 +04:00
def test_stack ( self ) :
src = '''
#include <stdio.h>
int test ( int i ) {
int x = 10 ;
if ( i > 0 ) {
return test ( i - 1 ) ;
}
2011-03-17 01:31:12 +03:00
return int ( & x ) ; / / both for the number , and forces x to not be nativized
2010-09-29 06:58:22 +04:00
}
int main ( )
{
/ / We should get the same value for the first and last - stack has unwound
int x1 = test ( 0 ) ;
int x2 = test ( 100 ) ;
int x3 = test ( 0 ) ;
printf ( " * %d , %d * \\ n " , x3 - x1 , x2 != x1 ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *0,1* ' )
2010-09-29 06:58:22 +04:00
2010-08-26 08:01:10 +04:00
def test_strings ( self ) :
src = '''
#include <stdio.h>
#include <stdlib.h>
2010-09-11 08:15:40 +04:00
#include <string.h>
2010-08-26 08:01:10 +04:00
int main ( int argc , char * * argv )
{
2010-12-29 06:52:41 +03:00
int x = 5 , y = 9 , magic = 7 ; / / fool compiler with magic
memmove ( & x , & y , magic - 7 ) ; / / 0 should not crash us
2011-01-17 10:22:57 +03:00
int xx , yy , zz ;
2011-08-28 20:47:53 +04:00
char s [ 32 ] ;
int cc = sscanf ( " abc_10.b1_xyz_543_defg " , " abc_ %d . %2x _xyz_ %3d _ %3s " , & xx , & yy , & zz , s ) ;
printf ( " %d : %d , %d , %d , %s \\ n " , cc , xx , yy , zz , s ) ;
2011-01-17 10:22:57 +03:00
printf ( " %d \\ n " , argc ) ;
2010-08-26 08:01:10 +04:00
puts ( argv [ 1 ] ) ;
puts ( argv [ 2 ] ) ;
2010-09-24 07:21:03 +04:00
printf ( " %d \\ n " , atoi ( argv [ 3 ] ) + 2 ) ;
2010-09-11 08:15:40 +04:00
const char * foolingthecompiler = " \\ rabcd " ;
2010-09-24 07:21:03 +04:00
printf ( " %d \\ n " , strlen ( foolingthecompiler ) ) ; / / Tests parsing / 0 D in llvm - should not be a 0 ( end string ) then a D !
printf ( " %s \\ n " , NULL ) ; / / Should print ' (null) ' , not the string at address 0 , which is a real address for us !
2010-12-29 06:52:20 +03:00
printf ( " /* a comment */ \\ n " ) ; / / Should not break the generated code !
printf ( " // another \\ n " ) ; / / Should not break the generated code !
2011-08-27 09:09:49 +04:00
char * strdup_val = strdup ( " test " ) ;
printf ( " %s \\ n " , strdup_val ) ;
free ( strdup_val ) ;
2010-08-26 08:01:10 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' 4:10,177,543,def \n 4 \n wowie \n too \n 76 \n 5 \n (null) \n /* a comment */ \n // another \n test \n ' , [ ' wowie ' , ' too ' , ' 74 ' ] )
2010-08-26 08:01:10 +04:00
2011-09-10 00:51:14 +04:00
def test_errar ( self ) :
2011-07-14 02:46:44 +04:00
src = r '''
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main ( ) {
char * err ;
char buffer [ 200 ] ;
err = strerror ( EDOM ) ;
strerror_r ( EWOULDBLOCK , buffer , 200 ) ;
printf ( " < %s > \n " , err ) ;
printf ( " < %s > \n " , buffer ) ;
printf ( " < %d > \n " , strerror_r ( EWOULDBLOCK , buffer , 0 ) ) ;
2011-07-14 19:38:01 +04:00
errno = 123 ;
printf ( " < %d > \n " , errno ) ;
2011-07-14 02:46:44 +04:00
return 0 ;
}
'''
expected = '''
< Numerical argument out of domain >
< Resource temporarily unavailable >
< 34 >
2011-07-14 19:38:01 +04:00
< 123 >
2011-07-14 02:46:44 +04:00
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( ' (^| \n ) \ s+ ' , ' \\ 1 ' , expected ) )
2011-07-14 02:46:44 +04:00
2010-12-29 07:36:26 +03:00
def test_mainenv ( self ) :
src = '''
#include <stdio.h>
int main ( int argc , char * * argv , char * * envp )
{
printf ( " * % p* \\ n " , envp ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *(nil)* ' )
2010-12-29 07:36:26 +03:00
2010-08-26 08:01:10 +04:00
def test_funcs ( self ) :
src = '''
#include <stdio.h>
int funcy ( int x )
{
return x * 9 ;
}
int main ( )
{
printf ( " * %d , %d * \\ n " , funcy ( 8 ) , funcy ( 10 ) ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *72,90* ' )
2010-08-26 08:01:10 +04:00
def test_structs ( self ) :
src = '''
#include <stdio.h>
struct S
{
int x , y ;
} ;
int main ( )
{
S a , b ;
a . x = 5 ; a . y = 6 ;
b . x = 101 ; b . y = 7009 ;
S * c , * d ;
c = & a ;
c - > x * = 2 ;
c = & b ;
c - > y - = 1 ;
d = c ;
d - > y + = 10 ;
printf ( " * %d , %d , %d , %d , %d , %d , %d , %d * \\ n " , a . x , a . y , b . x , b . y , c - > x , c - > y , d - > x , d - > y ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *10,6,101,7018,101,7018,101,7018* ' )
2010-08-26 08:01:10 +04:00
gen_struct_src = '''
#include <stdio.h>
#include <stdlib.h>
2010-09-08 06:23:00 +04:00
#include "emscripten.h"
2010-08-26 08:01:10 +04:00
struct S
{
int x , y ;
} ;
int main ( )
{
S * a = { { gen_struct } } ;
a - > x = 51 ; a - > y = 62 ;
printf ( " * %d , %d * \\ n " , a - > x , a - > y ) ;
{ { del_struct } } ( a ) ;
return 0 ;
}
'''
def test_mallocstruct ( self ) :
2011-10-13 18:40:29 +04:00
self . do_run ( self . gen_struct_src . replace ( ' {{ gen_struct}} ' , ' (S*)malloc(sizeof(S)) ' ) . replace ( ' {{ del_struct}} ' , ' free ' ) , ' *51,62* ' )
2010-08-26 08:01:10 +04:00
def test_newstruct ( self ) :
2011-10-13 18:40:29 +04:00
self . do_run ( self . gen_struct_src . replace ( ' {{ gen_struct}} ' , ' new S ' ) . replace ( ' {{ del_struct}} ' , ' delete ' ) , ' *51,62* ' )
2010-08-26 08:01:10 +04:00
def test_addr_of_stacked ( self ) :
src = '''
#include <stdio.h>
void alter ( int * y )
{
* y + = 5 ;
}
int main ( )
{
int x = 2 ;
alter ( & x ) ;
printf ( " * %d * \\ n " , x ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *7* ' )
2010-08-26 08:01:10 +04:00
2010-11-15 08:23:48 +03:00
def test_globals ( self ) :
src = '''
#include <stdio.h>
char cache [ 256 ] , * next = cache ;
int main ( )
{
cache [ 10 ] = 25 ;
next [ 20 ] = 51 ;
printf ( " * %d , %d * \\ n " , next [ 10 ] , cache [ 20 ] ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *25,51* ' )
2010-11-15 08:23:48 +03:00
2010-08-26 08:01:10 +04:00
def test_linked_list ( self ) :
src = '''
#include <stdio.h>
struct worker_args {
int value ;
struct worker_args * next ;
} ;
int main ( )
{
worker_args a ;
worker_args b ;
a . value = 60 ;
a . next = & b ;
b . value = 900 ;
b . next = NULL ;
worker_args * c = & a ;
int total = 0 ;
while ( c ) {
total + = c - > value ;
c = c - > next ;
}
2010-09-06 22:14:12 +04:00
/ / Chunk of em
worker_args chunk [ 10 ] ;
for ( int i = 0 ; i < 9 ; i + + ) {
chunk [ i ] . value = i * 10 ;
chunk [ i ] . next = & chunk [ i + 1 ] ;
}
chunk [ 9 ] . value = 90 ;
chunk [ 9 ] . next = & chunk [ 0 ] ;
c = chunk ;
do {
total + = c - > value ;
c = c - > next ;
} while ( c != chunk ) ;
2010-09-07 02:25:17 +04:00
printf ( " * %d , %d * \\ n " , total , b . next ) ;
/ / NULL * is * 0 , in C / C + + . No JS null ! ( null == 0 is false , etc . )
2010-08-26 08:01:10 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *1410,0* ' )
2010-09-07 02:25:17 +04:00
2011-01-30 03:55:59 +03:00
def test_sup ( self ) :
src = '''
#include <stdio.h>
struct S4 { int x ; } ; / / size : 4
struct S4_2 { short x , y ; } ; / / size : 4 , but for alignment purposes , 2
struct S6 { short x , y , z ; } ; / / size : 6
struct S6w { char x [ 6 ] ; } ; / / size : 6 also
struct S6z { int x ; short y ; } ; / / size : 8 , since we align to a multiple of the biggest - 4
struct C___ { S6 a , b , c ; int later ; } ;
struct Carr { S6 a [ 3 ] ; int later ; } ; / / essentially the same , but differently defined
struct C__w { S6 a ; S6w b ; S6 c ; int later ; } ; / / same size , different struct
struct Cp1_ { int pre ; short a ; S6 b , c ; int later ; } ; / / fillers for a
struct Cp2_ { int a ; short pre ; S6 b , c ; int later ; } ; / / fillers for a ( get addr of the other filler )
struct Cint { S6 a ; int b ; S6 c ; int later ; } ; / / An int ( different size ) for b
struct C4__ { S6 a ; S4 b ; S6 c ; int later ; } ; / / Same size as int from before , but a struct
struct C4_2 { S6 a ; S4_2 b ; S6 c ; int later ; } ; / / Same size as int from before , but a struct with max element size 2
struct C__z { S6 a ; S6z b ; S6 c ; int later ; } ; / / different size , 8 instead of 6
int main ( )
{
#define TEST(struc) \\
{ \\
struc * s = 0 ; \\
printf ( " * %s : %d , %d , %d , %d < %d * \\ n " , #struc, (int)&(s->a), (int)&(s->b), (int)&(s->c), (int)&(s->later), sizeof(struc)); \\
}
#define TEST_ARR(struc) \\
{ \\
struc * s = 0 ; \\
printf ( " * %s : %d , %d , %d , %d < %d * \\ n " , #struc, (int)&(s->a[0]), (int)&(s->a[1]), (int)&(s->a[2]), (int)&(s->later), sizeof(struc)); \\
}
printf ( " sizeofs: %d , %d \\ n " , sizeof ( S6 ) , sizeof ( S6z ) ) ;
TEST ( C___ ) ;
TEST_ARR ( Carr ) ;
TEST ( C__w ) ;
TEST ( Cp1_ ) ;
TEST ( Cp2_ ) ;
TEST ( Cint ) ;
TEST ( C4__ ) ;
TEST ( C4_2 ) ;
TEST ( C__z ) ;
return 1 ;
}
'''
2011-10-21 23:08:44 +04:00
if Settings . QUANTUM_SIZE == 1 :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' sizeofs:6,8 \n *C___: 0,3,6,9<24* \n *Carr: 0,3,6,9<24* \n *C__w: 0,3,9,12<24* \n *Cp1_: 1,2,5,8<24* \n *Cp2_: 0,2,5,8<24* \n *Cint: 0,3,4,7<24* \n *C4__: 0,3,4,7<24* \n *C4_2: 0,3,5,8<20* \n *C__z: 0,3,5,8<28* ' )
2011-04-22 18:53:31 +04:00
else :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' sizeofs:6,8 \n *C___: 0,6,12,20<24* \n *Carr: 0,6,12,20<24* \n *C__w: 0,6,12,20<24* \n *Cp1_: 4,6,12,20<24* \n *Cp2_: 0,6,12,20<24* \n *Cint: 0,8,12,20<24* \n *C4__: 0,8,12,20<24* \n *C4_2: 0,6,10,16<20* \n *C__z: 0,8,16,24<28* ' )
2011-01-30 03:55:59 +03:00
2010-09-07 02:25:17 +04:00
def test_assert ( self ) :
src = '''
#include <stdio.h>
#include <assert.h>
int main ( ) {
assert ( 1 == true ) ; / / pass
assert ( 1 == false ) ; / / fail
return 1 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' Assertion failed: 1 == false ' )
2010-08-26 08:01:10 +04:00
2010-11-21 02:19:01 +03:00
def test_exceptions ( self ) :
2012-01-22 02:01:42 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( " we don ' t support libcxx in q1 " )
2011-12-05 01:09:53 +04:00
self . banned_js_engines = [ NODE_JS ] # node issue 1669, exception causes stdout not to be flushed
2011-12-22 05:13:04 +04:00
Settings . DISABLE_EXCEPTION_CATCHING = 0
2012-01-22 02:12:52 +04:00
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
2011-12-05 01:09:53 +04:00
2010-11-21 02:19:01 +03:00
src = '''
#include <stdio.h>
void thrower ( ) {
printf ( " infunc... " ) ;
throw ( 99 ) ;
printf ( " FAIL " ) ;
}
int main ( ) {
try {
printf ( " *throw... " ) ;
throw ( 1 ) ;
printf ( " FAIL " ) ;
} catch ( . . . ) {
printf ( " caught! " ) ;
}
try {
thrower ( ) ;
} catch ( . . . ) {
printf ( " done!* \\ n " ) ;
}
return 1 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *throw...caught!infunc...done!* ' )
2010-11-21 02:19:01 +03:00
2011-10-21 23:08:44 +04:00
Settings . DISABLE_EXCEPTION_CATCHING = 1
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' Compiled code throwing an exception ' )
2012-01-11 08:21:47 +04:00
src = '''
#include <iostream>
2012-01-12 12:40:05 +04:00
class MyException
{
public :
MyException ( ) { std : : cout << " Construct... " ; }
2012-01-12 00:11:52 +04:00
MyException ( const MyException & ) { std : : cout << " Copy... " ; }
2012-01-12 12:40:05 +04:00
~ MyException ( ) { std : : cout << " Destruct... " ; }
} ;
int function ( )
{
std : : cout << " Throw... " ;
throw MyException ( ) ;
}
int function2 ( )
{
return function ( ) ;
}
int main ( )
{
try
{
function2 ( ) ;
}
catch ( MyException & e )
{
std : : cout << " Catched... " ;
}
2012-01-12 00:11:52 +04:00
try
2012-01-12 12:40:05 +04:00
{
function2 ( ) ;
}
catch ( MyException e )
{
std : : cout << " Catched... " ;
}
return 0 ;
}
'''
2012-01-11 08:21:47 +04:00
Settings . DISABLE_EXCEPTION_CATCHING = 0
2012-01-12 00:11:52 +04:00
self . do_run ( src , ' Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct... ' )
2011-08-15 08:53:34 +04:00
2011-09-13 03:07:59 +04:00
def test_typed_exceptions ( self ) :
2011-09-17 20:55:34 +04:00
return self . skip ( ' TODO: fix this for llvm 3.0 ' )
2011-10-21 23:08:44 +04:00
Settings . SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access.
Settings . EXCEPTION_DEBUG = 0 # Messes up expected output.
2011-09-13 03:07:59 +04:00
src = open ( path_from_root ( ' tests ' , ' exceptions ' , ' typed.cpp ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' exceptions ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-09-13 03:07:59 +04:00
2010-08-26 08:01:10 +04:00
def test_class ( self ) :
src = '''
#include <stdio.h>
struct Random {
enum { IM = 139968 , IA = 3877 , IC = 29573 } ;
Random ( ) : last ( 42 ) { }
float get ( float max = 1.0 f ) {
last = ( last * IA + IC ) % IM ;
return max * last / IM ;
}
protected :
unsigned int last ;
} rng1 ;
int main ( )
{
Random rng2 ;
int count = 0 ;
for ( int i = 0 ; i < 100 ; i + + ) {
float x1 = rng1 . get ( ) ;
float x2 = rng2 . get ( ) ;
printf ( " %f , %f \\ n " , x1 , x2 ) ;
if ( x1 != x2 ) count + = 1 ;
}
printf ( " * %d * \\ n " , count ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *0* ' )
2010-08-26 08:01:10 +04:00
def test_inherit ( self ) :
src = '''
#include <stdio.h>
struct Parent {
int x1 , x2 ;
} ;
struct Child : Parent {
int y ;
} ;
int main ( )
{
Parent a ;
a . x1 = 50 ;
a . x2 = 87 ;
Child b ;
b . x1 = 78 ;
b . x2 = 550 ;
b . y = 101 ;
Child * c = ( Child * ) & a ;
c - > x1 + + ;
c = & b ;
c - > y - - ;
printf ( " * %d , %d , %d , %d , %d , %d , %d * \\ n " , a . x1 , a . x2 , b . x1 , b . x2 , b . y , c - > x1 , c - > x2 ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *51,87,78,550,100,78,550* ' )
2010-08-26 08:01:10 +04:00
def test_polymorph ( self ) :
src = '''
#include <stdio.h>
2010-10-24 07:37:49 +04:00
struct Pure {
virtual int implme ( ) = 0 ;
} ;
struct Parent : Pure {
2010-08-26 08:01:10 +04:00
virtual int getit ( ) { return 11 ; } ;
2010-10-24 07:37:49 +04:00
int implme ( ) { return 32 ; }
2010-08-26 08:01:10 +04:00
} ;
struct Child : Parent {
int getit ( ) { return 74 ; }
2010-10-24 07:37:49 +04:00
int implme ( ) { return 1012 ; }
2010-08-26 08:01:10 +04:00
} ;
2010-10-24 22:38:08 +04:00
struct Other {
int one ( ) { return 11 ; }
int two ( ) { return 22 ; }
} ;
2010-08-26 08:01:10 +04:00
int main ( )
{
Parent * x = new Parent ( ) ;
Parent * y = new Child ( ) ;
2010-10-24 07:37:49 +04:00
printf ( " * %d , %d , %d , %d * \\ n " , x - > getit ( ) , y - > getit ( ) , x - > implme ( ) , y - > implme ( ) ) ;
2010-10-24 22:38:08 +04:00
Other * o = new Other ;
int ( Other : : * Ls ) ( ) = & Other : : one ;
printf ( " * %d * \\ n " , ( o - > * ( Ls ) ) ( ) ) ;
Ls = & Other : : two ;
printf ( " * %d * \\ n " , ( o - > * ( Ls ) ) ( ) ) ;
2010-08-26 08:01:10 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *11,74,32,1012* \n *11* \n *22* ' )
2010-08-26 08:01:10 +04:00
2011-11-08 06:22:16 +04:00
def test_dynamic_cast ( self ) :
src = '''
#include <stdio.h>
class CBase { virtual void dummy ( ) { } } ;
class CDerived : public CBase { int a ; } ;
class CDerivedest : public CDerived { float b ; } ;
int main ( )
{
CBase * pa = new CBase ;
CBase * pb = new CDerived ;
CBase * pc = new CDerivedest ;
printf ( " a1: %d \\ n " , dynamic_cast < CDerivedest * > ( pa ) != NULL ) ;
printf ( " a2: %d \\ n " , dynamic_cast < CDerived * > ( pa ) != NULL ) ;
printf ( " a3: %d \\ n " , dynamic_cast < CBase * > ( pa ) != NULL ) ;
printf ( " b1: %d \\ n " , dynamic_cast < CDerivedest * > ( pb ) != NULL ) ;
printf ( " b2: %d \\ n " , dynamic_cast < CDerived * > ( pb ) != NULL ) ;
printf ( " b3: %d \\ n " , dynamic_cast < CBase * > ( pb ) != NULL ) ;
printf ( " c1: %d \\ n " , dynamic_cast < CDerivedest * > ( pc ) != NULL ) ;
printf ( " c2: %d \\ n " , dynamic_cast < CDerived * > ( pc ) != NULL ) ;
printf ( " c3: %d \\ n " , dynamic_cast < CBase * > ( pc ) != NULL ) ;
return 0 ;
}
'''
self . do_run ( src , ' a1: 0 \n a2: 0 \n a3: 1 \n b1: 0 \n b2: 1 \n b3: 1 \n c1: 1 \n c2: 1 \n c3: 1 \n ' )
2010-10-11 09:52:54 +04:00
def test_funcptr ( self ) :
src = '''
#include <stdio.h>
int calc1 ( ) { return 26 ; }
int calc2 ( ) { return 90 ; }
typedef int ( * fp_t ) ( ) ;
2010-10-22 08:41:43 +04:00
fp_t globally1 = calc1 ;
fp_t globally2 = calc2 ;
2011-05-15 19:04:34 +04:00
int nothing ( const char * str ) { return 0 ; }
2010-10-11 09:52:54 +04:00
int main ( )
{
fp_t fp = calc1 ;
void * vp = ( void * ) fp ;
fp_t fpb = ( fp_t ) vp ;
fp_t fp2 = calc2 ;
void * vp2 = ( void * ) fp2 ;
fp_t fpb2 = ( fp_t ) vp2 ;
2010-10-22 08:41:43 +04:00
printf ( " * %d , %d , %d , %d , %d , %d * \\ n " , fp ( ) , fpb ( ) , fp2 ( ) , fpb2 ( ) , globally1 ( ) , globally2 ( ) ) ;
2010-12-06 04:30:45 +03:00
fp_t t = calc1 ;
printf ( " * %d , %d " , t == calc1 , t == calc2 ) ;
t = calc2 ;
printf ( " , %d , %d * \\ n " , t == calc1 , t == calc2 ) ;
2011-05-15 19:04:34 +04:00
int ( * other ) ( const char * str ) ;
other = nothing ;
other ( " *hello!* " ) ;
other = puts ;
other ( " *goodbye!* " ) ;
2010-10-11 09:52:54 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *26,26,90,90,26,90* \n *1,0,0,1* \n *goodbye!* ' )
2010-10-11 09:52:54 +04:00
2011-06-25 18:49:01 +04:00
def test_mathfuncptr ( self ) :
src = '''
#include <math.h>
#include <stdio.h>
int
main ( void ) {
float ( * fn ) ( float ) = & sqrtf ;
float ( * fn2 ) ( float ) = & fabsf ;
printf ( " fn2(-5) = %d , fn(10) = %f \\ n " , ( int ) fn2 ( - 5 ) , fn ( 10 ) ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' fn2(-5) = 5, fn(10) = 3.16 ' )
2011-06-25 18:49:01 +04:00
2010-08-29 00:38:43 +04:00
def test_emptyclass ( self ) :
src = '''
#include <stdio.h>
struct Randomized {
Randomized ( int x ) {
printf ( " *zzcheezzz* \\ n " ) ;
}
} ;
int main ( int argc , const char * argv [ ] ) {
new Randomized ( 55 ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *zzcheezzz* ' )
2010-08-29 00:38:43 +04:00
2011-05-27 23:46:32 +04:00
def test_alloca ( self ) :
src = '''
#include <stdio.h>
2012-01-03 00:44:49 +04:00
#include <stdlib.h>
2011-05-27 23:46:32 +04:00
int main ( ) {
char * pc ;
pc = ( char * ) alloca ( 5 ) ;
printf ( " z: %d * %d * \\ n " , pc > 0 , ( int ) pc ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' z:1* ' , force_c = True )
2011-05-27 23:46:32 +04:00
2012-01-07 05:55:44 +04:00
if self . emcc_args is not None : # too slow in other modes
# 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 )
# 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* ' )
2012-01-12 09:30:03 +04:00
# 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! ' )
2010-09-26 07:57:52 +04:00
def test_array2 ( self ) :
src = '''
#include <stdio.h>
static const double grid [ 4 ] [ 2 ] = {
2010-10-19 08:15:36 +04:00
{ - 3 / 3. , - 1 / 3. } , { + 1 / 3. , - 3 / 3. } ,
{ - 1 / 3. , + 3 / 3. } , { + 3 / 3. , + 1 / 3. }
2010-09-26 07:57:52 +04:00
} ;
int main ( ) {
for ( int i = 0 ; i < 4 ; i + + )
printf ( " %d : %.2f , %.2f " , i , grid [ i ] [ 0 ] , grid [ i ] [ 1 ] ) ;
printf ( " \\ n " ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' 0:-1.00,-0.33 1:0.33,-1.00 2:-0.33,1.00 3:1.00,0.33 ' )
2010-09-26 07:57:52 +04:00
2010-11-28 07:58:19 +03:00
def test_array2b ( self ) :
src = '''
#include <stdio.h>
static const struct {
unsigned char left ;
unsigned char right ;
} prioritah [ ] = {
{ 6 , 6 } , { 6 , 6 } , { 7 , 95 } , { 7 , 7 }
} ;
int main ( ) {
printf ( " * %d , %d \\ n " , prioritah [ 1 ] . left , prioritah [ 1 ] . right ) ;
printf ( " %d , %d * \\ n " , prioritah [ 2 ] . left , prioritah [ 2 ] . right ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *6,6 \n 7,95* ' )
2010-11-28 07:58:19 +03:00
2010-09-09 06:55:07 +04:00
def test_constglobalstructs ( self ) :
2010-08-26 08:01:10 +04:00
src = '''
#include <stdio.h>
struct IUB {
int c ;
double p ;
unsigned int pi ;
} ;
IUB iub [ ] = {
{ ' a ' , 0.27 , 5 } ,
{ ' c ' , 0.15 , 4 } ,
{ ' g ' , 0.12 , 3 } ,
{ ' t ' , 0.27 , 2 } ,
} ;
2010-11-14 05:50:15 +03:00
const unsigned char faceedgesidx [ 6 ] [ 4 ] =
{
{ 4 , 5 , 8 , 10 } ,
{ 6 , 7 , 9 , 11 } ,
{ 0 , 2 , 8 , 9 } ,
{ 1 , 3 , 10 , 11 } ,
{ 0 , 1 , 4 , 6 } ,
{ 2 , 3 , 5 , 7 } ,
} ;
2010-08-26 08:01:10 +04:00
int main ( int argc , const char * argv [ ] ) {
2010-11-14 05:50:15 +03:00
printf ( " * %d , %d , %d , %d * \\ n " , iub [ 0 ] . c , int ( iub [ 1 ] . p * 100 ) , iub [ 2 ] . pi , faceedgesidx [ 3 ] [ 2 ] ) ;
2010-08-26 08:01:10 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *97,15,3,10* ' )
2010-08-26 08:01:10 +04:00
def test_conststructs ( self ) :
src = '''
#include <stdio.h>
struct IUB {
int c ;
double p ;
unsigned int pi ;
} ;
int main ( int argc , const char * argv [ ] ) {
2010-09-26 07:26:16 +04:00
int before = 70 ;
2010-08-26 08:01:10 +04:00
IUB iub [ ] = {
2010-08-29 05:38:30 +04:00
{ ' a ' , 0.3029549426680 , 5 } ,
2010-08-26 08:01:10 +04:00
{ ' c ' , 0.15 , 4 } ,
{ ' g ' , 0.12 , 3 } ,
{ ' t ' , 0.27 , 2 } ,
} ;
2010-09-26 07:26:16 +04:00
int after = 90 ;
printf ( " * %d , %d , %d , %d , %d , %d * \\ n " , before , iub [ 0 ] . c , int ( iub [ 1 ] . p * 100 ) , iub [ 2 ] . pi , int ( iub [ 0 ] . p * 10000 ) , after ) ;
2010-08-26 08:01:10 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *70,97,15,3,3029,90* ' )
2010-08-26 08:01:10 +04:00
2010-10-02 07:58:15 +04:00
def test_mod_globalstruct ( self ) :
src = '''
#include <stdio.h>
struct malloc_params {
size_t magic , page_size ;
} ;
malloc_params mparams ;
#define SIZE_T_ONE ((size_t)1)
#define page_align(S) (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
int main ( )
{
mparams . page_size = 4096 ;
printf ( " * %d , %d , %d , %d * \\ n " , mparams . page_size , page_align ( 1000 ) , page_align ( 6000 ) , page_align ( 66474 ) ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *4096,4096,8192,69632* ' )
2010-10-02 07:58:15 +04:00
2010-12-08 08:54:29 +03:00
def test_pystruct ( self ) :
src = '''
#include <stdio.h>
/ / Based on CPython code
union PyGC_Head {
struct {
union PyGC_Head * gc_next ;
union PyGC_Head * gc_prev ;
size_t gc_refs ;
} gc ;
long double dummy ; / * force worst - case alignment * /
} ;
struct gc_generation {
PyGC_Head head ;
int threshold ; / * collection threshold * /
int count ; / * count of allocations or collections of younger
generations * /
} ;
#define NUM_GENERATIONS 3
#define GEN_HEAD(n) (&generations[n].head)
/ * linked lists of container objects * /
static struct gc_generation generations [ NUM_GENERATIONS ] = {
/ * PyGC_Head , threshold , count * /
{ { { GEN_HEAD ( 0 ) , GEN_HEAD ( 0 ) , 0 } } , 700 , 0 } ,
{ { { GEN_HEAD ( 1 ) , GEN_HEAD ( 1 ) , 0 } } , 10 , 0 } ,
{ { { GEN_HEAD ( 2 ) , GEN_HEAD ( 2 ) , 0 } } , 10 , 0 } ,
} ;
int main ( )
{
gc_generation * n = NULL ;
printf ( " * %d , %d , %d , %d , %d , %d , %d , %d * \\ n " ,
( int ) ( & n [ 0 ] ) ,
( int ) ( & n [ 0 ] . head ) ,
( int ) ( & n [ 0 ] . head . gc . gc_next ) ,
( int ) ( & n [ 0 ] . head . gc . gc_prev ) ,
( int ) ( & n [ 0 ] . head . gc . gc_refs ) ,
( int ) ( & n [ 0 ] . threshold ) , ( int ) ( & n [ 0 ] . count ) , ( int ) ( & n [ 1 ] )
) ;
printf ( " * %d , %d , %d * \\ n " ,
( int ) ( & generations [ 0 ] ) ==
( int ) ( & generations [ 0 ] . head . gc . gc_next ) ,
( int ) ( & generations [ 0 ] ) ==
( int ) ( & generations [ 0 ] . head . gc . gc_prev ) ,
( int ) ( & generations [ 0 ] ) ==
( int ) ( & generations [ 1 ] )
) ;
int x1 = ( int ) ( & generations [ 0 ] ) ;
int x2 = ( int ) ( & generations [ 1 ] ) ;
printf ( " * %d * \\ n " , x1 == x2 ) ;
for ( int i = 0 ; i < NUM_GENERATIONS ; i + + ) {
PyGC_Head * list = GEN_HEAD ( i ) ;
printf ( " %d : %d , %d \\ n " , i , ( int ) list == ( int ) ( list - > gc . gc_prev ) , ( int ) list == ( int ) ( list - > gc . gc_next ) ) ;
}
2011-02-12 05:37:04 +03:00
printf ( " * %d , %d , %d * \\ n " , sizeof ( PyGC_Head ) , sizeof ( gc_generation ) , int ( GEN_HEAD ( 2 ) ) - int ( GEN_HEAD ( 1 ) ) ) ;
2010-12-08 08:54:29 +03:00
}
'''
2011-10-21 23:08:44 +04:00
if Settings . QUANTUM_SIZE == 1 :
2011-04-22 18:53:31 +04:00
# Compressed memory. Note that sizeof() does give the fat sizes, however!
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *0,0,0,1,2,3,4,5* \n *1,0,0* \n *0* \n 0:1,1 \n 1:1,1 \n 2:1,1 \n *12,20,5* ' )
2011-04-22 18:53:31 +04:00
else :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *0,0,0,4,8,12,16,20* \n *1,0,0* \n *0* \n 0:1,1 \n 1:1,1 \n 2:1,1 \n *12,20,20* ' )
2010-12-08 08:54:29 +03:00
2010-09-03 08:34:15 +04:00
def test_ptrtoint ( self ) :
src = '''
#include <stdio.h>
int main ( int argc , const char * argv [ ] ) {
char * a = new char [ 10 ] ;
char * a0 = a + 0 ;
char * a5 = a + 5 ;
int * b = new int [ 10 ] ;
int * b0 = b + 0 ;
int * b5 = b + 5 ;
int c = ( int ) b5 - ( int ) b0 ; / / Emscripten should warn !
int d = ( int ) b5 - ( int ) b0 ; / / Emscripten should warn !
printf ( " * %d * \\ n " , ( int ) a5 - ( int ) a0 ) ;
return 0 ;
}
'''
runner = self
def check_warnings ( output ) :
runner . assertEquals ( filter ( lambda line : ' Warning ' in line , output . split ( ' \n ' ) ) . __len__ ( ) , 4 )
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *5* ' , output_processor = check_warnings )
2010-08-26 08:01:10 +04:00
2010-09-08 06:23:00 +04:00
def test_sizeof ( self ) :
2010-11-26 00:06:31 +03:00
# Has invalid writes between printouts
2011-10-21 23:08:44 +04:00
Settings . SAFE_HEAP = 0
2010-11-26 00:06:31 +03:00
2010-08-26 08:01:10 +04:00
src = '''
#include <stdio.h>
#include <string.h>
2010-09-08 06:23:00 +04:00
#include "emscripten.h"
struct A { int x , y ; } ;
2010-08-26 08:01:10 +04:00
int main ( int argc , const char * argv [ ] ) {
int * a = new int [ 10 ] ;
int * b = new int [ 1 ] ;
int * c = new int [ 10 ] ;
for ( int i = 0 ; i < 10 ; i + + )
a [ i ] = 2 ;
* b = 5 ;
for ( int i = 0 ; i < 10 ; i + + )
c [ i ] = 8 ;
printf ( " * %d , %d , %d , %d , %d * \\ n " , a [ 0 ] , a [ 9 ] , * b , c [ 0 ] , c [ 9 ] ) ;
/ / Should overwrite a , but not touch b !
2011-04-22 18:53:31 +04:00
memcpy ( a , c , 10 * sizeof ( int ) ) ;
2010-08-26 08:01:10 +04:00
printf ( " * %d , %d , %d , %d , %d * \\ n " , a [ 0 ] , a [ 9 ] , * b , c [ 0 ] , c [ 9 ] ) ;
2010-09-08 06:23:00 +04:00
/ / Part 2
2010-09-09 06:56:06 +04:00
A as [ 3 ] = { { 5 , 12 } , { 6 , 990 } , { 7 , 2 } } ;
2011-04-22 18:53:31 +04:00
memcpy ( & as [ 0 ] , & as [ 2 ] , sizeof ( A ) ) ;
2010-09-08 06:23:00 +04:00
printf ( " * %d , %d , %d , %d , %d , %d * \\ n " , as [ 0 ] . x , as [ 0 ] . y , as [ 1 ] . x , as [ 1 ] . y , as [ 2 ] . x , as [ 2 ] . y ) ;
2010-08-26 08:01:10 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *2,2,5,8,8***8,8,5,8,8***7,2,6,990,7,2* ' , [ ] , lambda x : x . replace ( ' \n ' , ' * ' ) )
2010-08-26 08:01:10 +04:00
2011-02-13 06:35:45 +03:00
def test_emscripten_api ( self ) :
2011-11-18 22:02:45 +04:00
#if Settings.MICRO_OPTS or Settings.RELOOP or Building.LLVM_OPTS: return self.skip('FIXME')
2011-10-14 04:33:04 +04:00
2011-12-07 01:27:43 +04:00
src = r '''
2011-02-13 06:35:45 +03:00
#include <stdio.h>
#include "emscripten.h"
int main ( ) {
2011-12-01 02:48:41 +04:00
/ / EMSCRIPTEN_COMMENT ( " hello from the source " ) ;
2011-02-13 06:35:45 +03:00
emscripten_run_script ( " print( ' hello world ' + ' ! ' ) " ) ;
2011-12-07 01:27:43 +04:00
printf ( " * %d * \n " , emscripten_run_script_int ( " 5*20 " ) ) ;
2011-02-13 06:35:45 +03:00
return 0 ;
}
'''
2011-10-11 06:58:29 +04:00
2011-12-21 06:49:42 +04:00
check = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( )
# TODO: restore this (see comment in emscripten.h) assert '// hello from the source' in src
2011-12-21 09:28:53 +04:00
'''
2011-10-11 06:58:29 +04:00
2011-12-07 01:27:43 +04:00
self . do_run ( src , ' hello world! \n *100* ' , post_build = check )
def test_memorygrowth ( self ) :
# With typed arrays in particular, it is dangerous to use more memory than TOTAL_MEMORY,
# since we then need to enlarge the heap(s).
src = r '''
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "emscripten.h"
int main ( )
{
char * buf1 = ( char * ) malloc ( 100 ) ;
char * data1 = " hello " ;
memcpy ( buf1 , data1 , strlen ( data1 ) + 1 ) ;
float * buf2 = ( float * ) malloc ( 100 ) ;
float pie = 4.955 ;
memcpy ( buf2 , & pie , sizeof ( float ) ) ;
printf ( " *pre: %s , %.3f * \n " , buf1 , buf2 [ 0 ] ) ;
int totalMemory = emscripten_run_script_int ( " TOTAL_MEMORY " ) ;
2011-12-07 02:00:21 +04:00
char * buf3 = ( char * ) malloc ( totalMemory + 1 ) ;
2011-12-07 01:27:43 +04:00
char * buf4 = ( char * ) malloc ( 100 ) ;
float * buf5 = ( float * ) malloc ( 100 ) ;
/ / printf ( " totalMemory: %d bufs: %d , %d , %d , %d , %d \n " , totalMemory , buf1 , buf2 , buf3 , buf4 , buf5 ) ;
assert ( ( int ) buf4 > ( int ) totalMemory & & ( int ) buf5 > ( int ) totalMemory ) ;
printf ( " * %s , %.3f * \n " , buf1 , buf2 [ 0 ] ) ; / / the old heap data should still be there
memcpy ( buf4 , buf1 , strlen ( data1 ) + 1 ) ;
memcpy ( buf5 , buf2 , sizeof ( float ) ) ;
printf ( " * %s , %.3f * \n " , buf4 , buf5 [ 0 ] ) ; / / and the new heap space should work too
return 0 ;
}
'''
self . do_run ( src , ' *pre: hello,4.955* \n *hello,4.955* \n *hello,4.955* ' )
2011-02-13 06:35:45 +03:00
2011-04-22 18:53:31 +04:00
def test_ssr ( self ) : # struct self-ref
src = '''
#include <stdio.h>
/ / see related things in openjpeg
typedef struct opj_mqc_state {
unsigned int qeval ;
int mps ;
struct opj_mqc_state * nmps ;
struct opj_mqc_state * nlps ;
} opj_mqc_state_t ;
static opj_mqc_state_t mqc_states [ 2 ] = {
{ 0x5600 , 0 , & mqc_states [ 2 ] , & mqc_states [ 3 ] } ,
{ 0x5602 , 1 , & mqc_states [ 3 ] , & mqc_states [ 2 ] } ,
} ;
int main ( ) {
printf ( " * %d * \\ n " , ( int ) ( mqc_states + 1 ) - ( int ) mqc_states ) ;
for ( int i = 0 ; i < 2 ; i + + )
printf ( " %d : %d , %d , %d , %d \\ n " , i , mqc_states [ i ] . qeval , mqc_states [ i ] . mps ,
( int ) mqc_states [ i ] . nmps - ( int ) mqc_states , ( int ) mqc_states [ i ] . nlps - ( int ) mqc_states ) ;
return 0 ;
}
'''
2011-10-21 23:08:44 +04:00
if Settings . QUANTUM_SIZE == 1 :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ''' *4* \n 0:22016,0,8,12 \n 1:22018,1,12,8 \n ''' )
2011-04-22 18:53:31 +04:00
else :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ''' *16* \n 0:22016,0,32,48 \n 1:22018,1,48,32 \n ''' )
2011-04-22 18:53:31 +04:00
2010-10-24 04:48:34 +04:00
def test_tinyfuncstr ( self ) :
src = '''
#include <stdio.h>
struct Class {
static char * name1 ( ) { return " nameA " ; }
char * name2 ( ) { return " nameB " ; }
} ;
int main ( ) {
printf ( " * %s , %s * \\ n " , Class : : name1 ( ) , ( new Class ( ) ) - > name2 ( ) ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *nameA,nameB* ' )
2010-10-24 04:48:34 +04:00
2010-08-30 03:25:06 +04:00
def test_llvmswitch ( self ) :
src = '''
#include <stdio.h>
#include <string.h>
int switcher ( int p )
{
switch ( p ) {
case ' a ' :
case ' b ' :
case ' c ' :
return p - 1 ;
case ' d ' :
return p + 1 ;
}
return p ;
}
int main ( int argc , const char * argv [ ] ) {
printf ( " * %d , %d , %d , %d , %d * \\ n " , switcher ( ' a ' ) , switcher ( ' b ' ) , switcher ( ' c ' ) , switcher ( ' d ' ) , switcher ( ' e ' ) ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *96,97,98,101,101* ' )
2010-08-30 03:25:06 +04:00
2011-06-29 05:24:06 +04:00
def test_indirectbr ( self ) :
2011-11-10 05:48:15 +04:00
if Settings . USE_TYPED_ARRAYS == 2 :
Settings . I64_MODE = 1 # Unsafe optimizations use 64-bit load/store on two i32s
2011-06-29 05:24:06 +04:00
src = '''
#include <stdio.h>
int main ( void ) {
const void * addrs [ 2 ] = { & & FOO , & & BAR } ;
/ / confuse the optimizer so it doesn ' t hardcode the jump and avoid generating an |indirectbr| instruction
int which = 0 ;
for ( int x = 0 ; x < 1000 ; x + + ) which = ( which + x * x ) % 7 ;
which = ( which % 2 ) + 1 ;
goto * addrs [ which ] ;
FOO :
printf ( " bad \\ n " ) ;
return 1 ;
BAR :
printf ( " good \\ n " ) ;
const void * addr = & & FOO ;
goto * addr ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' good \n bad ' )
2011-06-29 05:24:06 +04:00
2011-04-17 03:35:08 +04:00
def test_pack ( self ) :
src = '''
#include <stdio.h>
#include <string.h>
#pragma pack(push,1)
typedef struct header
{
unsigned char id ;
unsigned short colour ;
unsigned char desc ;
} header ;
#pragma pack(pop)
typedef struct fatheader
{
unsigned char id ;
unsigned short colour ;
unsigned char desc ;
} fatheader ;
int main ( int argc , const char * argv [ ] ) {
header h , * ph = 0 ;
fatheader fh , * pfh = 0 ;
printf ( " * %d , %d , %d * \\ n " , sizeof ( header ) , ( int ) ( ( int ) & h . desc - ( int ) & h . id ) , ( int ) ( & ph [ 1 ] ) - ( int ) ( & ph [ 0 ] ) ) ;
printf ( " * %d , %d , %d * \\ n " , sizeof ( fatheader ) , ( int ) ( ( int ) & fh . desc - ( int ) & fh . id ) , ( int ) ( & pfh [ 1 ] ) - ( int ) ( & pfh [ 0 ] ) ) ;
return 0 ;
}
'''
2011-10-21 23:08:44 +04:00
if Settings . QUANTUM_SIZE == 1 :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *4,2,3* \n *6,2,3* ' )
2011-04-22 18:53:31 +04:00
else :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *4,3,4* \n *6,4,6* ' )
2011-04-17 03:35:08 +04:00
2010-09-05 05:05:18 +04:00
def test_varargs ( self ) :
2011-10-21 23:08:44 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' FIXME: Add support for this ' )
2011-04-23 00:23:37 +04:00
2010-09-05 03:46:11 +04:00
src = '''
#include <stdio.h>
2010-11-27 03:55:02 +03:00
#include <stdarg.h>
2010-09-05 03:46:11 +04:00
void vary ( const char * s , . . . )
{
va_list v ;
va_start ( v , s ) ;
char d [ 20 ] ;
vsnprintf ( d , 20 , s , v ) ;
puts ( d ) ;
2010-12-05 02:33:29 +03:00
/ / Try it with copying
va_list tempva ;
__va_copy ( tempva , v ) ;
vsnprintf ( d , 20 , s , tempva ) ;
puts ( d ) ;
2010-09-05 03:46:11 +04:00
va_end ( v ) ;
}
2010-09-11 22:01:37 +04:00
void vary2 ( char color , const char * s , . . . )
{
va_list v ;
va_start ( v , s ) ;
char d [ 21 ] ;
d [ 0 ] = color ;
vsnprintf ( d + 1 , 20 , s , v ) ;
puts ( d ) ;
va_end ( v ) ;
}
2010-11-27 03:55:02 +03:00
#define GETMAX(pref, type) \
type getMax ##pref(int num, ...) \
{ \
va_list vv ; \
va_start ( vv , num ) ; \
type maxx = va_arg ( vv , type ) ; \
for ( int i = 1 ; i < num ; i + + ) \
{ \
type curr = va_arg ( vv , type ) ; \
maxx = curr > maxx ? curr : maxx ; \
} \
va_end ( vv ) ; \
return maxx ; \
}
GETMAX ( i , int ) ;
GETMAX ( D , double ) ;
2010-09-05 03:46:11 +04:00
int main ( ) {
2010-09-12 01:15:46 +04:00
vary ( " *cheez: %d + %d * " , 0 , 24 ) ; / / Also tests that ' 0 ' is not special as an array ender
2011-04-26 19:26:00 +04:00
vary ( " *albeit* " ) ; / / Should not fail with no var args in vararg function
2010-09-11 22:01:37 +04:00
vary2 ( ' Q ' , " %d * " , 85 ) ;
2010-11-27 03:55:02 +03:00
int maxxi = getMaxi ( 6 , 2 , 5 , 21 , 4 , - 10 , 19 ) ;
printf ( " maxxi: %d * \\ n " , maxxi ) ;
double maxxD = getMaxD ( 6 , ( double ) 2.1 , ( double ) 5.1 , ( double ) 22.1 , ( double ) 4.1 , ( double ) - 10.1 , ( double ) 19.1 ) ;
printf ( " maxxD: %.2f * \\ n " , ( float ) maxxD ) ;
2011-11-25 21:51:02 +04:00
/ / And , as a function pointer
void ( * vfp ) ( const char * s , . . . ) = vary ;
vfp ( " *vfp: %d , %d * " , 22 , 199 ) ;
2010-09-05 03:46:11 +04:00
return 0 ;
}
'''
2011-11-25 21:51:02 +04:00
self . do_run ( src , ' *cheez: 0+24* \n *cheez: 0+24* \n *albeit* \n *albeit* \n Q85* \n maxxi:21* \n maxxD:22.10* \n *vfp:22,199* \n *vfp:22,199* \n ' )
2011-11-26 09:19:53 +04:00
def test_structbyval ( self ) :
# part 1: make sure that normally, passing structs by value works
src = r '''
#include <stdio.h>
struct point
{
int x , y ;
} ;
void dump ( struct point p ) {
p . x + + ; / / should not modify
p . y + + ; / / anything in the caller !
printf ( " dump: %d , %d \n " , p . x , p . y ) ;
}
void dumpmod ( struct point * p ) {
p - > x + + ; / / should not modify
p - > y + + ; / / anything in the caller !
printf ( " dump: %d , %d \n " , p - > x , p - > y ) ;
}
int main ( int argc , const char * argv [ ] ) {
point p = { 54 , 2 } ;
printf ( " pre: %d , %d \n " , p . x , p . y ) ;
dump ( p ) ;
void ( * dp ) ( point p ) = dump ; / / And , as a function pointer
dp ( p ) ;
printf ( " post: %d , %d \n " , p . x , p . y ) ;
dumpmod ( & p ) ;
dumpmod ( & p ) ;
printf ( " last: %d , %d \n " , p . x , p . y ) ;
return 0 ;
}
'''
self . do_run ( src , ' pre: 54,2 \n dump: 55,3 \n dump: 55,3 \n post: 54,2 \n dump: 55,3 \n dump: 56,4 \n last: 56,4 ' )
# Check for lack of warning in the generated code (they should appear in part 2)
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. ' not in generated , ' Unexpected warning '
# part 2: make sure we warn about mixing c and c++ calling conventions here
2011-11-25 21:51:02 +04:00
header = r '''
struct point
{
int x , y ;
} ;
'''
open ( os . path . join ( self . get_dir ( ) , ' header.h ' ) , ' w ' ) . write ( header )
supp = r '''
#include <stdio.h>
#include "header.h"
void dump ( struct point p ) {
2011-11-25 22:11:20 +04:00
p . x + + ; / / should not modify
p . y + + ; / / anything in the caller !
2011-11-25 21:51:02 +04:00
printf ( " dump: %d , %d \n " , p . x , p . y ) ;
}
'''
supp_name = os . path . join ( self . get_dir ( ) , ' supp.c ' )
open ( supp_name , ' w ' ) . write ( supp )
main = r '''
#include <stdio.h>
#include "header.h"
2011-11-26 09:19:53 +04:00
#ifdef __cplusplus
2011-11-25 21:51:02 +04:00
extern " C " {
2011-11-26 09:19:53 +04:00
#endif
void dump ( struct point p ) ;
#ifdef __cplusplus
2011-11-25 21:51:02 +04:00
}
2011-11-26 09:19:53 +04:00
#endif
2011-11-25 21:51:02 +04:00
int main ( int argc , const char * argv [ ] ) {
2011-11-26 09:19:53 +04:00
struct point p = { 54 , 2 } ;
2011-11-25 21:51:02 +04:00
printf ( " pre: %d , %d \n " , p . x , p . y ) ;
dump ( p ) ;
2011-11-26 09:19:53 +04:00
void ( * dp ) ( struct point p ) = dump ; / / And , as a function pointer
2011-11-25 22:11:20 +04:00
dp ( p ) ;
printf ( " post: %d , %d \n " , p . x , p . y ) ;
2011-11-25 21:51:02 +04:00
return 0 ;
}
'''
main_name = os . path . join ( self . get_dir ( ) , ' main.cpp ' )
open ( main_name , ' w ' ) . write ( main )
2011-12-18 04:52:17 +04:00
Building . emcc ( supp_name )
Building . emcc ( main_name )
2011-11-25 21:51:02 +04:00
all_name = os . path . join ( self . get_dir ( ) , ' all.bc ' )
Building . link ( [ supp_name + ' .o ' , main_name + ' .o ' ] , all_name )
2011-11-26 09:19:53 +04:00
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 \n dump: 55,3 \n dump: 55,3 \n post: 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 ( )
2011-12-22 05:45:33 +04:00
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 ( %s truct.point.0*)* ' in generated , ' Missing expected warning details '
2011-11-26 09:19:53 +04:00
return
raise Exception ( ' We should not have gotten to here! ' )
2010-09-05 03:46:11 +04:00
2010-10-22 10:20:08 +04:00
def test_stdlibs ( self ) :
2011-10-21 23:08:44 +04:00
if Settings . USE_TYPED_ARRAYS == 2 :
2011-08-27 06:28:46 +04:00
# Typed arrays = 2 + safe heap prints a warning that messes up our output.
2011-10-21 23:08:44 +04:00
Settings . SAFE_HEAP = 0
2010-09-05 08:39:06 +04:00
src = '''
#include <stdio.h>
#include <stdlib.h>
2010-10-22 10:20:08 +04:00
#include <sys/time.h>
2010-09-05 08:39:06 +04:00
void clean ( )
{
printf ( " *cleaned* \\ n " ) ;
}
2010-12-05 00:52:23 +03:00
int comparer ( const void * a , const void * b ) {
int aa = * ( ( int * ) a ) ;
int bb = * ( ( int * ) b ) ;
return aa - bb ;
}
2010-09-05 08:39:06 +04:00
int main ( ) {
2010-12-05 00:52:23 +03:00
/ / timeofday
2010-10-22 10:20:08 +04:00
timeval t ;
gettimeofday ( & t , NULL ) ;
2010-12-05 00:52:23 +03:00
printf ( " * %d , %d \\ n " , int ( t . tv_sec ) , int ( t . tv_usec ) ) ; / / should not crash
/ / atexit
2010-09-05 08:39:06 +04:00
atexit ( clean ) ;
2010-12-05 00:52:23 +03:00
/ / qsort
int values [ 6 ] = { 3 , 2 , 5 , 1 , 5 , 6 } ;
qsort ( values , 5 , sizeof ( int ) , comparer ) ;
printf ( " * %d , %d , %d , %d , %d , %d * \\ n " , values [ 0 ] , values [ 1 ] , values [ 2 ] , values [ 3 ] , values [ 4 ] , values [ 5 ] ) ;
2010-12-11 09:59:38 +03:00
printf ( " *stdin==0: %d * \\ n " , stdin == 0 ) ; / / check that external values are at least not NULL
2010-12-12 08:29:03 +03:00
printf ( " * %% * \\ n " ) ;
printf ( " * %.1ld * \\ n " , 5 ) ;
2010-12-11 09:59:38 +03:00
2010-12-13 02:05:22 +03:00
printf ( " * %.1f * \\ n " , strtod ( " 66 " , NULL ) ) ; / / checks dependency system , as our strtod needs _isspace etc .
2011-08-23 09:50:23 +04:00
printf ( " * %ld * \\ n " , strtol ( " 10 " , NULL , 0 ) ) ;
printf ( " * %ld * \\ n " , strtol ( " 0 " , NULL , 0 ) ) ;
printf ( " * %ld * \\ n " , strtol ( " -10 " , NULL , 0 ) ) ;
printf ( " * %ld * \\ n " , strtol ( " 12 " , NULL , 16 ) ) ;
printf ( " * %lu * \\ n " , strtoul ( " 10 " , NULL , 0 ) ) ;
printf ( " * %lu * \\ n " , strtoul ( " 0 " , NULL , 0 ) ) ;
printf ( " * %lu * \\ n " , strtoul ( " -10 " , NULL , 0 ) ) ;
2011-11-17 08:51:15 +04:00
printf ( " *malloc(0)!=0: %d * \\ n " , malloc ( 0 ) != 0 ) ; / / We should not fail horribly
2010-09-05 08:39:06 +04:00
return 0 ;
}
'''
2011-08-23 09:50:23 +04:00
2011-11-17 08:51:15 +04:00
self . do_run ( src , ' *1,2,3,5,5,6* \n *stdin==0:0* \n * % * \n *5* \n *66.0* \n *10* \n *0* \n *-10* \n *18* \n *10* \n *0* \n *4294967286* \n *malloc(0)!=0:1* \n *cleaned* ' )
2010-09-05 08:39:06 +04:00
2011-12-21 08:53:27 +04:00
src = r '''
#include <stdio.h>
#include <stdbool.h>
int main ( ) {
bool x = true ;
bool y = false ;
printf ( " * %d * \n " , x != y ) ;
return 0 ;
}
'''
self . do_run ( src , ' *1* ' , force_c = True )
2011-07-03 08:36:10 +04:00
def test_time ( self ) :
2011-11-13 23:18:51 +04:00
# XXX Not sure what the right output is here. Looks like the test started failing with daylight savings changes. Modified it to pass again.
2011-07-03 08:36:10 +04:00
src = open ( path_from_root ( ' tests ' , ' time ' , ' src.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' time ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected ,
2011-10-06 21:27:55 +04:00
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'])
2011-07-03 08:36:10 +04:00
2010-09-09 07:49:49 +04:00
def test_statics ( self ) :
2011-06-04 01:40:15 +04:00
# static initializers save i16 but load i8 for some reason
2011-10-21 23:08:44 +04:00
if Settings . SAFE_HEAP :
Settings . SAFE_HEAP = 3
Settings . SAFE_HEAP_LINES = [ ' src.cpp:19 ' , ' src.cpp:26 ' ]
2011-06-04 01:40:15 +04:00
2010-09-09 07:49:49 +04:00
src = '''
#include <stdio.h>
#include <string.h>
#define CONSTRLEN 32
void conoutfv ( const char * fmt )
{
static char buf [ CONSTRLEN ] ;
strcpy ( buf , fmt ) ;
puts ( buf ) ;
}
2010-10-25 02:43:08 +04:00
struct XYZ {
float x , y , z ;
XYZ ( float a , float b , float c ) : x ( a ) , y ( b ) , z ( c ) { }
static const XYZ & getIdentity ( )
{
static XYZ iT ( 1 , 2 , 3 ) ;
return iT ;
}
} ;
struct S {
static const XYZ & getIdentity ( )
{
static const XYZ iT ( XYZ : : getIdentity ( ) ) ;
return iT ;
}
} ;
2010-09-09 07:49:49 +04:00
int main ( ) {
conoutfv ( " *staticccz* " ) ;
2010-10-25 02:43:08 +04:00
printf ( " * %.2f , %.2f , %.2f * \\ n " , S : : getIdentity ( ) . x , S : : getIdentity ( ) . y , S : : getIdentity ( ) . z ) ;
2010-09-09 07:49:49 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *staticccz* \n *1.00,2.00,3.00* ' )
2010-09-09 07:49:49 +04:00
2010-09-26 07:26:16 +04:00
def test_copyop ( self ) :
# clang generated code is vulnerable to this, as it uses
# memcpy for assignments, with hardcoded numbers of bytes
# (llvm-gcc copies items one by one). See QUANTUM_SIZE in
# settings.js.
src = '''
#include <stdio.h>
#include <math.h>
2011-04-22 18:53:31 +04:00
#include <string.h>
2010-09-26 07:26:16 +04:00
struct vec {
double x , y , z ;
vec ( ) : x ( 0 ) , y ( 0 ) , z ( 0 ) { } ;
vec ( const double a , const double b , const double c ) : x ( a ) , y ( b ) , z ( c ) { } ;
} ;
struct basis {
vec a , b , c ;
basis ( const vec & v ) {
a = v ; / / should not touch b !
printf ( " * %.2f , %.2f , %.2f * \\ n " , b . x , b . y , b . z ) ;
}
} ;
int main ( ) {
basis B ( vec ( 1 , 0 , 0 ) ) ;
2011-04-22 18:53:31 +04:00
/ / Part 2 : similar problem with memset and memmove
int x = 1 , y = 77 , z = 2 ;
memset ( ( void * ) & x , 0 , sizeof ( int ) ) ;
memset ( ( void * ) & z , 0 , sizeof ( int ) ) ;
printf ( " * %d , %d , %d * \\ n " , x , y , z ) ;
memcpy ( ( void * ) & x , ( void * ) & z , sizeof ( int ) ) ;
memcpy ( ( void * ) & z , ( void * ) & x , sizeof ( int ) ) ;
printf ( " * %d , %d , %d * \\ n " , x , y , z ) ;
memmove ( ( void * ) & x , ( void * ) & z , sizeof ( int ) ) ;
memmove ( ( void * ) & z , ( void * ) & x , sizeof ( int ) ) ;
printf ( " * %d , %d , %d * \\ n " , x , y , z ) ;
2010-09-26 07:26:16 +04:00
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *0.00,0.00,0.00* \n *0,77,0* \n *0,77,0* \n *0,77,0* ' )
2010-09-26 07:26:16 +04:00
2011-09-18 10:49:38 +04:00
def test_memcpy ( self ) :
src = '''
#include <stdio.h>
#include <string.h>
#define MAXX 48
void reset ( unsigned char * buffer ) {
for ( int i = 0 ; i < MAXX ; i + + ) buffer [ i ] = i + 1 ;
}
void dump ( unsigned char * buffer ) {
for ( int i = 0 ; i < MAXX - 1 ; i + + ) printf ( " %2d , " , buffer [ i ] ) ;
printf ( " %d \\ n " , buffer [ MAXX - 1 ] ) ;
}
int main ( ) {
unsigned char buffer [ MAXX ] ;
for ( int i = MAXX / 4 ; i < MAXX - MAXX / 4 ; i + + ) {
for ( int j = MAXX / 4 ; j < MAXX - MAXX / 4 ; j + + ) {
for ( int k = 1 ; k < MAXX / 4 ; k + + ) {
if ( i == j ) continue ;
if ( i < j & & i + k > j ) continue ;
if ( j < i & & j + k > i ) continue ;
2011-11-04 22:54:27 +04:00
printf ( " [ %d , %d , %d ] " , i , j , k ) ;
2011-09-18 10:49:38 +04:00
reset ( buffer ) ;
memcpy ( buffer + i , buffer + j , k ) ;
dump ( buffer ) ;
}
}
}
return 0 ;
}
'''
2012-01-27 22:22:14 +04:00
def check ( result ) :
return hashlib . sha1 ( result ) . hexdigest ( )
self . do_run ( src , ' 6c9cdfe937383b79e52ca7a2cce83a21d9f5422c ' ,
output_nicerizer = check )
2011-09-18 10:49:38 +04:00
2012-01-07 08:38:59 +04:00
def test_memmove ( self ) :
src = '''
#include <stdio.h>
#include <string.h>
int main ( ) {
char str [ ] = " memmove can be very useful....! " ;
memmove ( str + 20 , str + 15 , 11 ) ;
puts ( str ) ;
return 0 ;
}
'''
2012-01-27 22:22:14 +04:00
self . do_run ( src , ' memmove can be very very useful ' )
2012-01-07 08:38:59 +04:00
2011-12-08 23:44:30 +04:00
def test_bsearch ( self ) :
2011-12-24 06:35:19 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' Test cannot work with q1 ' )
2011-12-08 23:44:30 +04:00
src = '''
#include <stdlib.h>
#include <stdio.h>
int cmp ( const void * key , const void * member ) {
return * ( int * ) key - * ( int * ) member ;
}
void printResult ( int * needle , int * haystack , unsigned int len ) {
void * result = bsearch ( needle , haystack , len , sizeof ( unsigned int ) , cmp ) ;
if ( result == NULL ) {
printf ( " null \\ n " ) ;
} else {
printf ( " %d \\ n " , * ( unsigned int * ) result ) ;
}
}
int main ( ) {
int a [ ] = { - 2 , - 1 , 0 , 6 , 7 , 9 } ;
int b [ ] = { 0 , 1 } ;
/ * Find all keys that exist . * /
for ( int i = 0 ; i < 6 ; i + + ) {
int val = a [ i ] ;
printResult ( & val , a , 6 ) ;
}
/ * Keys that are covered by the range of the array but aren ' t in
* the array cannot be found .
* /
int v1 = 3 ;
int v2 = 8 ;
printResult ( & v1 , a , 6 ) ;
printResult ( & v2 , a , 6 ) ;
/ * Keys outside the range of the array cannot be found . * /
int v3 = - 1 ;
int v4 = 2 ;
printResult ( & v3 , b , 2 ) ;
printResult ( & v4 , b , 2 ) ;
return 0 ;
}
'''
self . do_run ( src , ' -2 \n -1 \n 0 \n 6 \n 7 \n 9 \n null \n null \n null \n null ' )
2010-09-15 07:10:32 +04:00
def test_nestedstructs ( self ) :
src = '''
#include <stdio.h>
#include "emscripten.h"
struct base {
int x ;
float y ;
union {
int a ;
float b ;
} ;
char c ;
} ;
struct hashtableentry {
int key ;
base data ;
} ;
struct hashset {
typedef hashtableentry entry ;
struct chain { entry elem ; chain * next ; } ;
/ / struct chainchunk { chain chains [ 100 ] ; chainchunk * next ; } ;
} ;
struct hashtable : hashset {
hashtable ( ) {
base * b = NULL ;
entry * e = NULL ;
chain * c = NULL ;
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 * \\ n " ,
2011-04-22 18:53:31 +04:00
sizeof ( base ) ,
2010-09-15 07:10:32 +04:00
int ( & ( b - > x ) ) , int ( & ( b - > y ) ) , int ( & ( b - > a ) ) , int ( & ( b - > b ) ) , int ( & ( b - > c ) ) ,
2011-04-22 18:53:31 +04:00
sizeof ( hashtableentry ) ,
2010-09-15 07:10:32 +04:00
int ( & ( e - > key ) ) , int ( & ( e - > data ) ) , int ( & ( e - > data . x ) ) , int ( & ( e - > data . y ) ) , int ( & ( e - > data . a ) ) , int ( & ( e - > data . b ) ) , int ( & ( e - > data . c ) ) ,
2011-04-22 18:53:31 +04:00
sizeof ( hashset : : chain ) ,
2010-09-15 07:10:32 +04:00
int ( & ( c - > elem ) ) , int ( & ( c - > next ) ) , int ( & ( c - > elem . key ) ) , int ( & ( c - > elem . data ) ) , int ( & ( c - > elem . data . x ) ) , int ( & ( c - > elem . data . y ) ) , int ( & ( c - > elem . data . a ) ) , int ( & ( c - > elem . data . b ) ) , int ( & ( c - > elem . data . c ) )
) ;
}
} ;
2010-10-10 00:55:35 +04:00
struct B { char buffer [ 62 ] ; int last ; char laster ; char laster2 ; } ;
2010-10-19 08:15:36 +04:00
struct Bits {
unsigned short A : 1 ;
unsigned short B : 1 ;
unsigned short C : 1 ;
unsigned short D : 1 ;
unsigned short x1 : 1 ;
unsigned short x2 : 1 ;
unsigned short x3 : 1 ;
unsigned short x4 : 1 ;
} ;
2010-09-15 07:10:32 +04:00
int main ( ) {
hashtable t ;
2010-10-10 00:55:35 +04:00
/ / Part 2 - the char [ ] should be compressed , BUT have a padding space at the end so the next
/ / one is aligned properly . Also handle char ; char ; etc . properly .
B * b = NULL ;
printf ( " * %d , %d , %d , %d , %d , %d , %d , %d , %d * \\ n " , int ( b ) , int ( & ( b - > buffer ) ) , int ( & ( b - > buffer [ 0 ] ) ) , int ( & ( b - > buffer [ 1 ] ) ) , int ( & ( b - > buffer [ 2 ] ) ) ,
2011-04-22 18:53:31 +04:00
int ( & ( b - > last ) ) , int ( & ( b - > laster ) ) , int ( & ( b - > laster2 ) ) , sizeof ( B ) ) ;
2010-10-10 00:55:35 +04:00
2010-10-19 08:15:36 +04:00
/ / Part 3 - bitfields , and small structures
Bits * b2 = NULL ;
2011-04-22 18:53:31 +04:00
printf ( " * %d * \\ n " , sizeof ( Bits ) ) ;
2010-10-19 08:15:36 +04:00
2010-09-15 07:10:32 +04:00
return 0 ;
}
'''
2011-10-21 23:08:44 +04:00
if Settings . QUANTUM_SIZE == 1 :
2011-04-22 18:53:31 +04:00
# Compressed memory. Note that sizeof() does give the fat sizes, however!
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *16,0,1,2,2,3|20,0,1,1,2,3,3,4|24,0,5,0,1,1,2,3,3,4* \n *0,0,0,1,2,62,63,64,72* \n *2* ' )
2010-09-26 07:26:16 +04:00
else :
# Bloated memory; same layout as C/C++
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *16,0,4,8,8,12|20,0,4,4,8,12,12,16|24,0,20,0,4,4,8,12,12,16* \n *0,0,0,1,2,64,68,69,72* \n *2* ' )
2010-09-15 07:10:32 +04:00
2011-12-06 02:09:46 +04:00
def test_runtimelink ( self ) :
2011-12-06 03:15:04 +04:00
if Building . LLVM_OPTS : return self . skip ( ' LLVM opts will optimize printf into puts in the parent, and the child will still look for puts ' )
2012-01-19 06:10:57 +04:00
Settings . LINKABLE = 1
2011-12-06 05:57:54 +04:00
self . banned_js_engines = [ NODE_JS ] # node's global scope behaves differently than everything else, needs investigation FIXME
2011-12-06 03:15:04 +04:00
2011-12-06 02:09:46 +04:00
header = r '''
struct point
{
int x , y ;
} ;
'''
open ( os . path . join ( self . get_dir ( ) , ' header.h ' ) , ' w ' ) . write ( header )
supp = r '''
#include <stdio.h>
#include "header.h"
extern void mainFunc ( int x ) ;
extern int mainInt ;
void suppFunc ( struct point & p ) {
printf ( " supp: %d , %d \n " , p . x , p . y ) ;
mainFunc ( p . x + p . y ) ;
printf ( " supp see: %d \n " , mainInt ) ;
}
2011-12-06 05:57:54 +04:00
int suppInt = 76 ;
2011-12-06 02:09:46 +04:00
'''
supp_name = os . path . join ( self . get_dir ( ) , ' supp.c ' )
open ( supp_name , ' w ' ) . write ( supp )
main = r '''
#include <stdio.h>
#include "header.h"
extern void suppFunc ( struct point & p ) ;
extern int suppInt ;
void mainFunc ( int x ) {
printf ( " main: %d \n " , x ) ;
}
int mainInt = 543 ;
int main ( int argc , const char * argv [ ] ) {
struct point p = { 54 , 2 } ;
suppFunc ( p ) ;
2011-12-06 05:57:54 +04:00
printf ( " main see: %d \n ok. \n " , suppInt ) ;
2011-12-06 02:09:46 +04:00
return 0 ;
}
'''
Settings . BUILD_AS_SHARED_LIB = 2
dirname = self . get_dir ( )
self . build ( supp , dirname , supp_name )
shutil . move ( supp_name + ' .o.js ' , os . path . join ( dirname , ' liblib.so ' ) )
Settings . BUILD_AS_SHARED_LIB = 0
Settings . RUNTIME_LINKED_LIBS = [ ' liblib.so ' ] ;
2011-12-06 05:57:54 +04:00
self . do_run ( main , ' supp: 54,2 \n main: 56 \n supp see: 543 \n main see: 76 \n ok. ' )
2011-12-06 02:09:46 +04:00
2011-06-26 05:57:06 +04:00
def test_dlfcn_basic ( self ) :
2012-01-20 04:23:28 +04:00
Settings . LINKABLE = 1
2011-06-26 05:57:06 +04:00
lib_src = '''
#include <cstdio>
class Foo {
public :
Foo ( ) {
printf ( " Constructing lib object. \\ n " ) ;
}
} ;
Foo global ;
'''
dirname = self . get_dir ( )
filename = os . path . join ( dirname , ' liblib.cpp ' )
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 1
2011-06-26 05:57:06 +04:00
self . build ( lib_src , dirname , filename )
2011-06-29 12:25:15 +04:00
shutil . move ( filename + ' .o.js ' , os . path . join ( dirname , ' liblib.so ' ) )
2011-06-26 05:57:06 +04:00
src = '''
#include <cstdio>
#include <dlfcn.h>
class Bar {
public :
Bar ( ) {
printf ( " Constructing main object. \\ n " ) ;
}
} ;
Bar global ;
int main ( ) {
dlopen ( " liblib.so " , RTLD_NOW ) ;
return 0 ;
}
'''
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 0
2011-12-21 06:49:42 +04:00
add_pre_run_and_checks = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
" FS.createLazyFile( ' / ' , ' liblib.so ' , ' liblib.so ' , true, false); "
)
open ( filename , ' w ' ) . write ( src )
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' Constructing main object. \n Constructing lib object. \n ' ,
2011-12-21 09:15:48 +04:00
post_build = add_pre_run_and_checks )
2011-06-26 05:57:06 +04:00
def test_dlfcn_qsort ( self ) :
2012-01-20 04:23:28 +04:00
Settings . LINKABLE = 1
2011-11-12 07:07:55 +04:00
if Settings . USE_TYPED_ARRAYS == 2 :
Settings . CORRECT_SIGNS = 1 # Needed for unsafe optimizations
2011-06-26 05:57:06 +04:00
lib_src = '''
int lib_cmp ( const void * left , const void * right ) {
const int * a = ( const int * ) left ;
const int * b = ( const int * ) right ;
if ( * a > * b ) return 1 ;
else if ( * a == * b ) return 0 ;
else return - 1 ;
}
typedef int ( * CMP_TYPE ) ( const void * , const void * ) ;
2011-08-25 23:21:00 +04:00
extern " C " CMP_TYPE get_cmp ( ) {
2011-06-26 05:57:06 +04:00
return lib_cmp ;
}
'''
dirname = self . get_dir ( )
filename = os . path . join ( dirname , ' liblib.cpp ' )
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 1
Settings . EXPORTED_FUNCTIONS = [ ' _get_cmp ' ]
2011-06-26 05:57:06 +04:00
self . build ( lib_src , dirname , filename )
2011-06-29 12:25:15 +04:00
shutil . move ( filename + ' .o.js ' , os . path . join ( dirname , ' liblib.so ' ) )
2011-06-26 05:57:06 +04:00
src = '''
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
typedef int ( * CMP_TYPE ) ( const void * , const void * ) ;
int main_cmp ( const void * left , const void * right ) {
const int * a = ( const int * ) left ;
const int * b = ( const int * ) right ;
if ( * a < * b ) return 1 ;
else if ( * a == * b ) return 0 ;
else return - 1 ;
}
int main ( ) {
void * lib_handle ;
CMP_TYPE ( * getter_ptr ) ( ) ;
2011-06-26 06:39:05 +04:00
CMP_TYPE lib_cmp_ptr ;
2011-06-26 05:57:06 +04:00
int arr [ 5 ] = { 4 , 2 , 5 , 1 , 3 } ;
lib_handle = dlopen ( " liblib.so " , RTLD_NOW ) ;
if ( lib_handle == NULL ) {
printf ( " Could not load lib. \\ n " ) ;
return 1 ;
}
2011-08-25 23:21:00 +04:00
getter_ptr = ( CMP_TYPE ( * ) ( ) ) dlsym ( lib_handle , " get_cmp " ) ;
2011-06-26 05:57:06 +04:00
if ( getter_ptr == NULL ) {
printf ( " Could not find func. \\ n " ) ;
return 1 ;
}
2011-06-26 06:39:05 +04:00
lib_cmp_ptr = getter_ptr ( ) ;
2011-06-26 05:57:06 +04:00
qsort ( ( void * ) arr , 5 , sizeof ( int ) , main_cmp ) ;
printf ( " Sort with main comparison: " ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
printf ( " %d " , arr [ i ] ) ;
}
printf ( " \\ n " ) ;
2011-06-26 06:39:05 +04:00
qsort ( ( void * ) arr , 5 , sizeof ( int ) , lib_cmp_ptr ) ;
2011-06-26 05:57:06 +04:00
printf ( " Sort with lib comparison: " ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
printf ( " %d " , arr [ i ] ) ;
}
printf ( " \\ n " ) ;
return 0 ;
}
'''
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 0
Settings . EXPORTED_FUNCTIONS = [ ' _main ' ]
2011-12-21 09:15:48 +04:00
add_pre_run_and_checks = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
" FS.createLazyFile( ' / ' , ' liblib.so ' , ' liblib.so ' , true, false); "
)
open ( filename , ' w ' ) . write ( src )
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' Sort with main comparison: 5 4 3 2 1 *Sort with lib comparison: 1 2 3 4 5 * ' ,
2011-12-21 09:15:48 +04:00
output_nicerizer = lambda x : x . replace ( ' \n ' , ' * ' ) ,
post_build = add_pre_run_and_checks )
2011-06-26 05:57:06 +04:00
def test_dlfcn_data_and_fptr ( self ) :
2011-10-27 07:41:51 +04:00
if Building . LLVM_OPTS : return self . skip ( ' LLVM opts will optimize out parent_func ' )
2011-06-30 06:16:08 +04:00
2012-01-19 06:10:57 +04:00
Settings . LINKABLE = 1
2011-06-26 05:57:06 +04:00
lib_src = '''
#include <stdio.h>
int global = 42 ;
2011-06-30 06:16:08 +04:00
extern void parent_func ( ) ; / / a function that is defined in the parent
2011-06-26 05:57:06 +04:00
void lib_fptr ( ) {
printf ( " Second calling lib_fptr from main. \\ n " ) ;
2011-06-30 06:16:08 +04:00
parent_func ( ) ;
/ / call it also through a pointer , to check indexizing
void ( * p_f ) ( ) ;
p_f = parent_func ;
p_f ( ) ;
2011-06-26 05:57:06 +04:00
}
2011-08-25 23:21:00 +04:00
extern " C " void ( * func ( int x , void ( * fptr ) ( ) ) ) ( ) {
2011-06-26 05:57:06 +04:00
printf ( " In func: %d \\ n " , x ) ;
fptr ( ) ;
return lib_fptr ;
}
'''
dirname = self . get_dir ( )
filename = os . path . join ( dirname , ' liblib.cpp ' )
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 1
Settings . EXPORTED_FUNCTIONS = [ ' _func ' ]
Settings . EXPORTED_GLOBALS = [ ' _global ' ]
2011-06-26 05:57:06 +04:00
self . build ( lib_src , dirname , filename )
2011-06-29 12:25:15 +04:00
shutil . move ( filename + ' .o.js ' , os . path . join ( dirname , ' liblib.so ' ) )
2011-06-26 05:57:06 +04:00
src = '''
#include <stdio.h>
#include <dlfcn.h>
typedef void ( * FUNCTYPE ( int , void ( * ) ( ) ) ) ( ) ;
FUNCTYPE func ;
2011-06-30 06:16:08 +04:00
void parent_func ( ) {
printf ( " parent_func called from child \\ n " ) ;
}
2011-06-26 05:57:06 +04:00
void main_fptr ( ) {
printf ( " First calling main_fptr from lib. \\ n " ) ;
}
int main ( ) {
void * lib_handle ;
FUNCTYPE * func_fptr ;
/ / Test basic lib loading .
lib_handle = dlopen ( " liblib.so " , RTLD_NOW ) ;
if ( lib_handle == NULL ) {
printf ( " Could not load lib. \\ n " ) ;
return 1 ;
}
/ / Test looked up function .
2011-08-25 23:21:00 +04:00
func_fptr = ( FUNCTYPE * ) dlsym ( lib_handle , " func " ) ;
2011-08-02 11:23:41 +04:00
/ / Load twice to test cache .
2011-08-25 23:21:00 +04:00
func_fptr = ( FUNCTYPE * ) dlsym ( lib_handle , " func " ) ;
2011-06-26 05:57:06 +04:00
if ( func_fptr == NULL ) {
printf ( " Could not find func. \\ n " ) ;
return 1 ;
}
/ / Test passing function pointers across module bounds .
void ( * fptr ) ( ) = func_fptr ( 13 , main_fptr ) ;
fptr ( ) ;
/ / Test global data .
int * global = ( int * ) dlsym ( lib_handle , " global " ) ;
if ( global == NULL ) {
printf ( " Could not find global. \\ n " ) ;
return 1 ;
}
printf ( " Var: %d \\ n " , * global ) ;
return 0 ;
}
'''
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 0
Settings . EXPORTED_FUNCTIONS = [ ' _main ' ]
Settings . EXPORTED_GLOBALS = [ ]
2011-12-21 09:15:48 +04:00
add_pre_run_and_checks = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
" FS.createLazyFile( ' / ' , ' liblib.so ' , ' liblib.so ' , true, false); "
)
open ( filename , ' w ' ) . write ( src )
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' In func: 13*First calling main_fptr from lib.*Second calling lib_fptr from main.*parent_func called from child*parent_func called from child*Var: 42* ' ,
2011-07-28 14:55:24 +04:00
output_nicerizer = lambda x : x . replace ( ' \n ' , ' * ' ) ,
2011-07-30 03:46:20 +04:00
post_build = add_pre_run_and_checks )
2011-06-26 05:57:06 +04:00
2011-08-25 09:26:39 +04:00
def test_dlfcn_alias ( self ) :
2012-01-20 04:23:28 +04:00
Settings . LINKABLE = 1
2011-11-22 04:59:37 +04:00
if Building . LLVM_OPTS == 2 : return self . skip ( ' LLVM LTO will optimize away stuff we expect from the shared library ' )
2011-08-25 09:26:39 +04:00
lib_src = r '''
#include <stdio.h>
extern int parent_global ;
2011-08-25 23:21:00 +04:00
extern " C " void func ( ) {
2011-08-25 09:26:39 +04:00
printf ( " Parent global: %d . \n " , parent_global ) ;
}
'''
dirname = self . get_dir ( )
filename = os . path . join ( dirname , ' liblib.cpp ' )
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 1
Settings . EXPORTED_FUNCTIONS = [ ' _func ' ]
2011-08-25 09:26:39 +04:00
self . build ( lib_src , dirname , filename )
shutil . move ( filename + ' .o.js ' , os . path . join ( dirname , ' liblib.so ' ) )
src = r '''
#include <dlfcn.h>
int parent_global = 123 ;
int main ( ) {
void * lib_handle ;
void ( * fptr ) ( ) ;
lib_handle = dlopen ( " liblib.so " , RTLD_NOW ) ;
2011-08-25 23:21:00 +04:00
fptr = ( void ( * ) ( ) ) dlsym ( lib_handle , " func " ) ;
2011-08-25 09:26:39 +04:00
fptr ( ) ;
parent_global = 456 ;
fptr ( ) ;
return 0 ;
}
'''
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 0
Settings . INCLUDE_FULL_LIBRARY = 1
Settings . EXPORTED_FUNCTIONS = [ ' _main ' ]
2011-12-21 09:15:48 +04:00
add_pre_run_and_checks = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
" FS.createLazyFile( ' / ' , ' liblib.so ' , ' liblib.so ' , true, false); "
)
open ( filename , ' w ' ) . write ( src )
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' Parent global: 123.*Parent global: 456.* ' ,
2011-12-21 09:15:48 +04:00
output_nicerizer = lambda x : x . replace ( ' \n ' , ' * ' ) ,
post_build = add_pre_run_and_checks ,
extra_emscripten_args = [ ' -H ' , ' libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/time.h,libc/langinfo.h ' ] )
2011-10-21 23:08:44 +04:00
Settings . INCLUDE_FULL_LIBRARY = 0
2011-08-25 09:26:39 +04:00
2011-08-25 11:53:27 +04:00
def test_dlfcn_varargs ( self ) :
2012-01-20 04:23:28 +04:00
Settings . LINKABLE = 1
2011-11-22 04:59:37 +04:00
if Building . LLVM_OPTS == 2 : return self . skip ( ' LLVM LTO will optimize things that prevent shared objects from working ' )
2011-10-21 23:08:44 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' FIXME: Add support for this ' )
2011-11-22 04:59:37 +04:00
2011-08-25 11:53:27 +04:00
lib_src = r '''
void print_ints ( int n , . . . ) ;
2011-08-25 23:21:00 +04:00
extern " C " void func ( ) {
2011-08-25 11:53:27 +04:00
print_ints ( 2 , 13 , 42 ) ;
}
'''
dirname = self . get_dir ( )
filename = os . path . join ( dirname , ' liblib.cpp ' )
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 1
Settings . EXPORTED_FUNCTIONS = [ ' _func ' ]
2011-08-25 11:53:27 +04:00
self . build ( lib_src , dirname , filename )
shutil . move ( filename + ' .o.js ' , os . path . join ( dirname , ' liblib.so ' ) )
src = r '''
#include <stdarg.h>
#include <stdio.h>
#include <dlfcn.h>
void print_ints ( int n , . . . ) {
va_list args ;
va_start ( args , n ) ;
for ( int i = 0 ; i < n ; i + + ) {
printf ( " %d \n " , va_arg ( args , int ) ) ;
}
va_end ( args ) ;
}
int main ( ) {
void * lib_handle ;
void ( * fptr ) ( ) ;
print_ints ( 2 , 100 , 200 ) ;
lib_handle = dlopen ( " liblib.so " , RTLD_NOW ) ;
2011-08-25 23:21:00 +04:00
fptr = ( void ( * ) ( ) ) dlsym ( lib_handle , " func " ) ;
2011-08-25 11:53:27 +04:00
fptr ( ) ;
return 0 ;
}
'''
2011-10-21 23:08:44 +04:00
Settings . BUILD_AS_SHARED_LIB = 0
Settings . EXPORTED_FUNCTIONS = [ ' _main ' ]
2011-12-21 09:15:48 +04:00
add_pre_run_and_checks = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-21 09:28:08 +04:00
" FS.createLazyFile( ' / ' , ' liblib.so ' , ' liblib.so ' , true, false); "
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-11-22 04:59:37 +04:00
self . do_run ( src , ' 100 \n 200 \n 13 \n 42 \n ' ,
2011-12-21 09:15:48 +04:00
post_build = add_pre_run_and_checks )
2011-08-25 11:53:27 +04:00
2011-08-23 12:17:50 +04:00
def test_rand ( self ) :
src = r '''
#include <stdio.h>
#include <stdlib.h>
int main ( ) {
printf ( " %d \n " , rand ( ) ) ;
printf ( " %d \n " , rand ( ) ) ;
srand ( 123 ) ;
printf ( " %d \n " , rand ( ) ) ;
printf ( " %d \n " , rand ( ) ) ;
srand ( 123 ) ;
printf ( " %d \n " , rand ( ) ) ;
printf ( " %d \n " , rand ( ) ) ;
unsigned state = 0 ;
int r ;
r = rand_r ( & state ) ;
printf ( " %d , %u \n " , r , state ) ;
r = rand_r ( & state ) ;
printf ( " %d , %u \n " , r , state ) ;
state = 0 ;
r = rand_r ( & state ) ;
printf ( " %d , %u \n " , r , state ) ;
return 0 ;
}
'''
expected = '''
1250496027
1116302336
440917656
1476150784
440917656
1476150784
12345 , 12345
1406932606 , 3554416254
12345 , 12345
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( r ' (^| \ n) \ s+ ' , r ' \ 1 ' , expected ) )
2011-08-23 12:17:50 +04:00
2011-06-27 11:39:31 +04:00
def test_strtod ( self ) :
src = r '''
#include <stdio.h>
#include <stdlib.h>
int main ( ) {
char * endptr ;
printf ( " \n " ) ;
printf ( " %g \n " , strtod ( " 0 " , & endptr ) ) ;
printf ( " %g \n " , strtod ( " 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 ( " 123 " , & endptr ) ) ;
printf ( " %g \n " , strtod ( " 123.456 " , & endptr ) ) ;
2011-08-28 11:06:36 +04:00
printf ( " %g \n " , strtod ( " -123.456 " , & endptr ) ) ;
2011-06-27 11:39:31 +04:00
printf ( " %g \n " , strtod ( " 1234567891234567890 " , & endptr ) ) ;
printf ( " %g \n " , strtod ( " 1234567891234567890e+50 " , & endptr ) ) ;
printf ( " %g \n " , strtod ( " 84e+220 " , & endptr ) ) ;
printf ( " %g \n " , strtod ( " 123e-50 " , & endptr ) ) ;
printf ( " %g \n " , strtod ( " 123e-250 " , & endptr ) ) ;
printf ( " %g \n " , strtod ( " 123e-450 " , & endptr ) ) ;
2011-08-28 11:06:36 +04:00
char str [ ] = " 12.34e56end " ;
printf ( " %g \n " , strtod ( str , & endptr ) ) ;
2011-06-27 11:39:31 +04:00
printf ( " %d \n " , endptr - str ) ;
2011-12-08 02:19:19 +04:00
printf ( " %g \n " , strtod ( " 84e+420 " , & endptr ) ) ;
2011-06-27 11:39:31 +04:00
return 0 ;
}
'''
expected = '''
0
0
0
1
1
1
123
123.456
2011-08-28 11:06:36 +04:00
- 123.456
2011-06-27 11:39:31 +04:00
1.23457e+18
1.23457e+68
8.4e+221
1.23e-48
1.23e-248
0
2011-08-28 11:06:36 +04:00
1.234e+57
10
2011-12-08 02:19:19 +04:00
inf
2011-06-27 11:39:31 +04:00
'''
2011-12-08 02:19:19 +04:00
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( r ' \ n \ s+ ' , ' \n ' , expected ) )
2011-06-27 11:39:31 +04:00
2011-12-09 23:14:33 +04:00
def test_strtok ( self ) :
src = r '''
#include<stdio.h>
#include<string.h>
int main ( ) {
char test [ 80 ] , blah [ 80 ] ;
char * sep = " \\ /:;=- " ;
char * word , * phrase , * brkt , * brkb ;
strcpy ( test , " This;is.a:test:of=the/string \\ tokenizer-function. " ) ;
for ( word = strtok_r ( test , sep , & brkt ) ; word ; word = strtok_r ( NULL , sep , & brkt ) ) {
strcpy ( blah , " blah:blat:blab:blag " ) ;
for ( phrase = strtok_r ( blah , sep , & brkb ) ; phrase ; phrase = strtok_r ( NULL , sep , & brkb ) ) {
printf ( " at %s : %s \n " , word , phrase ) ;
}
}
return 1 ;
}
'''
expected = ''' at This:blah
at This : blat
at This : blab
at This : blag
at is . a : blah
at is . a : blat
at is . a : blab
at is . a : blag
at test : blah
at test : blat
at test : blab
at test : blag
at of : blah
at of : blat
at of : blab
at of : blag
at the : blah
at the : blat
at the : blab
at the : blag
at string : blah
at string : blat
at string : blab
at string : blag
at tokenizer : blah
at tokenizer : blat
at tokenizer : blab
at tokenizer : blag
at function . : blah
at function . : blat
at function . : blab
at function . : blag
'''
self . do_run ( src , expected )
2011-08-28 11:06:36 +04:00
def test_parseInt ( self ) :
2011-12-10 09:20:19 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' Q1 and I64_1 do not mix well yet ' )
2011-12-07 23:24:09 +04:00
Settings . I64_MODE = 1 # Necessary to prevent i64s being truncated into i32s, but we do still get doubling
# FIXME: The output here is wrong, due to double rounding of i64s!
2011-08-28 11:06:36 +04:00
src = open ( path_from_root ( ' tests ' , ' parseInt ' , ' src.c ' ) , ' r ' ) . read ( )
2011-12-07 23:24:09 +04:00
expected = open ( path_from_root ( ' tests ' , ' parseInt ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-08-28 11:06:36 +04:00
2011-06-27 11:10:40 +04:00
def test_printf ( self ) :
2011-12-10 09:20:19 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' Q1 and I64_1 do not mix well yet ' )
Settings . I64_MODE = 1
2011-12-08 05:51:15 +04:00
self . banned_js_engines = [ NODE_JS , V8_ENGINE ] # SpiderMonkey and V8 do different things to float64 typed arrays, un-NaNing, etc.
2011-06-27 11:10:40 +04:00
src = open ( path_from_root ( ' tests ' , ' printf ' , ' test.c ' ) , ' r ' ) . read ( )
2011-12-10 06:51:38 +04:00
expected = [ open ( path_from_root ( ' tests ' , ' printf ' , ' output.txt ' ) , ' r ' ) . read ( ) ,
open ( path_from_root ( ' tests ' , ' printf ' , ' output_i64_1.txt ' ) , ' r ' ) . read ( ) ]
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-06-27 11:10:40 +04:00
2011-08-25 17:15:30 +04:00
def test_printf_types ( self ) :
src = r '''
#include <stdio.h>
int main ( ) {
char c = ' 1 ' ;
short s = 2 ;
int i = 3 ;
long long l = 4 ;
float f = 5.5 ;
double d = 6.6 ;
printf ( " %c , %hd , %d , % lld, %.1f , % .1llf \n " , c , s , i , l , f , d ) ;
return 0 ;
}
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' 1,2,3,4,5.5,6.6 \n ' )
2011-08-25 17:15:30 +04:00
2011-08-25 17:04:06 +04:00
def test_vprintf ( self ) :
src = r '''
#include <stdio.h>
#include <stdarg.h>
void print ( char * format , . . . ) {
va_list args ;
va_start ( args , format ) ;
vprintf ( format , args ) ;
va_end ( args ) ;
}
int main ( ) {
print ( " Call with %d variable argument. \n " , 1 ) ;
print ( " Call with %d variable %s . \n " , 2 , " arguments " ) ;
return 0 ;
}
'''
expected = '''
Call with 1 variable argument .
Call with 2 variable arguments .
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( ' (^| \n ) \ s+ ' , ' \\ 1 ' , expected ) )
2011-08-25 17:04:06 +04:00
2011-11-03 05:21:55 +04:00
def test_atoi ( self ) :
src = r '''
#include <stdio.h>
#include <stdlib.h>
int main ( ) {
2012-01-27 22:22:14 +04:00
printf ( " %d * " , atoi ( " " ) ) ;
printf ( " %d * " , atoi ( " a " ) ) ;
printf ( " %d * " , atoi ( " b " ) ) ;
printf ( " %d * " , atoi ( " c " ) ) ;
printf ( " %d * " , atoi ( " 6 " ) ) ;
printf ( " %d * " , atoi ( " 5 " ) ) ;
printf ( " %d * " , atoi ( " 4 " ) ) ;
printf ( " %d * " , atoi ( " 3 6 " ) ) ;
printf ( " %d * " , atoi ( " 3 7 " ) ) ;
printf ( " %d * " , atoi ( " 9 d " ) ) ;
2011-11-03 05:21:55 +04:00
printf ( " %d \n " , atoi ( " 8 e " ) ) ;
return 0 ;
}
'''
2012-01-27 22:22:14 +04:00
self . do_run ( src , ' 0*0*0*0*6*5*4*3*3*9*8 ' )
2011-11-03 05:21:55 +04:00
2011-11-03 02:36:36 +04:00
def test_sscanf ( self ) :
src = r '''
#include <stdio.h>
#include <string.h>
2011-12-16 09:58:59 +04:00
#include <stdlib.h>
2011-11-03 02:36:36 +04:00
int main ( ) {
#define CHECK(str) \
{ \
char name [ 1000 ] ; \
memset ( name , 0 , 1000 ) ; \
int prio = 99 ; \
sscanf ( str , " %s %d " , name , & prio ) ; \
printf ( " %s : %d \n " , name , prio ) ; \
}
CHECK ( " en-us 2 " ) ;
CHECK ( " en-r " ) ;
CHECK ( " en 3 " ) ;
2011-12-16 09:58:59 +04:00
printf ( " %f , %f \n " , atof ( " 1.234567 " ) , atof ( " cheez " ) ) ;
2012-02-06 09:48:26 +04:00
float a = - 1 ;
sscanf ( " -3.03 " , " %f " , & a ) ;
printf ( " %.4f \n " , a ) ;
2011-11-03 02:36:36 +04:00
return 0 ;
}
'''
2012-02-06 09:48:26 +04:00
self . do_run ( src , ' en-us : 2 \n en-r : 99 \n en : 3 \n 1.234567, 0.000000 \n -3.0300 ' )
2011-11-03 02:36:36 +04:00
2012-02-06 09:48:26 +04:00
# Part 2: doubles
2011-12-25 05:41:29 +04:00
if Settings . USE_TYPED_ARRAYS == 2 :
for ftype in [ ' float ' , ' double ' ] :
src = r '''
#include <stdio.h>
2011-12-22 06:31:24 +04:00
2011-12-25 05:41:29 +04:00
int main ( ) {
char strval1 [ ] = " 1.2345678901 " ;
char strval2 [ ] = " 1.23456789e5 " ;
char strval3 [ ] = " 1.23456789E5 " ;
char strval4 [ ] = " 1.2345678e-5 " ;
char strval5 [ ] = " 1.2345678E-5 " ;
double dblval = 1.2345678901 ;
double tstval ;
sscanf ( strval1 , " %lf " , & tstval ) ;
if ( dblval != tstval ) printf ( " FAIL: Values are not equal: %lf %lf \n " , dblval , tstval ) ;
else printf ( " Pass: %lf %lf \n " , tstval , dblval ) ;
sscanf ( strval2 , " %lf " , & tstval ) ;
dblval = 123456.789 ;
if ( dblval != tstval ) printf ( " FAIL: Values are not equal: %lf %lf \n " , dblval , tstval ) ;
else printf ( " Pass: %lf %lf \n " , tstval , dblval ) ;
sscanf ( strval3 , " %lf " , & tstval ) ;
dblval = 123456.789 ;
if ( dblval != tstval ) printf ( " FAIL: Values are not equal: %lf %lf \n " , dblval , tstval ) ;
else printf ( " Pass: %lf %lf \n " , tstval , dblval ) ;
sscanf ( strval4 , " %lf " , & tstval ) ;
dblval = 0.000012345678 ;
if ( dblval != tstval ) printf ( " FAIL: Values are not equal: %lf %lf \n " , dblval , tstval ) ;
else printf ( " Pass: %lf %lf \n " , tstval , dblval ) ;
sscanf ( strval5 , " %lf " , & tstval ) ;
dblval = 0.000012345678 ;
if ( dblval != tstval ) printf ( " FAIL: Values are not equal: %lf %lf \n " , dblval , tstval ) ;
else printf ( " Pass: %lf %lf \n " , tstval , dblval ) ;
return 0 ;
}
'''
if ftype == ' float ' :
self . do_run ( src . replace ( ' %lf ' , ' %f ' ) . replace ( ' double ' , ' float ' ) , ''' Pass: 1.234568 1.234568
Pass : 123456.789063 123456.789063
Pass : 123456.789063 123456.789063
Pass : 0.000012 0.000012
Pass : 0.000012 0.000012 ''' )
else :
2012-01-27 22:22:14 +04:00
self . do_run ( src , ''' Pass: 1.234568 1.234568
Pass : 123456.789000 123456.789000
Pass : 123456.789000 123456.789000
Pass : 0.000012 0.000012
Pass : 0.000012 0.000012 ''' )
2011-12-22 06:31:24 +04:00
2011-08-17 08:44:30 +04:00
def test_langinfo ( self ) :
src = open ( path_from_root ( ' tests ' , ' langinfo ' , ' test.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' langinfo ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , extra_emscripten_args = [ ' -H ' , ' libc/langinfo.h ' ] )
2011-08-17 08:44:30 +04:00
2011-01-17 00:52:25 +03:00
def test_files ( self ) :
2011-12-22 04:01:33 +04:00
if self . emcc_args is not None and ' -O2 ' in self . emcc_args :
self . emcc_args + = [ ' --closure ' , ' 1 ' ] # Use closure here, to test we don't break FS stuff
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 1 # Just so our output is what we expect. Can flip them both.
2011-12-21 09:15:48 +04:00
post = '''
def process ( filename ) :
2012-02-06 01:33:20 +04:00
src = \' \' \'
var Module = {
' 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 ) ;
var test_files_input = ' hi there! ' ;
var test_files_input_index = 0 ;
FS . init ( function ( ) {
return test_files_input . charCodeAt ( test_files_input_index + + ) | | null ;
} ) ;
}
} ;
\' \' \' + open(filename, ' r ' ).read()
2011-12-21 09:15:48 +04:00
open ( filename , ' w ' ) . write ( src )
'''
2011-05-16 03:26:57 +04:00
other = open ( os . path . join ( self . get_dir ( ) , ' test.file ' ) , ' w ' )
other . write ( ' some data ' ) ;
other . close ( )
2011-01-17 00:52:25 +03:00
src = open ( path_from_root ( ' tests ' , ' files.cpp ' ) , ' r ' ) . read ( )
2011-12-21 07:53:06 +04:00
self . do_run ( src , ' size: 7 \n data: 100,-56,50,25,10,77,123 \n loop: 100 -56 50 25 10 77 123 \n input:hi there! \n texto \n texte \n $ \n 5 : 10,30,20,11,88 \n other=some data. \n seeked=me da. \n seeked=ata. \n seeked=ta. \n fscanfed: 10 - hello \n ' ,
2011-10-06 04:41:21 +04:00
post_build = post , extra_emscripten_args = [ ' -H ' , ' libc/fcntl.h ' ] )
2011-01-17 00:52:25 +03:00
2011-07-16 12:53:12 +04:00
def test_folders ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
\' \' \'
FS . createFolder ( ' / ' , ' test ' , true , false ) ;
FS . createPath ( ' / ' , ' test/hello/world/ ' , true , false ) ;
FS . createPath ( ' /test ' , ' goodbye/world/ ' , true , false ) ;
FS . createPath ( ' /test/goodbye ' , ' noentry ' , false , false ) ;
FS . createDataFile ( ' /test ' , ' freeforall.ext ' , ' abc ' , true , true ) ;
FS . createDataFile ( ' /test ' , ' restricted.ext ' , ' def ' , false , false ) ;
\' \' \'
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-16 12:53:12 +04:00
src = r '''
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
int main ( ) {
struct dirent * e ;
/ / Basic correct behaviour .
DIR * d = opendir ( " /test " ) ;
printf ( " --E: %d \n " , errno ) ;
while ( ( e = readdir ( d ) ) ) puts ( e - > d_name ) ;
printf ( " --E: %d \n " , errno ) ;
/ / Empty folder ; tell / seek .
puts ( " **** " ) ;
d = opendir ( " /test/hello/world/ " ) ;
e = readdir ( d ) ;
puts ( e - > d_name ) ;
int pos = telldir ( d ) ;
e = readdir ( d ) ;
puts ( e - > d_name ) ;
seekdir ( d , pos ) ;
e = readdir ( d ) ;
puts ( e - > d_name ) ;
/ / Errors .
puts ( " **** " ) ;
printf ( " --E: %d \n " , errno ) ;
d = opendir ( " /test/goodbye/noentry " ) ;
printf ( " --E: %d , D: %d \n " , errno , d ) ;
d = opendir ( " /i/dont/exist " ) ;
printf ( " --E: %d , D: %d \n " , errno , d ) ;
d = opendir ( " /test/freeforall.ext " ) ;
printf ( " --E: %d , D: %d \n " , errno , d ) ;
while ( ( e = readdir ( d ) ) ) puts ( e - > d_name ) ;
printf ( " --E: %d \n " , errno ) ;
return 0 ;
}
'''
expected = '''
- - E : 0
.
. .
hello
goodbye
freeforall . ext
restricted . ext
- - E : 0
* * * *
.
. .
. .
* * * *
- - E : 0
- - E : 13 , D : 0
- - E : 2 , D : 0
- - E : 20 , D : 0
- - E : 9
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( ' (^| \n ) \ s+ ' , ' \\ 1 ' , expected ) , post_build = add_pre_run )
2011-07-16 12:53:12 +04:00
2011-07-18 03:19:28 +04:00
def test_stat ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
\' \' \'
var f1 = FS . createFolder ( ' / ' , ' test ' , true , true ) ;
var f2 = FS . createDataFile ( f1 , ' file ' , ' abcdef ' , true , true ) ;
var f3 = FS . createLink ( f1 , ' link ' , ' file ' , true , true ) ;
var f4 = FS . createDevice ( f1 , ' device ' , function ( ) { } , function ( ) { } ) ;
f1 . timestamp = f2 . timestamp = f3 . timestamp = f4 . timestamp = new Date ( 1200000000000 ) ;
\' \' \'
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-18 03:19:28 +04:00
src = open ( path_from_root ( ' tests ' , ' stat ' , ' src.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' stat ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run , extra_emscripten_args = [ ' -H ' , ' libc/fcntl.h ' ] )
2011-07-20 11:20:09 +04:00
def test_fcntl ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
" FS.createDataFile( ' / ' , ' test ' , ' abcdef ' , true, true); "
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-20 11:20:09 +04:00
src = open ( path_from_root ( ' tests ' , ' fcntl ' , ' src.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' fcntl ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run , extra_emscripten_args = [ ' -H ' , ' libc/fcntl.h ' ] )
2011-07-20 11:20:09 +04:00
def test_fcntl_open ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
\' \' \'
FS . createDataFile ( ' / ' , ' test-file ' , ' abcdef ' , true , true ) ;
FS . createFolder ( ' / ' , ' test-folder ' , true , true ) ;
\' \' \'
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-20 11:20:09 +04:00
src = open ( path_from_root ( ' tests ' , ' fcntl-open ' , ' src.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' fcntl-open ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run , extra_emscripten_args = [ ' -H ' , ' libc/fcntl.h ' ] )
2011-07-20 11:20:09 +04:00
def test_fcntl_misc ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
" FS.createDataFile( ' / ' , ' test ' , ' abcdef ' , true, true); "
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-20 11:20:09 +04:00
src = open ( path_from_root ( ' tests ' , ' fcntl-misc ' , ' src.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' fcntl-misc ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run , extra_emscripten_args = [ ' -H ' , ' libc/fcntl.h ' ] )
2011-07-18 03:19:28 +04:00
2011-07-21 05:08:42 +04:00
def test_poll ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
\' \' \'
FS . createDataFile ( ' / ' , ' file ' , ' abcdef ' , true , true ) ;
FS . createDevice ( ' / ' , ' device ' , function ( ) { } , function ( ) { } ) ;
\' \' \'
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-21 05:08:42 +04:00
src = r '''
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
int main ( ) {
struct pollfd multi [ 5 ] ;
multi [ 0 ] . fd = open ( " /file " , O_RDONLY , 0777 ) ;
multi [ 1 ] . fd = open ( " /device " , O_RDONLY , 0777 ) ;
multi [ 2 ] . fd = 123 ;
multi [ 3 ] . fd = open ( " /file " , O_RDONLY , 0777 ) ;
multi [ 4 ] . fd = open ( " /file " , O_RDONLY , 0777 ) ;
multi [ 0 ] . events = POLLIN | POLLOUT | POLLNVAL | POLLERR ;
multi [ 1 ] . events = POLLIN | POLLOUT | POLLNVAL | POLLERR ;
multi [ 2 ] . events = POLLIN | POLLOUT | POLLNVAL | POLLERR ;
multi [ 3 ] . events = 0x00 ;
multi [ 4 ] . events = POLLOUT | POLLNVAL | POLLERR ;
printf ( " ret: %d \n " , poll ( multi , 5 , 123 ) ) ;
printf ( " errno: %d \n " , errno ) ;
2011-10-02 23:48:08 +04:00
printf ( " multi[0].revents: %d \n " , multi [ 0 ] . revents == ( POLLIN | POLLOUT ) ) ;
printf ( " multi[1].revents: %d \n " , multi [ 1 ] . revents == ( POLLIN | POLLOUT ) ) ;
printf ( " multi[2].revents: %d \n " , multi [ 2 ] . revents == POLLNVAL ) ;
printf ( " multi[3].revents: %d \n " , multi [ 3 ] . revents == 0 ) ;
printf ( " multi[4].revents: %d \n " , multi [ 4 ] . revents == POLLOUT ) ;
2011-07-21 05:08:42 +04:00
return 0 ;
}
'''
expected = r '''
ret : 4
errno : 0
2011-10-02 23:48:08 +04:00
multi [ 0 ] . revents : 1
multi [ 1 ] . revents : 1
multi [ 2 ] . revents : 1
multi [ 3 ] . revents : 1
multi [ 4 ] . revents : 1
2011-07-21 05:08:42 +04:00
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( ' (^| \n ) \ s+ ' , ' \\ 1 ' , expected ) , post_build = add_pre_run , extra_emscripten_args = [ ' -H ' , ' libc/fcntl.h,poll.h ' ] )
2011-07-21 05:08:42 +04:00
2011-07-19 22:55:58 +04:00
def test_statvfs ( self ) :
src = r '''
#include <stdio.h>
#include <errno.h>
#include <sys/statvfs.h>
int main ( ) {
struct statvfs s ;
printf ( " result: %d \n " , statvfs ( " /test " , & s ) ) ;
printf ( " errno: %d \n " , errno ) ;
printf ( " f_bsize: %lu \n " , s . f_bsize ) ;
printf ( " f_frsize: %lu \n " , s . f_frsize ) ;
printf ( " f_blocks: %lu \n " , s . f_blocks ) ;
printf ( " f_bfree: %lu \n " , s . f_bfree ) ;
printf ( " f_bavail: %lu \n " , s . f_bavail ) ;
printf ( " f_files: %lu \n " , s . f_files ) ;
printf ( " f_ffree: %lu \n " , s . f_ffree ) ;
printf ( " f_favail: %lu \n " , s . f_favail ) ;
printf ( " f_fsid: %lu \n " , s . f_fsid ) ;
printf ( " f_flag: %lu \n " , s . f_flag ) ;
printf ( " f_namemax: %lu \n " , s . f_namemax ) ;
return 0 ;
}
'''
expected = r '''
result : 0
errno : 0
f_bsize : 4096
f_frsize : 4096
f_blocks : 1000000
f_bfree : 500000
f_bavail : 500000
2012-02-06 05:36:08 +04:00
f_files : 10
2011-07-19 22:55:58 +04:00
f_ffree : 1000000
f_favail : 1000000
f_fsid : 42
f_flag : 2
f_namemax : 255
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( ' (^| \n ) \ s+ ' , ' \\ 1 ' , expected ) )
2011-07-19 22:55:58 +04:00
2011-07-16 15:09:00 +04:00
def test_libgen ( self ) :
src = r '''
#include <stdio.h>
#include <libgen.h>
int main ( ) {
char p1 [ 16 ] = " /usr/lib " , p1x [ 16 ] = " /usr/lib " ;
printf ( " %s -> " , p1 ) ;
printf ( " %s : %s \n " , dirname ( p1x ) , basename ( p1 ) ) ;
char p2 [ 16 ] = " /usr " , p2x [ 16 ] = " /usr " ;
printf ( " %s -> " , p2 ) ;
printf ( " %s : %s \n " , dirname ( p2x ) , basename ( p2 ) ) ;
char p3 [ 16 ] = " /usr/ " , p3x [ 16 ] = " /usr/ " ;
printf ( " %s -> " , p3 ) ;
printf ( " %s : %s \n " , dirname ( p3x ) , basename ( p3 ) ) ;
char p4 [ 16 ] = " /usr/lib/// " , p4x [ 16 ] = " /usr/lib/// " ;
printf ( " %s -> " , p4 ) ;
printf ( " %s : %s \n " , dirname ( p4x ) , basename ( p4 ) ) ;
char p5 [ 16 ] = " / " , p5x [ 16 ] = " / " ;
printf ( " %s -> " , p5 ) ;
printf ( " %s : %s \n " , dirname ( p5x ) , basename ( p5 ) ) ;
char p6 [ 16 ] = " /// " , p6x [ 16 ] = " /// " ;
printf ( " %s -> " , p6 ) ;
printf ( " %s : %s \n " , dirname ( p6x ) , basename ( p6 ) ) ;
char p7 [ 16 ] = " /usr/../lib/.. " , p7x [ 16 ] = " /usr/../lib/.. " ;
printf ( " %s -> " , p7 ) ;
printf ( " %s : %s \n " , dirname ( p7x ) , basename ( p7 ) ) ;
char p8 [ 16 ] = " " , p8x [ 16 ] = " " ;
printf ( " (empty) -> %s : %s \n " , dirname ( p8x ) , basename ( p8 ) ) ;
printf ( " (null) -> %s : %s \n " , dirname ( 0 ) , basename ( 0 ) ) ;
return 0 ;
}
'''
expected = '''
/ usr / lib - > / usr : lib
/ usr - > / : usr
/ usr / - > / : usr
/ usr / lib / / / - > / usr : lib
/ - > / : /
/ / / - > / : /
/ usr / . . / lib / . . - > / usr / . . / lib : . .
( empty ) - > . : .
( null ) - > . : .
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( ' (^| \n ) \ s+ ' , ' \\ 1 ' , expected ) )
2011-07-16 15:09:00 +04:00
2011-07-16 16:01:43 +04:00
def test_utime ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run_and_checks = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
\' \' \'
var TEST_F1 = FS . createFolder ( ' / ' , ' writeable ' , true , true ) ;
var TEST_F2 = FS . createFolder ( ' / ' , ' unwriteable ' , true , false ) ;
\' \' \'
) . replace (
' // {{ POST_RUN_ADDITIONS}} ' ,
\' \' \'
print ( ' first changed: ' + ( TEST_F1 . timestamp == 1200000000000 ) ) ;
print ( ' second changed: ' + ( TEST_F2 . timestamp == 1200000000000 ) ) ;
\' \' \'
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-16 16:01:43 +04:00
src = r '''
#include <stdio.h>
#include <errno.h>
#include <utime.h>
int main ( ) {
struct utimbuf t = { 1000000000 , 1200000000 } ;
char * writeable = " /writeable " ;
char * unwriteable = " /unwriteable " ;
utime ( writeable , & t ) ;
printf ( " writeable errno: %d \n " , errno ) ;
utime ( unwriteable , & t ) ;
printf ( " unwriteable errno: %d \n " , errno ) ;
return 0 ;
}
'''
expected = '''
writeable errno : 0
unwriteable errno : 1
first changed : true
second changed : false
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( ' (^| \n ) \ s+ ' , ' \\ 1 ' , expected ) , post_build = add_pre_run_and_checks )
2011-07-16 16:01:43 +04:00
2012-01-30 01:04:55 +04:00
def test_direct_string_constant_usage ( self ) :
2012-01-30 23:52:12 +04:00
if self . emcc_args is None : return self . skip ( ' requires libcxx ' )
2012-01-30 01:04:55 +04:00
src = '''
2012-01-30 23:52:12 +04:00
#include <iostream>
template < int i >
void printText ( const char ( & text ) [ i ] )
{
std : : cout << text ;
}
int main ( )
{
printText ( " some string constant " ) ;
return 0 ;
}
'''
2012-01-30 01:04:55 +04:00
self . do_run ( src , " some string constant " )
2011-07-22 22:36:14 +04:00
def test_fs_base ( self ) :
2011-10-21 23:08:44 +04:00
Settings . INCLUDE_FULL_LIBRARY = 1
2011-07-23 07:33:14 +04:00
try :
2011-12-21 09:15:48 +04:00
addJS = '''
def process ( filename ) :
2011-12-21 09:42:12 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace ( ' FS.init(); ' , ' ' ) . replace ( # Disable normal initialization, replace with ours
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-21 09:42:12 +04:00
open ( shared . path_from_root ( ' tests ' , ' filesystem ' , ' src.js ' ) , ' r ' ) . read ( ) )
2011-12-21 09:15:48 +04:00
open ( filename , ' w ' ) . write ( src )
'''
2011-07-23 07:33:14 +04:00
src = ' int main() { return 0;} \n '
expected = open ( path_from_root ( ' tests ' , ' filesystem ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = addJS , extra_emscripten_args = [ ' -H ' , ' libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h ' ] )
2011-07-23 07:33:14 +04:00
finally :
2011-10-21 23:30:08 +04:00
Settings . INCLUDE_FULL_LIBRARY = 0
2011-07-22 22:36:14 +04:00
2011-07-23 06:49:48 +04:00
def test_unistd_access ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
2011-12-22 02:13:35 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-22 02:13:35 +04:00
open ( shared . path_from_root ( ' tests ' , ' unistd ' , ' access.js ' ) , ' r ' ) . read ( )
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-23 06:49:48 +04:00
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' access.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' access.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run )
2011-07-23 06:49:48 +04:00
def test_unistd_curdir ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
2011-12-22 02:13:35 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-22 02:13:35 +04:00
open ( shared . path_from_root ( ' tests ' , ' unistd ' , ' curdir.js ' ) , ' r ' ) . read ( )
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-23 06:49:48 +04:00
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' curdir.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' curdir.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run )
2011-07-23 06:49:48 +04:00
def test_unistd_close ( self ) :
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' close.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' close.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-23 06:49:48 +04:00
def test_unistd_confstr ( self ) :
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' confstr.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' confstr.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , extra_emscripten_args = [ ' -H ' , ' libc/unistd.h ' ] )
2011-07-23 06:49:48 +04:00
def test_unistd_ttyname ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
2011-12-22 02:13:35 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-22 02:13:35 +04:00
open ( shared . path_from_root ( ' tests ' , ' unistd ' , ' ttyname.js ' ) , ' r ' ) . read ( )
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-23 06:49:48 +04:00
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' ttyname.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' ttyname.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run )
2011-07-23 06:49:48 +04:00
def test_unistd_dup ( self ) :
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' dup.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' dup.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-23 06:49:48 +04:00
def test_unistd_pathconf ( self ) :
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' pathconf.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' pathconf.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-23 06:49:48 +04:00
def test_unistd_truncate ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
2011-12-22 02:13:35 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-22 02:13:35 +04:00
open ( shared . path_from_root ( ' tests ' , ' unistd ' , ' truncate.js ' ) , ' r ' ) . read ( )
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-23 06:49:48 +04:00
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' truncate.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' truncate.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run )
2011-07-23 06:49:48 +04:00
def test_unistd_swab ( self ) :
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' swab.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' swab.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-23 06:49:48 +04:00
def test_unistd_isatty ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
2011-12-22 02:13:35 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-22 02:13:35 +04:00
open ( shared . path_from_root ( ' tests ' , ' unistd ' , ' isatty.js ' ) , ' r ' ) . read ( )
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-23 06:49:48 +04:00
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' isatty.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' isatty.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run )
2011-07-23 06:49:48 +04:00
def test_unistd_sysconf ( self ) :
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' sysconf.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' sysconf.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-23 06:49:48 +04:00
def test_unistd_login ( self ) :
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' login.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' login.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-23 06:49:48 +04:00
def test_unistd_unlink ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
2011-12-22 02:13:35 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-22 02:13:35 +04:00
open ( shared . path_from_root ( ' tests ' , ' unistd ' , ' unlink.js ' ) , ' r ' ) . read ( )
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-23 06:49:48 +04:00
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' unlink.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' unlink.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run )
2011-07-23 06:49:48 +04:00
def test_unistd_links ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
2011-12-22 02:13:35 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-22 02:13:35 +04:00
open ( shared . path_from_root ( ' tests ' , ' unistd ' , ' links.js ' ) , ' r ' ) . read ( )
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-23 06:49:48 +04:00
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' links.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' links.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run )
2011-07-23 06:49:48 +04:00
def test_unistd_sleep ( self ) :
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' sleep.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' sleep.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-23 06:49:48 +04:00
def test_unistd_io ( self ) :
2011-12-21 09:15:48 +04:00
add_pre_run = '''
def process ( filename ) :
2011-12-22 02:13:35 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2011-12-22 02:13:35 +04:00
open ( shared . path_from_root ( ' tests ' , ' unistd ' , ' io.js ' ) , ' r ' ) . read ( )
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-07-23 06:49:48 +04:00
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' io.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' io.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected , post_build = add_pre_run )
2011-07-23 06:49:48 +04:00
def test_unistd_misc ( self ) :
src = open ( path_from_root ( ' tests ' , ' unistd ' , ' misc.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' unistd ' , ' misc.out ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-23 06:49:48 +04:00
2011-07-29 15:23:37 +04:00
def test_uname ( self ) :
src = r '''
#include <stdio.h>
#include <sys/utsname.h>
int main ( ) {
struct utsname u ;
printf ( " ret: %d \n " , uname ( & u ) ) ;
printf ( " sysname: %s \n " , u . sysname ) ;
printf ( " nodename: %s \n " , u . nodename ) ;
printf ( " release: %s \n " , u . release ) ;
printf ( " version: %s \n " , u . version ) ;
printf ( " machine: %s \n " , u . machine ) ;
printf ( " invalid: %d \n " , uname ( 0 ) ) ;
return 0 ;
}
'''
expected = '''
ret : 0
sysname : Emscripten
nodename : emscripten
release : 1.0
version : #1
machine : x86 - JS
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( ' (^| \n ) \ s+ ' , ' \\ 1 ' , expected ) )
2011-07-29 15:23:37 +04:00
2011-07-29 23:32:29 +04:00
def test_env ( self ) :
src = open ( path_from_root ( ' tests ' , ' env ' , ' src.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' env ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-29 23:32:29 +04:00
2012-01-31 05:21:04 +04:00
def test_systypes ( self ) :
src = open ( path_from_root ( ' tests ' , ' systypes ' , ' src.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' systypes ' , ' output.txt ' ) , ' r ' ) . read ( )
self . do_run ( src , expected )
2011-07-30 17:13:42 +04:00
def test_getloadavg ( self ) :
src = r '''
#include <stdio.h>
#include <stdlib.h>
int main ( ) {
double load [ 5 ] = { 42.13 , 42.13 , 42.13 , 42.13 , 42.13 } ;
printf ( " ret: %d \n " , getloadavg ( load , 5 ) ) ;
2011-07-31 19:15:43 +04:00
printf ( " load[0]: %.3lf \n " , load [ 0 ] ) ;
printf ( " load[1]: %.3lf \n " , load [ 1 ] ) ;
printf ( " load[2]: %.3lf \n " , load [ 2 ] ) ;
printf ( " load[3]: %.3lf \n " , load [ 3 ] ) ;
printf ( " load[4]: %.3lf \n " , load [ 4 ] ) ;
2011-07-30 17:13:42 +04:00
return 0 ;
}
'''
expected = '''
ret : 3
2011-07-31 19:15:43 +04:00
load [ 0 ] : 0.100
load [ 1 ] : 0.100
load [ 2 ] : 0.100
load [ 3 ] : 42.130
load [ 4 ] : 42.130
2011-07-30 17:13:42 +04:00
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , re . sub ( ' (^| \n ) \ s+ ' , ' \\ 1 ' , expected ) )
2011-07-30 17:13:42 +04:00
2012-01-27 09:04:21 +04:00
def test_inet ( self ) :
src = r '''
#include <stdio.h>
#include <arpa/inet.h>
int main ( ) {
printf ( " * %x , %x , %x , %x * \n " , htonl ( 0x12345678 ) , htons ( 0xabcd ) , ntohl ( 0x43211234 ) , ntohs ( 0xbeaf ) ) ;
return 0 ;
}
'''
self . do_run ( src , ' *78563412,cdab,34122143,afbe* ' )
2011-07-30 17:12:36 +04:00
def test_ctype ( self ) :
2011-07-31 05:44:26 +04:00
# The bit fiddling done by the macros using __ctype_b_loc requires this.
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 1
2011-07-30 17:12:36 +04:00
src = open ( path_from_root ( ' tests ' , ' ctype ' , ' src.c ' ) , ' r ' ) . read ( )
expected = open ( path_from_root ( ' tests ' , ' ctype ' , ' output.txt ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , expected )
2011-07-31 05:44:26 +04:00
CORRECT_SIGNS = 0
2011-07-30 17:12:36 +04:00
2012-01-18 02:52:05 +04:00
def test_atomic ( self ) :
2012-01-17 09:12:48 +04:00
src = '''
2012-01-18 02:52:05 +04:00
#include <stdio.h>
int main ( ) {
int x = 10 ;
int y = __sync_add_and_fetch ( & x , 5 ) ;
printf ( " * %d , %d * \\ n " , x , y ) ;
x = 10 ;
y = __sync_fetch_and_add ( & x , 5 ) ;
printf ( " * %d , %d * \\ n " , x , y ) ;
x = 10 ;
y = __sync_lock_test_and_set ( & x , 6 ) ;
printf ( " * %d , %d * \\ n " , x , y ) ;
x = 10 ;
y = __sync_bool_compare_and_swap ( & x , 9 , 7 ) ;
printf ( " * %d , %d * \\ n " , x , y ) ;
y = __sync_bool_compare_and_swap ( & x , 10 , 7 ) ;
printf ( " * %d , %d * \\ n " , x , y ) ;
return 0 ;
}
'''
2012-01-17 09:12:48 +04:00
2012-01-18 02:52:05 +04:00
self . do_run ( src , ' *15,15* \n *15,10* \n *6,10* \n *10,0* \n *7,1* ' )
2012-01-17 09:12:48 +04:00
2011-10-30 00:10:22 +04:00
# libc++ tests
2011-10-18 02:23:40 +04:00
def test_iostream ( self ) :
2012-01-22 02:01:42 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( " we don ' t support libcxx in q1 " )
if self . emcc_args is None :
2012-01-22 02:12:52 +04:00
if Building . LLVM_OPTS : return self . skip ( ' optimizing bitcode before emcc can confuse libcxx inclusion ' )
2012-01-22 02:01:42 +04:00
self . emcc_args = [ ] # libc++ auto-inclusion is only done if we use emcc
2012-02-02 03:23:49 +04:00
Settings . SAFE_HEAP = 0 # Some spurious warnings from libc++ internals
2012-01-21 22:09:19 +04:00
2011-10-18 02:23:40 +04:00
src = '''
#include <iostream>
int main ( )
{
2011-12-17 23:00:58 +04:00
std : : cout << " hello world " << std : : endl << 77 << " . " << std : : endl ;
2011-10-18 02:23:40 +04:00
return 0 ;
}
'''
2012-01-18 05:11:26 +04:00
# FIXME: should not have so many newlines in output here
2012-01-19 09:23:36 +04:00
self . do_run ( src , ' hello world \n \n 77. \n ' )
2011-10-18 02:23:40 +04:00
2011-10-30 00:10:22 +04:00
def test_stdvec ( self ) :
src = '''
#include <vector>
#include <stdio.h>
struct S {
int a ;
float b ;
} ;
void foo ( int a , float b )
{
printf ( " %d : %.2f \\ n " , a , b ) ;
}
int main ( int argc , char * argv [ ] )
{
std : : vector < S > ar ;
S s ;
s . a = 789 ;
s . b = 123.456 f ;
ar . push_back ( s ) ;
s . a = 0 ;
s . b = 100.1 f ;
ar . push_back ( s ) ;
foo ( ar [ 0 ] . a , ar [ 0 ] . b ) ;
foo ( ar [ 1 ] . a , ar [ 1 ] . b ) ;
}
'''
self . do_run ( src , ' 789:123.46 \n 0:100.1 ' )
2011-11-13 02:32:22 +04:00
### 'Medium' tests
2010-11-06 06:48:19 +03:00
2010-08-26 08:01:10 +04:00
def test_fannkuch ( self ) :
results = [ ( 1 , 0 ) , ( 2 , 1 ) , ( 3 , 2 ) , ( 4 , 4 ) , ( 5 , 7 ) , ( 6 , 10 ) , ( 7 , 16 ) , ( 8 , 22 ) ]
for i , j in results :
2011-01-15 09:44:52 +03:00
src = open ( path_from_root ( ' tests ' , ' fannkuch.cpp ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' Pfannkuchen( %d ) = %d . ' % ( i , j ) , [ str ( i ) ] , no_build = i > 1 )
2010-08-26 08:01:10 +04:00
2010-09-26 08:25:47 +04:00
def test_raytrace ( self ) :
2011-12-07 02:32:44 +04:00
if Settings . USE_TYPED_ARRAYS == 2 : return self . skip ( ' Relies on double value rounding, extremely sensitive ' )
2011-06-06 18:40:27 +04:00
2011-11-12 02:05:16 +04:00
src = open ( path_from_root ( ' tests ' , ' raytrace.cpp ' ) , ' r ' ) . read ( ) . replace ( ' double ' , ' float ' )
2011-01-15 09:44:52 +03:00
output = open ( path_from_root ( ' tests ' , ' raytrace.ppm ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , output , [ ' 3 ' , ' 16 ' ] ) #, build_ll_hook=self.do_autodebug)
2010-09-23 06:31:37 +04:00
2010-08-28 08:16:06 +04:00
def test_fasta ( self ) :
2010-09-24 07:21:03 +04:00
results = [ ( 1 , ''' GG*ctt**tgagc* ''' ) , ( 20 , ''' GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT*cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg**tacgtgtagcctagtgtttgtgttgcgttatagtctatttgtggacacagtatggtcaaa**tgacgtcttttgatctgacggcgttaacaaagatactctg* ''' ) ,
( 50 , ''' GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA*TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT*cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg**tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa**NtactMcSMtYtcMgRtacttctWBacgaa**agatactctgggcaacacacatacttctctcatgttgtttcttcggacctttcataacct**ttcctggcacatggttagctgcacatcacaggattgtaagggtctagtggttcagtgagc**ggaatatcattcgtcggtggtgttaatctatctcggtgtagcttataaatgcatccgtaa**gaatattatgtttatttgtcggtacgttcatggtagtggtgtcgccgatttagacgtaaa**ggcatgtatg* ''' ) ]
2010-08-26 08:01:10 +04:00
for i , j in results :
2011-01-15 09:44:52 +03:00
src = open ( path_from_root ( ' tests ' , ' fasta.cpp ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , j , [ str ( i ) ] , lambda x : x . replace ( ' \n ' , ' * ' ) , no_build = i > 1 )
2010-08-26 08:01:10 +04:00
2011-06-11 21:32:16 +04:00
def test_dlmalloc ( self ) :
2012-01-21 22:09:19 +04:00
if self . emcc_args is None : self . emcc_args = [ ] # dlmalloc auto-inclusion is only done if we use emcc
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 2
Settings . CORRECT_SIGNS_LINES = [ ' src.cpp: ' + str ( i + 4 ) for i in [ 4816 , 4191 , 4246 , 4199 , 4205 , 4235 , 4227 ] ]
Settings . TOTAL_MEMORY = 100 * 1024 * 1024 # needed with typed arrays
2011-06-11 21:32:16 +04:00
2012-01-19 07:39:01 +04:00
src = open ( path_from_root ( ' system ' , ' lib ' , ' dlmalloc.c ' ) , ' r ' ) . read ( ) + ' \n \n \n ' + open ( path_from_root ( ' tests ' , ' dlmalloc_test.c ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *1,0* ' , [ ' 200 ' , ' 1 ' ] )
self . do_run ( src , ' *400,0* ' , [ ' 400 ' , ' 400 ' ] , no_build = True )
2011-06-11 21:32:16 +04:00
2011-10-09 00:28:01 +04:00
# Linked version
src = open ( path_from_root ( ' tests ' , ' dlmalloc_test.c ' ) , ' r ' ) . read ( )
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *1,0* ' , [ ' 200 ' , ' 1 ' ] , extra_emscripten_args = [ ' -m ' ] )
self . do_run ( src , ' *400,0* ' , [ ' 400 ' , ' 400 ' ] , extra_emscripten_args = [ ' -m ' ] , no_build = True )
2011-10-09 00:28:01 +04:00
2011-12-21 04:38:14 +04:00
if self . emcc_args == [ ] : # TODO: do this in other passes too, passing their opts into emcc
2011-12-17 00:36:12 +04:00
# 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 ' ) )
2011-12-17 05:46:05 +04:00
output = Popen ( [ EMCC , path_from_root ( ' tests ' , ' dlmalloc_test.c ' ) ,
2012-01-03 07:21:57 +04:00
' -o ' , os . path . join ( self . get_dir ( ) , ' src.cpp.o.js ' ) ] , stdout = PIPE , stderr = self . stderr_redirect ) . communicate ( )
2011-12-17 00:36:12 +04:00
self . do_run ( ' x ' , ' *1,0* ' , [ ' 200 ' , ' 1 ' ] , no_build = True )
self . do_run ( ' x ' , ' *400,0* ' , [ ' 400 ' , ' 400 ' ] , no_build = True )
2012-01-08 06:01:09 +04:00
# The same for new and all its variants
src = open ( path_from_root ( ' tests ' , ' new.cpp ' ) ) . read ( )
for new , delete in [
( ' malloc(100) ' , ' free ' ) ,
( ' new char[100] ' , ' delete[] ' ) ,
( ' new Structy ' , ' delete ' ) ,
( ' new int ' , ' delete ' ) ,
( ' new Structy[10] ' , ' delete[] ' ) ,
] :
self . do_run ( src . replace ( ' {{ { NEW }}} ' , new ) . replace ( ' {{ { DELETE }}} ' , delete ) , ' *1,0* ' )
2011-01-18 02:36:26 +03:00
def test_libcxx ( self ) :
2012-01-19 22:14:11 +04:00
self . do_run ( open ( path_from_root ( ' tests ' , ' hashtest.cpp ' ) ) . read ( ) ,
' june -> 30 \n Previous (in alphabetical order) is july \n Next (in alphabetical order) is march ' )
2011-01-17 10:22:57 +03:00
2011-10-13 18:40:29 +04:00
self . do_run ( '''
2011-03-13 22:13:21 +03:00
#include <set>
#include <stdio.h>
int main ( ) {
std : : set < int > * fetchOriginatorNums = new std : : set < int > ( ) ;
fetchOriginatorNums - > insert ( 171 ) ;
printf ( " hello world \\ n " ) ;
return 1 ;
}
2012-01-19 22:14:11 +04:00
''' , ' hello world ' );
2012-01-07 01:26:24 +04:00
def test_static_variable ( self ) :
2012-01-24 08:22:07 +04:00
if self . emcc_args is None : Settings . SAFE_HEAP = 0 # LLVM mixes i64 and i8 in the guard check
2012-01-07 01:26:24 +04:00
src = '''
#include <stdio.h>
struct DATA
{
int value ;
DATA ( )
{
value = 0 ;
}
} ;
DATA & GetData ( )
{
static DATA data ;
return data ;
}
int main ( )
{
GetData ( ) . value = 10 ;
printf ( " value: %i " , GetData ( ) . value ) ;
}
'''
self . do_run ( src , ' value:10 ' )
2012-01-18 23:25:57 +04:00
def test_mmap ( self ) :
src = '''
2012-01-19 00:05:45 +04:00
#include <stdio.h>
2012-01-18 23:25:57 +04:00
#include <sys/mman.h>
#include <assert.h>
int main ( int argc , char * argv [ ] ) {
const int NUM_BYTES = 8 * 1024 * 1024 ;
const int NUM_INTS = NUM_BYTES / sizeof ( int ) ;
int * map = ( int * ) mmap ( 0 , NUM_BYTES , PROT_READ | PROT_WRITE ,
MAP_SHARED | MAP_ANON , - 1 , 0 ) ;
assert ( map != MAP_FAILED ) ;
int i ;
for ( i = 0 ; i < NUM_INTS ; i + + ) {
map [ i ] = i ;
}
for ( i = 0 ; i < NUM_INTS ; i + + ) {
assert ( map [ i ] == i ) ;
}
assert ( munmap ( map , NUM_BYTES ) == 0 ) ;
2012-01-19 00:05:45 +04:00
printf ( " hello,world " ) ;
2012-01-18 23:25:57 +04:00
return 0 ;
}
'''
2012-01-19 00:05:45 +04:00
self . do_run ( src , ' hello,world ' )
self . do_run ( src , ' hello,world ' , force_c = True )
2011-03-13 22:13:21 +03:00
2010-11-14 01:45:22 +03:00
def test_cubescript ( self ) :
2011-12-22 06:15:26 +04:00
if self . emcc_args is not None and ' -O2 ' in self . emcc_args :
self . emcc_args + = [ ' --closure ' , ' 1 ' ] # Use closure here for some additional coverage
2011-07-30 07:09:49 +04:00
2011-12-22 06:15:26 +04:00
Building . COMPILER_TEST_OPTS = [ ] # remove -g, so we have one test without it by default
2012-01-24 08:22:07 +04:00
if self . emcc_args is None : Settings . SAFE_HEAP = 0 # Has some actual loads of unwritten-to places, in the C++ code...
2011-01-02 03:56:22 +03:00
# Overflows happen in hash loop
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 1
Settings . CHECK_OVERFLOWS = 0
2010-11-22 04:43:22 +03:00
2011-11-12 08:39:57 +04:00
if Settings . USE_TYPED_ARRAYS == 2 :
Settings . CORRECT_SIGNS = 1
2011-10-13 18:40:29 +04:00
self . do_run ( path_from_root ( ' tests ' , ' cubescript ' ) , ' * \n Temp is 33 \n 9 \n 5 \n hello, everyone \n * ' , main_file = ' command.cpp ' )
2010-08-30 02:30:49 +04:00
2010-10-21 23:13:26 +04:00
def test_gcc_unmangler ( self ) :
2011-10-13 18:40:29 +04:00
self . do_run ( path_from_root ( ' third_party ' ) , ' *d_demangle(char const*, int, unsigned int*)* ' , args = [ ' _ZL10d_demanglePKciPj ' ] , main_file = ' gcc_demangler.c ' )
2010-10-21 09:56:12 +04:00
2010-12-19 02:55:21 +03:00
#### Code snippet that is helpful to search for nonportable optimizations ####
#global LLVM_OPT_OPTS
#for opt in ['-aa-eval', '-adce', '-always-inline', '-argpromotion', '-basicaa', '-basiccg', '-block-placement', '-break-crit-edges', '-codegenprepare', '-constmerge', '-constprop', '-correlated-propagation', '-count-aa', '-dce', '-deadargelim', '-deadtypeelim', '-debug-aa', '-die', '-domfrontier', '-domtree', '-dse', '-extract-blocks', '-functionattrs', '-globaldce', '-globalopt', '-globalsmodref-aa', '-gvn', '-indvars', '-inline', '-insert-edge-profiling', '-insert-optimal-edge-profiling', '-instcombine', '-instcount', '-instnamer', '-internalize', '-intervals', '-ipconstprop', '-ipsccp', '-iv-users', '-jump-threading', '-lazy-value-info', '-lcssa', '-lda', '-libcall-aa', '-licm', '-lint', '-live-values', '-loop-deletion', '-loop-extract', '-loop-extract-single', '-loop-index-split', '-loop-reduce', '-loop-rotate', '-loop-unroll', '-loop-unswitch', '-loops', '-loopsimplify', '-loweratomic', '-lowerinvoke', '-lowersetjmp', '-lowerswitch', '-mem2reg', '-memcpyopt', '-memdep', '-mergefunc', '-mergereturn', '-module-debuginfo', '-no-aa', '-no-profile', '-partial-inliner', '-partialspecialization', '-pointertracking', '-postdomfrontier', '-postdomtree', '-preverify', '-prune-eh', '-reassociate', '-reg2mem', '-regions', '-scalar-evolution', '-scalarrepl', '-sccp', '-scev-aa', '-simplify-libcalls', '-simplify-libcalls-halfpowr', '-simplifycfg', '-sink', '-split-geps', '-sretpromotion', '-strip', '-strip-dead-debug-info', '-strip-dead-prototypes', '-strip-debug-declare', '-strip-nondebug', '-tailcallelim', '-tailduplicate', '-targetdata', '-tbaa']:
# LLVM_OPT_OPTS = [opt]
# try:
2011-10-13 18:40:29 +04:00
# self.do_run(path_from_root(['third_party']), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'], main_file='gcc_demangler.c')
2010-12-19 02:55:21 +03:00
# print opt, "ok"
# except:
# print opt, "FAIL"
2010-11-21 07:00:11 +03:00
def test_lua ( self ) :
2011-12-22 04:56:03 +04:00
try :
os . environ [ ' EMCC_LEAVE_INPUTS_RAW ' ] = ' 1 '
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' TODO: make this work ' )
# Overflows in luaS_newlstr hash loop
2012-01-24 08:22:07 +04:00
if self . emcc_args is None : Settings . SAFE_HEAP = 0 # Has various warnings, with copied HEAP_HISTORY values (fixed if we copy 'null' as the type)
2011-12-22 04:56:03 +04:00
Settings . CORRECT_OVERFLOWS = 1
Settings . CHECK_OVERFLOWS = 0
Settings . CORRECT_SIGNS = 1 # Not sure why, but needed
Settings . INIT_STACK = 1 # TODO: Investigate why this is necessary
self . do_ll_run ( path_from_root ( ' tests ' , ' lua ' , ' lua.ll ' ) ,
' hello lua world! \n 17 \n 1 \n 2 \n 3 \n 4 \n 7 ' ,
args = [ ' -e ' , ''' print( " hello lua world! " );print(17);for x = 1,4 do print(x) end;print(10-3) ''' ] ,
output_nicerizer = lambda string : string . replace ( ' \n \n ' , ' \n ' ) . replace ( ' \n \n ' , ' \n ' ) ,
extra_emscripten_args = [ ' -H ' , ' libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h ' ] )
finally :
del os . environ [ ' EMCC_LEAVE_INPUTS_RAW ' ]
2010-11-21 05:38:44 +03:00
2011-10-25 02:20:01 +04:00
def get_build_dir ( self ) :
2011-02-28 03:54:21 +03:00
return os . path . join ( self . get_dir ( ) , ' building ' )
2011-03-16 06:13:57 +03:00
def get_freetype ( self ) :
2011-10-21 23:08:44 +04:00
Settings . INIT_STACK = 1 # TODO: Investigate why this is necessary
2011-04-27 02:44:18 +04:00
2012-01-26 05:52:48 +04:00
return self . get_library ( ' freetype ' , os . path . join ( ' objs ' , ' .libs ' , ' libfreetype.a ' ) )
2011-03-16 06:13:57 +03:00
2011-01-30 08:52:21 +03:00
def test_freetype ( self ) :
2011-10-21 23:08:44 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' TODO: Figure out and try to fix ' )
2011-04-23 00:23:37 +04:00
2011-10-21 23:08:44 +04:00
if Settings . CORRECT_SIGNS == 0 : Settings . CORRECT_SIGNS = 1 # Not sure why, but needed
2011-01-30 08:52:21 +03:00
2011-12-21 09:15:48 +04:00
post = '''
def process ( filename ) :
2011-12-21 09:42:12 +04:00
import tools . shared as shared
2011-12-21 09:15:48 +04:00
# Embed the font into the document
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
" FS.createDataFile( ' / ' , ' font.ttf ' , %s , true, false); " % str (
2011-12-21 09:42:12 +04:00
map ( ord , open ( shared . path_from_root ( ' tests ' , ' freetype ' , ' LiberationSansBold.ttf ' ) , ' rb ' ) . read ( ) )
2011-12-21 09:15:48 +04:00
)
)
open ( filename , ' w ' ) . write ( src )
'''
2011-01-30 08:52:21 +03:00
# Main
2011-10-13 18:40:29 +04:00
self . do_run ( open ( path_from_root ( ' tests ' , ' freetype ' , ' main.c ' ) , ' r ' ) . read ( ) ,
2011-01-30 08:52:21 +03:00
open ( path_from_root ( ' tests ' , ' freetype ' , ' ref.txt ' ) , ' r ' ) . read ( ) ,
2011-02-08 22:21:58 +03:00
[ ' font.ttf ' , ' test! ' , ' 150 ' , ' 120 ' , ' 25 ' ] ,
2011-03-16 06:13:57 +03:00
libraries = [ self . get_freetype ( ) ] ,
2011-01-31 18:43:01 +03:00
includes = [ path_from_root ( ' tests ' , ' freetype ' , ' include ' ) ] ,
2011-04-23 22:05:22 +04:00
post_build = post )
2011-04-22 18:53:31 +04:00
#build_ll_hook=self.do_autodebug)
2011-01-24 05:23:44 +03:00
2011-09-11 07:38:30 +04:00
def test_sqlite ( self ) :
2011-09-15 00:54:42 +04:00
# gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c
2012-01-22 02:24:33 +04:00
if self . emcc_args is None : return self . skip ( ' Very slow without ta2, and we would also need to include dlmalloc manually without emcc ' )
2011-10-21 23:08:44 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' TODO FIXME ' )
2011-09-11 07:38:30 +04:00
2011-11-17 22:16:42 +04:00
pgo_data = read_pgo_data ( path_from_root ( ' tests ' , ' sqlite ' , ' sqlite-autooptimize.fails.txt ' ) )
2011-09-13 21:29:47 +04:00
2011-12-22 02:33:06 +04:00
Settings . CORRECT_SIGNS = 1 # XXX: in default, we fail with 2 here, even though the pgo_data should be correct (and works in s_0_0). Investigate this.
2011-11-17 22:16:42 +04:00
Settings . CORRECT_SIGNS_LINES = pgo_data [ ' signs_lines ' ]
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 0
Settings . CORRECT_ROUNDINGS = 0
2012-01-24 08:22:07 +04:00
if self . emcc_args is None : Settings . SAFE_HEAP = 0 # uses time.h to set random bytes, other stuff
2011-10-21 23:08:44 +04:00
Settings . DISABLE_EXCEPTION_CATCHING = 1
Settings . FAST_MEMORY = 4 * 1024 * 1024
Settings . EXPORTED_FUNCTIONS = [ ' _main ' , ' _sqlite3_open ' , ' _sqlite3_close ' , ' _sqlite3_exec ' , ' _sqlite3_free ' , ' _callback ' ] ;
2011-09-11 07:38:30 +04:00
2011-10-13 18:40:29 +04:00
self . do_run ( r '''
2011-09-11 07:38:30 +04:00
#define SQLITE_DISABLE_LFS
#define LONGDOUBLE_TYPE double
#define SQLITE_INT64_TYPE int
2011-09-12 03:16:10 +04:00
#define SQLITE_THREADSAFE 0
2011-09-11 09:01:22 +04:00
''' + open(path_from_root( ' tests ' , ' sqlite ' , ' sqlite3.c ' ), ' r ' ).read() +
2011-09-12 03:16:10 +04:00
open ( path_from_root ( ' tests ' , ' sqlite ' , ' benchmark.c ' ) , ' r ' ) . read ( ) ,
open ( path_from_root ( ' tests ' , ' sqlite ' , ' benchmark.txt ' ) , ' r ' ) . read ( ) ,
2011-09-11 07:38:30 +04:00
includes = [ path_from_root ( ' tests ' , ' sqlite ' ) ] ,
force_c = True ,
2012-02-06 01:33:20 +04:00
js_engines = [ SPIDERMONKEY_ENGINE ] ) # V8 is slow
2011-09-11 07:38:30 +04:00
2011-02-06 08:01:26 +03:00
def test_zlib ( self ) :
2011-12-22 06:20:53 +04:00
if self . emcc_args is not None and ' -O2 ' in self . emcc_args :
self . emcc_args + = [ ' --closure ' , ' 1 ' ] # Use closure here for some additional coverage
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 1
2011-01-31 18:43:01 +03:00
2011-10-13 18:40:29 +04:00
self . do_run ( open ( path_from_root ( ' tests ' , ' zlib ' , ' example.c ' ) , ' r ' ) . read ( ) ,
2011-01-31 18:43:01 +03:00
open ( path_from_root ( ' tests ' , ' zlib ' , ' ref.txt ' ) , ' r ' ) . read ( ) ,
2012-01-26 05:52:48 +04:00
libraries = [ self . get_library ( ' zlib ' , os . path . join ( ' libz.a ' ) , make_args = [ ' libz.a ' ] ) ] ,
2011-01-31 18:43:01 +03:00
includes = [ path_from_root ( ' tests ' , ' zlib ' ) ] ,
force_c = True )
2011-04-22 18:53:31 +04:00
def test_the_bullet ( self ) : # Called thus so it runs late in the alphabetical cycle... it is long
2012-01-24 08:22:07 +04:00
if Building . LLVM_OPTS and self . emcc_args is None : Settings . SAFE_HEAP = 0 # Optimizations make it so we do not have debug info on the line we need to ignore
2011-04-22 04:55:35 +04:00
2011-12-05 06:51:43 +04:00
# Note: this is also a good test of per-file and per-line changes (since we have multiple files, and correct specific lines)
2011-10-21 23:08:44 +04:00
if Settings . SAFE_HEAP :
2011-04-22 04:55:35 +04:00
# Ignore bitfield warnings
2011-10-21 23:08:44 +04:00
Settings . SAFE_HEAP = 3
Settings . SAFE_HEAP_LINES = [ ' btVoronoiSimplexSolver.h:40 ' , ' btVoronoiSimplexSolver.h:41 ' ,
' btVoronoiSimplexSolver.h:42 ' , ' btVoronoiSimplexSolver.h:43 ' ]
2011-04-22 04:55:35 +04:00
2011-10-13 18:40:29 +04:00
self . do_run ( open ( path_from_root ( ' tests ' , ' bullet ' , ' Demos ' , ' HelloWorld ' , ' HelloWorld.cpp ' ) , ' r ' ) . read ( ) ,
2011-12-08 03:36:35 +04:00
[ open ( path_from_root ( ' tests ' , ' bullet ' , ' output.txt ' ) , ' r ' ) . read ( ) , # different roundings
open ( path_from_root ( ' tests ' , ' bullet ' , ' output2.txt ' ) , ' r ' ) . read ( ) ] ,
2012-01-26 05:52:48 +04:00
libraries = [ self . get_library ( ' bullet ' , [ os . path . join ( ' src ' , ' .libs ' , ' libBulletCollision.a ' ) ,
os . path . join ( ' src ' , ' .libs ' , ' libBulletDynamics.a ' ) ,
os . path . join ( ' src ' , ' .libs ' , ' libLinearMath.a ' ) ] ,
2011-04-22 04:55:35 +04:00
configure_args = [ ' --disable-demos ' , ' --disable-dependency-tracking ' ] ) ] ,
2011-05-25 19:28:12 +04:00
includes = [ path_from_root ( ' tests ' , ' bullet ' , ' src ' ) ] ,
js_engines = [ SPIDERMONKEY_ENGINE ] ) # V8 issue 1407
2011-04-22 04:55:35 +04:00
2011-03-17 03:19:57 +03:00
def test_poppler ( self ) :
2012-01-30 07:39:34 +04:00
if self . emcc_args is None : return self . skip ( ' very slow, we only do this in emcc runs ' )
2011-03-22 05:50:03 +03:00
2011-12-09 23:14:33 +04:00
Settings . CORRECT_OVERFLOWS = 1
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 1
2011-03-22 05:50:03 +03:00
2011-10-27 07:41:51 +04:00
Building . COMPILER_TEST_OPTS + = [
2011-10-08 07:56:26 +04:00
' -I ' + path_from_root ( ' tests ' , ' freetype ' , ' include ' ) ,
' -I ' + path_from_root ( ' tests ' , ' poppler ' , ' include ' ) ,
]
2011-03-13 00:37:44 +03:00
2011-10-21 23:08:44 +04:00
Settings . INVOKE_RUN = 0 # We append code that does run() ourselves
2011-03-17 01:31:12 +03:00
2011-03-16 06:13:57 +03:00
# See post(), below
input_file = open ( os . path . join ( self . get_dir ( ) , ' paper.pdf.js ' ) , ' w ' )
input_file . write ( str ( map ( ord , open ( path_from_root ( ' tests ' , ' poppler ' , ' paper.pdf ' ) , ' rb ' ) . read ( ) ) ) )
input_file . close ( )
2011-12-21 09:15:48 +04:00
post = '''
def process ( filename ) :
# To avoid loading this large file to memory and altering it, we simply append to the end
src = open ( filename , ' a ' )
src . write (
\' \' \'
FS . createDataFile ( ' / ' , ' paper.pdf ' , eval ( read ( ' paper.pdf.js ' ) ) , true , false ) ;
run ( ) ;
print ( " Data: " + JSON . stringify ( FS . root . contents [ ' filename-1.ppm ' ] . contents . map ( function ( x ) { return unSign ( x , 8 ) } ) ) ) ;
\' \' \'
)
src . close ( )
'''
2011-03-13 00:37:44 +03:00
2011-10-27 07:16:22 +04:00
#fontconfig = self.get_library('fontconfig', [os.path.join('src', '.libs', 'libfontconfig.a')]) # Used in file, but not needed, mostly
2011-03-13 22:13:21 +03:00
2011-03-16 06:13:57 +03:00
freetype = self . get_freetype ( )
2011-10-27 07:16:22 +04:00
poppler = self . get_library ( ' poppler ' ,
2012-01-31 21:14:33 +04:00
[ os . path . join ( ' poppler ' , ' .libs ' , self . get_shared_library_name ( ' libpoppler.so.13 ' ) ) ,
2011-03-13 22:13:21 +03:00
os . path . join ( ' utils ' , ' pdftoppm.o ' ) ,
os . path . join ( ' utils ' , ' parseargs.o ' ) ] ,
2011-07-28 14:49:53 +04:00
configure_args = [ ' --disable-libjpeg ' , ' --disable-libpng ' , ' --disable-poppler-qt ' , ' --disable-poppler-qt4 ' , ' --disable-cms ' ] )
2011-03-13 22:13:21 +03:00
# Combine libraries
2012-02-02 03:23:49 +04:00
combined = os . path . join ( self . get_dir ( ) , ' poppler-combined.bc ' )
2011-10-27 07:16:22 +04:00
Building . link ( [ freetype , poppler ] , combined )
2011-03-13 22:13:21 +03:00
2011-10-13 18:40:29 +04:00
self . do_ll_run ( combined ,
2011-12-09 22:30:52 +04:00
map ( ord , open ( path_from_root ( ' tests ' , ' poppler ' , ' ref.ppm ' ) , ' r ' ) . read ( ) ) . __str__ ( ) . replace ( ' ' , ' ' ) ,
2011-12-09 02:02:09 +04:00
args = ' -scale-to 512 paper.pdf filename ' . split ( ' ' ) ,
post_build = post )
#, build_ll_hook=self.do_autodebug)
2011-03-13 00:37:44 +03:00
2011-02-28 03:55:53 +03:00
def test_openjpeg ( self ) :
2011-10-21 23:08:44 +04:00
if Settings . USE_TYPED_ARRAYS == 2 :
Settings . CORRECT_SIGNS = 1
2011-03-06 00:30:17 +03:00
else :
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 2
Settings . CORRECT_SIGNS_LINES = [ " mqc.c:566 " , " mqc.c:317 " ]
2011-02-28 03:55:53 +03:00
2011-12-21 09:15:48 +04:00
post = '''
def process ( filename ) :
2011-12-21 09:49:17 +04:00
import tools . shared as shared
original_j2k = shared . path_from_root ( ' tests ' , ' openjpeg ' , ' syntensity_lobby_s.j2k ' )
2011-12-21 09:15:48 +04:00
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ PRE_RUN_ADDITIONS}} ' ,
2012-01-17 00:12:15 +04:00
" FS.createDataFile( ' / ' , ' image.j2k ' , %s , true, false); " % shared . line_splitter ( str (
2011-12-21 09:15:48 +04:00
map ( ord , open ( original_j2k , ' rb ' ) . read ( ) )
) )
) . replace (
' // {{ POST_RUN_ADDITIONS}} ' ,
2011-12-21 09:43:32 +04:00
" print( ' Data: ' + JSON.stringify(FS.root.contents[ ' image.raw ' ].contents)); "
2011-12-21 09:15:48 +04:00
)
open ( filename , ' w ' ) . write ( src )
'''
2011-02-28 03:54:21 +03:00
2011-12-10 22:17:38 +04:00
shutil . copy ( path_from_root ( ' tests ' , ' openjpeg ' , ' opj_config.h ' ) , self . get_dir ( ) )
2011-10-27 07:16:22 +04:00
lib = self . get_library ( ' openjpeg ' ,
2012-01-31 06:21:19 +04:00
[ os . path . join ( ' bin ' , self . get_shared_library_name ( ' libopenjpeg.so.1.4.0 ' ) ) ,
2011-02-28 03:55:53 +03:00
os . path . sep . join ( ' codec/CMakeFiles/j2k_to_image.dir/index.c.o ' . split ( ' / ' ) ) ,
os . path . sep . join ( ' codec/CMakeFiles/j2k_to_image.dir/convert.c.o ' . split ( ' / ' ) ) ,
os . path . sep . join ( ' codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o ' . split ( ' / ' ) ) ,
os . path . sep . join ( ' codec/CMakeFiles/j2k_to_image.dir/__/common/getopt.c.o ' . split ( ' / ' ) ) ] ,
configure = [ ' cmake ' , ' . ' ] ,
#configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'],
2011-12-10 22:17:38 +04:00
make_args = [ ] ) # no -j 2, since parallel builds can fail
2011-02-28 03:54:21 +03:00
# We use doubles in JS, so we get slightly different values than native code. So we
# check our output by comparing the average pixel difference
def image_compare ( output ) :
# Get the image generated by JS, from the JSON.stringify'd array
2011-03-05 19:02:38 +03:00
m = re . search ( ' \ [[ \ d, -]* \ ] ' , output )
2011-03-03 18:39:33 +03:00
try :
js_data = eval ( m . group ( 0 ) )
except AttributeError :
print ' Failed to find proper image output in: ' + output
2011-03-05 19:02:38 +03:00
raise
js_data = map ( lambda x : x if x > = 0 else 256 + x , js_data ) # Our output may be signed, so unsign it
2011-02-28 03:54:21 +03:00
2011-03-06 00:30:17 +03:00
# Get the correct output
true_data = open ( path_from_root ( ' tests ' , ' openjpeg ' , ' syntensity_lobby_s.raw ' ) , ' rb ' ) . read ( )
2011-02-28 03:54:21 +03:00
# Compare them
2011-03-06 00:30:17 +03:00
assert ( len ( js_data ) == len ( true_data ) )
2011-02-28 03:54:21 +03:00
num = len ( js_data )
2011-03-06 00:30:17 +03:00
diff_total = js_total = true_total = 0
2011-02-28 03:54:21 +03:00
for i in range ( num ) :
js_total + = js_data [ i ]
2011-03-06 00:30:17 +03:00
true_total + = ord ( true_data [ i ] )
diff_total + = abs ( js_data [ i ] - ord ( true_data [ i ] ) )
2011-02-28 03:54:21 +03:00
js_mean = js_total / float ( num )
2011-03-06 00:30:17 +03:00
true_mean = true_total / float ( num )
2011-02-28 03:54:21 +03:00
diff_mean = diff_total / float ( num )
2011-03-06 05:41:15 +03:00
image_mean = 83.265
2011-03-06 00:30:17 +03:00
#print '[image stats:', js_mean, image_mean, true_mean, diff_mean, num, ']'
2011-03-06 05:41:15 +03:00
assert abs ( js_mean - image_mean ) < 0.01
assert abs ( true_mean - image_mean ) < 0.01
assert diff_mean < 0.01
2011-02-28 03:54:21 +03:00
return output
2011-10-13 18:40:29 +04:00
self . do_run ( open ( path_from_root ( ' tests ' , ' openjpeg ' , ' codec ' , ' j2k_to_image.c ' ) , ' r ' ) . read ( ) ,
2011-02-28 03:54:21 +03:00
' Successfully generated ' , # The real test for valid output is in image_compare
2011-06-04 01:40:15 +04:00
' -i image.j2k -o image.raw ' . split ( ' ' ) ,
2011-02-28 03:54:21 +03:00
libraries = [ lib ] ,
includes = [ path_from_root ( ' tests ' , ' openjpeg ' , ' libopenjpeg ' ) ,
path_from_root ( ' tests ' , ' openjpeg ' , ' codec ' ) ,
path_from_root ( ' tests ' , ' openjpeg ' , ' common ' ) ,
2011-10-29 02:39:38 +04:00
os . path . join ( self . get_build_dir ( ) , ' openjpeg ' ) ] ,
2011-02-28 03:54:21 +03:00
force_c = True ,
post_build = post ,
2011-11-04 05:30:39 +04:00
output_nicerizer = image_compare ) #, build_ll_hook=self.do_autodebug)
2011-02-28 03:54:21 +03:00
2010-12-12 00:22:09 +03:00
def test_python ( self ) :
2011-12-07 02:32:44 +04:00
if Settings . QUANTUM_SIZE == 1 : return self . skip ( ' TODO: make this work ' )
2011-09-04 23:06:59 +04:00
2011-01-02 03:56:22 +03:00
# Overflows in string_hash
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 1
Settings . CHECK_OVERFLOWS = 0
2012-01-24 08:22:07 +04:00
if self . emcc_args is None : Settings . SAFE_HEAP = 0 # Has bitfields which are false positives. Also the PyFloat_Init tries to detect endianness.
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 1 # Not sure why, but needed
Settings . EXPORTED_FUNCTIONS = [ ' _main ' , ' _PyRun_SimpleStringFlags ' ] # for the demo
2011-06-19 10:15:14 +04:00
2012-02-01 02:07:22 +04:00
self . do_ll_run ( path_from_root ( ' tests ' , ' python ' , ' python.small.bc ' ) ,
2011-07-03 08:34:23 +04:00
' hello python world! \n [0, 2, 4, 6] \n 5 \n 22 \n 5.470000 ' ,
2012-01-22 02:24:33 +04:00
args = [ ' -S ' , ' -c ' ''' print " hello python world! " ; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print ' %f ' % 5.47 ''' ] )
2010-12-12 00:22:09 +03:00
2011-07-08 04:58:35 +04:00
# Test cases in separate files. Note that these files may contain invalid .ll!
# They are only valid enough for us to read for test purposes, not for llvm-as
# to process.
2010-11-17 07:05:51 +03:00
def test_cases ( self ) :
2011-12-22 03:47:38 +04:00
try :
self . banned_js_engines = [ NODE_JS ] # node issue 1669, exception causes stdout not to be flushed
2011-12-04 08:09:11 +04:00
2011-12-22 03:47:38 +04:00
os . environ [ ' EMCC_LEAVE_INPUTS_RAW ' ] = ' 1 '
Settings . CHECK_OVERFLOWS = 0
if Building . LLVM_OPTS : return self . skip ( " Our code is not exactly ' normal ' llvm assembly " )
for name in glob . glob ( path_from_root ( ' tests ' , ' cases ' , ' *.ll ' ) ) :
shortname = name . replace ( ' .ll ' , ' ' )
if ' ' not in shortname : continue
2012-01-28 00:09:59 +04:00
if ' _ta2 ' in shortname and not Settings . USE_TYPED_ARRAYS == 2 :
2012-01-28 00:22:22 +04:00
print self . skip ( ' case " %s " only relevant for ta2 ' % shortname )
2012-01-28 00:09:59 +04:00
continue
2012-01-09 06:28:27 +04:00
print >> sys . stderr , " Testing case ' %s ' ... " % shortname
2011-12-22 03:47:38 +04:00
output_file = path_from_root ( ' tests ' , ' cases ' , shortname + ' .txt ' )
if Settings . QUANTUM_SIZE == 1 :
q1_output_file = path_from_root ( ' tests ' , ' cases ' , shortname + ' _q1.txt ' )
if os . path . exists ( q1_output_file ) :
output_file = q1_output_file
if os . path . exists ( output_file ) :
output = open ( output_file , ' r ' ) . read ( )
else :
output = ' hello, world! '
if output . rstrip ( ) != ' skip ' :
self . do_ll_run ( path_from_root ( ' tests ' , ' cases ' , name ) , output )
# Optional source checking, a python script that gets a global generated with the source
src_checker = path_from_root ( ' tests ' , ' cases ' , shortname + ' .py ' )
if os . path . exists ( src_checker ) :
generated = open ( ' src.cpp.o.js ' ) . read ( )
exec ( open ( src_checker ) . read ( ) )
2011-09-04 23:06:59 +04:00
2011-12-22 03:47:38 +04:00
finally :
del os . environ [ ' EMCC_LEAVE_INPUTS_RAW ' ]
2010-11-17 07:05:51 +03:00
2011-03-03 18:39:33 +03:00
# Autodebug the code
def do_autodebug ( self , filename ) :
2012-01-03 07:21:57 +04:00
output = Popen ( [ ' python ' , AUTODEBUGGER , filename + ' .o.ll ' , filename + ' .o.ll.ll ' ] , stdout = PIPE , stderr = self . stderr_redirect ) . communicate ( ) [ 0 ]
2011-03-03 18:39:33 +03:00
assert ' Success. ' in output , output
2011-11-12 05:21:20 +04:00
self . prep_ll_run ( filename , filename + ' .o.ll.ll ' , force_recompile = True ) # rebuild .bc # TODO: use code in do_autodebug_post for this
# Autodebug the code, after LLVM opts. Will only work once!
def do_autodebug_post ( self , filename ) :
if not hasattr ( self , ' post ' ) :
print ' Asking for post re-call '
self . post = True
return True
print ' Autodebugging during post time '
delattr ( self , ' post ' )
2012-01-03 07:21:57 +04:00
output = Popen ( [ ' python ' , AUTODEBUGGER , filename + ' .o.ll ' , filename + ' .o.ll.ll ' ] , stdout = PIPE , stderr = self . stderr_redirect ) . communicate ( ) [ 0 ]
2011-11-12 05:21:20 +04:00
assert ' Success. ' in output , output
shutil . copyfile ( filename + ' .o.ll.ll ' , filename + ' .o.ll ' )
Building . llvm_as ( filename )
Building . llvm_dis ( filename )
2011-03-03 18:39:33 +03:00
2011-03-03 06:12:13 +03:00
def test_autodebug ( self ) :
2011-10-27 07:41:51 +04:00
if Building . LLVM_OPTS : return self . skip ( ' LLVM opts mess us up ' )
2011-03-03 06:12:13 +03:00
# Run a test that should work, generating some code
self . test_structs ( )
2011-03-03 18:39:33 +03:00
filename = os . path . join ( self . get_dir ( ) , ' src.cpp ' )
self . do_autodebug ( filename )
2011-03-03 06:12:13 +03:00
# Compare to each other, and to expected output
2012-01-28 00:01:19 +04:00
self . do_ll_run ( path_from_root ( ' tests ' , filename + ' .o.ll.ll ' ) , ''' AD:-1,1 ''' )
2012-01-20 09:06:44 +04:00
assert open ( ' stdout ' ) . read ( ) . startswith ( ' AD:-1 ' ) , ' We must note when we enter functions '
2011-03-03 18:39:33 +03:00
# Test using build_ll_hook
src = '''
#include <stdio.h>
char cache [ 256 ] , * next = cache ;
int main ( )
{
cache [ 10 ] = 25 ;
next [ 20 ] = 51 ;
int x = cache [ 10 ] ;
2011-09-11 01:30:17 +04:00
double y = 11.52 ;
printf ( " * %d , %d , %.2f * \\ n " , x , cache [ 20 ] , y ) ;
2011-03-03 18:39:33 +03:00
return 0 ;
}
'''
2012-01-28 00:01:19 +04:00
self . do_run ( src , ''' AD:-1,1 ''' , build_ll_hook = self . do_autodebug )
2011-03-03 06:12:13 +03:00
2011-09-18 23:57:07 +04:00
def test_profiling ( self ) :
2011-10-29 01:05:59 +04:00
src = '''
#include <emscripten.h>
#include <unistd.h>
int main ( )
{
EMSCRIPTEN_PROFILE_INIT ( 3 ) ;
EMSCRIPTEN_PROFILE_BEGIN ( 0 ) ;
usleep ( 10 * 1000 ) ;
EMSCRIPTEN_PROFILE_END ( 0 ) ;
EMSCRIPTEN_PROFILE_BEGIN ( 1 ) ;
usleep ( 50 * 1000 ) ;
EMSCRIPTEN_PROFILE_END ( 1 ) ;
EMSCRIPTEN_PROFILE_BEGIN ( 2 ) ;
usleep ( 250 * 1000 ) ;
EMSCRIPTEN_PROFILE_END ( 2 ) ;
return 0 ;
}
'''
2011-12-21 09:15:48 +04:00
post1 = '''
def process ( filename ) :
src = open ( filename , ' a ' )
src . write ( \' \' \'
Profiling . dump ( ) ;
\' \' \' )
src . close ( )
'''
2011-10-29 01:05:59 +04:00
self . do_run ( src , ''' Profiling data:
Block 0 : ''' , post_build=post1)
2010-11-06 06:48:19 +03:00
### Integration tests
def test_scriptaclass ( self ) :
2011-07-07 07:50:04 +04:00
header_filename = os . path . join ( self . get_dir ( ) , ' header.h ' )
2011-07-04 10:51:38 +04:00
header = '''
2010-11-06 06:48:19 +03:00
struct ScriptMe {
int value ;
ScriptMe ( int val ) ;
int getVal ( ) ; / / XXX Sadly , inlining these will result in LLVM not
/ / producing any code for them ( when just building
/ / as a library )
2010-11-18 10:13:17 +03:00
void mulVal ( int mul ) ;
2010-11-06 06:48:19 +03:00
} ;
2011-07-04 10:51:38 +04:00
'''
2011-07-07 07:50:04 +04:00
h = open ( header_filename , ' w ' )
h . write ( header )
h . close ( )
2011-07-04 10:51:38 +04:00
src = '''
#include "header.h"
2010-11-06 06:48:19 +03:00
ScriptMe : : ScriptMe ( int val ) : value ( val ) { }
int ScriptMe : : getVal ( ) { return value ; }
2010-11-18 10:13:17 +03:00
void ScriptMe : : mulVal ( int mul ) { value * = mul ; }
2010-11-06 06:48:19 +03:00
'''
2011-07-04 10:51:38 +04:00
# Way 1: use demangler and namespacer
2010-11-06 06:48:19 +03:00
script_src = '''
2010-11-07 00:59:41 +03:00
var sme = Module . _ . ScriptMe . __new__ ( 83 ) ; / / malloc ( sizeof ( ScriptMe ) ) , ScriptMe : : ScriptMe ( sme , 83 ) / new ScriptMe ( 83 ) ( at addr sme )
2010-11-06 22:55:25 +03:00
Module . _ . ScriptMe . mulVal ( sme , 2 ) ; / / ScriptMe : : mulVal ( sme , 2 ) sme . mulVal ( 2 )
print ( ' * ' + Module . _ . ScriptMe . getVal ( sme ) + ' * ' ) ;
2011-02-21 06:03:14 +03:00
_free ( sme ) ;
2010-11-06 21:48:23 +03:00
print ( ' *ok* ' ) ;
2010-11-06 06:48:19 +03:00
'''
2011-12-21 09:15:48 +04:00
post = '''
def process ( filename ) :
Popen ( [ ' python ' , DEMANGLER , filename ] , stdout = open ( filename + ' .tmp ' , ' w ' ) ) . communicate ( )
Popen ( [ ' python ' , NAMESPACER , filename , filename + ' .tmp ' ] , stdout = open ( filename + ' .tmp2 ' , ' w ' ) ) . communicate ( )
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ MODULE_ADDITIONS} ' ,
' Module[ " _ " ] = ' + open ( filename + ' .tmp2 ' , ' r ' ) . read ( ) . replace ( ' var ModuleNames = ' , ' ' ) . rstrip ( ) + ' ; \n \n ' + script_src + ' \n \n ' +
' // {{ MODULE_ADDITIONS} '
)
open ( filename , ' w ' ) . write ( src )
'''
2011-10-13 18:40:29 +04:00
# XXX disable due to possible v8 bug -- self.do_run(src, '*166*\n*ok*', post_build=post)
2010-11-06 06:48:19 +03:00
2012-02-04 03:00:45 +04:00
if self . emcc_args is not None and ' -O2 ' in self . emcc_args :
self . emcc_args + = [ ' --closure ' , ' 1 ' ] # Use closure here, to test we export things right
2011-07-04 10:51:38 +04:00
# Way 2: use CppHeaderParser
2011-10-21 23:08:44 +04:00
Settings . RUNTIME_TYPE_INFO = 1
2011-08-16 05:16:37 +04:00
2011-07-07 07:50:04 +04:00
header = '''
#include <stdio.h>
class Parent {
protected :
int value ;
public :
Parent ( int val ) ;
int getVal ( ) { return value ; } ; / / inline should work just fine here , unlike Way 1 before
void mulVal ( int mul ) ;
} ;
class Child1 : public Parent {
public :
Child1 ( ) : Parent ( 7 ) { printf ( " Child1: %d \\ n " , value ) ; } ;
Child1 ( int val ) : Parent ( val * 2 ) { value - = 1 ; printf ( " Child1: %d \\ n " , value ) ; } ;
int getValSqr ( ) { return value * value ; }
int getValSqr ( int more ) { return value * value * more ; }
2011-07-24 05:25:36 +04:00
int getValTimes ( int times = 1 ) { return value * times ; }
2011-07-07 07:50:04 +04:00
} ;
2011-07-26 09:03:18 +04:00
class Child2 : public Parent {
2011-07-07 07:50:04 +04:00
public :
Child2 ( ) : Parent ( 9 ) { printf ( " Child2: %d \\ n " , value ) ; } ;
int getValCube ( ) { return value * value * value ; }
2011-07-24 10:43:01 +04:00
static void printStatic ( ) { printf ( " *static* \\ n " ) ; }
2011-09-07 07:40:20 +04:00
virtual void virtualFunc ( ) { printf ( " *virtualf* \\ n " ) ; }
virtual void virtualFunc2 ( ) { printf ( " *virtualf2* \\ n " ) ; }
static void runVirtualFunc ( Child2 * self ) { self - > virtualFunc ( ) ; } ;
2011-07-07 07:50:04 +04:00
private :
void doSomethingSecret ( ) { printf ( " security breached! \\ n " ) ; } ; / / we should not be able to do this
} ;
'''
open ( header_filename , ' w ' ) . write ( header )
2011-07-04 10:51:38 +04:00
basename = os . path . join ( self . get_dir ( ) , ' bindingtest ' )
2012-01-03 07:21:57 +04:00
output = Popen ( [ BINDINGS_GENERATOR , basename , header_filename ] , stdout = PIPE , stderr = self . stderr_redirect ) . communicate ( ) [ 0 ]
2011-07-24 05:25:36 +04:00
#print output
2011-07-07 07:50:04 +04:00
assert ' Traceback ' not in output , ' Failure in binding generation: ' + output
2011-07-04 10:51:38 +04:00
2011-07-04 23:17:06 +04:00
src = '''
#include "header.h"
2011-07-07 07:50:04 +04:00
Parent : : Parent ( int val ) : value ( val ) { printf ( " Parent: %d \\ n " , val ) ; }
void Parent : : mulVal ( int mul ) { value * = mul ; }
2011-07-04 23:17:06 +04:00
2011-08-07 03:13:23 +04:00
#include "bindingtest.cpp"
2011-07-04 23:17:06 +04:00
'''
2011-07-04 10:51:38 +04:00
2011-12-22 02:09:14 +04:00
post2 = '''
2012-02-04 03:00:45 +04:00
def process ( filename ) :
src = open ( filename , ' a ' )
src . write ( open ( ' bindingtest.js ' ) . read ( ) + ' \\ n \\ n ' )
src . close ( )
'''
post3 = '''
2011-12-22 02:09:14 +04:00
def process ( filename ) :
script_src_2 = \' \' \'
2012-02-04 03:00:45 +04:00
var sme = new Module . Parent ( 42 ) ;
2011-07-04 10:51:38 +04:00
sme . mulVal ( 2 ) ;
2011-07-07 07:50:04 +04:00
print ( ' * ' )
print ( sme . getVal ( ) ) ;
print ( ' c1 ' ) ;
2012-02-04 03:00:45 +04:00
var c1 = new Module . Child1 ( ) ;
2011-07-07 07:50:04 +04:00
print ( c1 . getVal ( ) ) ;
c1 . mulVal ( 2 ) ;
print ( c1 . getVal ( ) ) ;
print ( c1 . getValSqr ( ) ) ;
2011-07-26 09:03:18 +04:00
print ( c1 . getValSqr ( 3 ) ) ;
2011-07-24 05:25:36 +04:00
print ( c1 . getValTimes ( ) ) ; / / default argument should be 1
print ( c1 . getValTimes ( 2 ) ) ;
2011-07-07 07:50:04 +04:00
print ( ' c1 v2 ' ) ;
2012-02-04 03:00:45 +04:00
c1 = new Module . Child1 ( 8 ) ; / / now with a parameter , we should handle the overloading automatically and properly and use constructor #2
2011-07-07 07:50:04 +04:00
print ( c1 . getVal ( ) ) ;
c1 . mulVal ( 2 ) ;
print ( c1 . getVal ( ) ) ;
print ( c1 . getValSqr ( ) ) ;
2011-07-26 09:03:18 +04:00
print ( c1 . getValSqr ( 3 ) ) ;
2011-07-07 07:50:04 +04:00
print ( ' c2 ' )
2012-02-04 03:00:45 +04:00
var c2 = new Module . Child2 ( ) ;
2011-07-07 07:50:04 +04:00
print ( c2 . getVal ( ) ) ;
c2 . mulVal ( 2 ) ;
print ( c2 . getVal ( ) ) ;
print ( c2 . getValCube ( ) ) ;
var succeeded ;
try {
succeeded = 0 ;
print ( c2 . doSomethingSecret ( ) ) ; / / should fail since private
succeeded = 1 ;
} catch ( e ) { }
print ( succeeded ) ;
try {
succeeded = 0 ;
print ( c2 . getValSqr ( ) ) ; / / function from the other class
succeeded = 1 ;
} catch ( e ) { }
print ( succeeded ) ;
try {
succeeded = 0 ;
c2 . getValCube ( ) ; / / sanity
succeeded = 1 ;
} catch ( e ) { }
print ( succeeded ) ;
2012-02-04 03:00:45 +04:00
Module . Child2 . prototype . printStatic ( ) ; / / static calls go through the prototype
2011-07-24 10:43:01 +04:00
2011-09-07 07:40:20 +04:00
/ / virtual function
c2 . virtualFunc ( ) ;
2012-02-04 03:00:45 +04:00
Module . Child2 . prototype . runVirtualFunc ( c2 ) ;
2011-09-07 07:40:20 +04:00
c2 . virtualFunc2 ( ) ;
/ / extend the class from JS
2012-02-04 03:00:45 +04:00
var c3 = new Module . Child2 ;
Module . customizeVTable ( c3 , [ {
original : Module . Child2 . prototype . virtualFunc ,
2011-09-07 07:40:20 +04:00
replacement : function ( ) {
print ( ' *js virtualf replacement* ' ) ;
}
} , {
2012-02-04 03:00:45 +04:00
original : Module . Child2 . prototype . virtualFunc2 ,
2011-09-07 07:40:20 +04:00
replacement : function ( ) {
print ( ' *js virtualf2 replacement* ' ) ;
}
} ] ) ;
c3 . virtualFunc ( ) ;
2012-02-04 03:00:45 +04:00
Module . Child2 . prototype . runVirtualFunc ( c3 ) ;
2011-09-07 07:40:20 +04:00
c3 . virtualFunc2 ( ) ;
c2 . virtualFunc ( ) ; / / original should remain the same
2012-02-04 03:00:45 +04:00
Module . Child2 . prototype . runVirtualFunc ( c2 ) ;
2011-09-07 07:40:20 +04:00
c2 . virtualFunc2 ( ) ;
2011-07-04 10:51:38 +04:00
print ( ' *ok* ' ) ;
2011-12-22 02:09:14 +04:00
\' \' \'
2012-02-04 03:00:45 +04:00
src = open ( filename , ' a ' )
src . write ( script_src_2 + ' \\ n ' )
src . close ( )
2011-12-21 09:15:48 +04:00
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ''' *
2011-07-07 07:50:04 +04:00
84
c1
Parent : 7
Child1 : 7
7
14
196
588
2011-07-24 05:25:36 +04:00
14
28
2011-07-07 07:50:04 +04:00
c1 v2
Parent : 16
Child1 : 15
15
30
900
2700
c2
Parent : 9
Child2 : 9
9
18
5832
0
0
1
2011-07-24 10:43:01 +04:00
* static *
2011-09-07 07:40:20 +04:00
* virtualf *
* virtualf *
* virtualf2 *
Parent : 9
Child2 : 9
* js virtualf replacement *
* js virtualf replacement *
* js virtualf2 replacement *
* virtualf *
* virtualf *
* virtualf2 *
2011-07-07 07:50:04 +04:00
* ok *
2012-02-04 03:00:45 +04:00
''' , post_build=[post2, post3])
2011-07-04 10:51:38 +04:00
2011-07-16 06:35:27 +04:00
def test_typeinfo ( self ) :
2012-01-24 02:55:24 +04:00
if self . emcc_args is not None and self . emcc_args != [ ] : return self . skip ( ' full LLVM opts optimize out all the code that uses the type ' )
2011-10-21 23:08:44 +04:00
Settings . RUNTIME_TYPE_INFO = 1
if Settings . QUANTUM_SIZE != 4 : return self . skip ( ' We assume normal sizes in the output here ' )
2011-07-16 06:35:27 +04:00
src = '''
#include<stdio.h>
struct UserStruct {
int x ;
char y ;
2011-07-18 09:06:26 +04:00
short z ;
} ;
struct Encloser {
short x ;
UserStruct us ;
int y ;
2011-07-16 06:35:27 +04:00
} ;
int main ( ) {
2011-07-18 09:06:26 +04:00
Encloser e ;
e . us . y = 5 ;
printf ( " *ok: %d * \\ n " , e . us . y ) ;
2011-07-16 06:35:27 +04:00
return 0 ;
}
'''
2011-12-21 09:15:48 +04:00
post = '''
def process ( filename ) :
src = open ( filename , ' r ' ) . read ( ) . replace (
' // {{ POST_RUN_ADDITIONS}} ' ,
\' \' \'
if ( Runtime . typeInfo ) {
print ( ' | ' + Runtime . typeInfo . UserStruct . fields + ' | ' + Runtime . typeInfo . UserStruct . flatIndexes + ' | ' ) ;
var t = Runtime . generateStructInfo ( [ ' x ' , { us : [ ' x ' , ' y ' , ' z ' ] } , ' y ' ] , ' Encloser ' )
print ( ' | ' + [ t . x , t . us . x , t . us . y , t . us . z , t . y ] + ' | ' ) ;
2012-02-01 04:33:52 +04:00
print ( ' | ' + JSON . stringify ( Runtime . generateStructInfo ( [ ' x ' , ' y ' , ' z ' ] , ' UserStruct ' ) ) + ' | ' ) ;
2011-12-21 09:15:48 +04:00
} else {
print ( ' No type info. ' ) ;
}
\' \' \'
)
open ( filename , ' w ' ) . write ( src )
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src ,
2011-08-16 05:16:37 +04:00
' *ok:5* \n |i32,i8,i16|0,4,6| \n |0,4,8,10,12| \n | { " __size__ " :8, " x " :0, " y " :4, " z " :6}| ' ,
post_build = post )
2011-07-16 06:35:27 +04:00
# Make sure that without the setting, we don't spam the .js with the type info
2011-10-21 23:08:44 +04:00
Settings . RUNTIME_TYPE_INFO = 0
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' No type info. ' , post_build = post )
2011-07-16 06:35:27 +04:00
2010-11-22 04:43:22 +03:00
### Tests for tools
def test_safe_heap ( self ) :
2011-10-21 23:08:44 +04:00
if not Settings . SAFE_HEAP : return self . skip ( ' We need SAFE_HEAP to test SAFE_HEAP ' )
2011-12-09 22:35:05 +04:00
if Settings . USE_TYPED_ARRAYS == 2 : return self . skip ( ' It is ok to violate the load-store assumption with TA2 ' )
2011-10-27 07:41:51 +04:00
if Building . LLVM_OPTS : return self . skip ( ' LLVM can optimize away the intermediate |x| ' )
2011-10-18 22:49:36 +04:00
2010-11-22 04:43:22 +03:00
src = '''
#include<stdio.h>
int main ( ) {
int * x = new int ;
* x = 20 ;
float * y = ( float * ) x ;
printf ( " %f \\ n " , * y ) ;
2011-04-22 00:17:24 +04:00
printf ( " *ok* \\ n " ) ;
2010-11-22 04:43:22 +03:00
return 0 ;
}
'''
2011-04-22 00:17:24 +04:00
try :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *nothingatall* ' )
2011-04-22 00:17:24 +04:00
except Exception , e :
# This test *should* fail, by throwing this exception
assert ' Assertion failed: Load-store consistency assumption failure! ' in str ( e ) , str ( e )
# And we should not fail if we disable checking on that line
2011-10-21 23:08:44 +04:00
Settings . SAFE_HEAP = 3
Settings . SAFE_HEAP_LINES = [ " src.cpp:7 " ]
2011-04-22 00:17:24 +04:00
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *ok* ' )
2011-04-22 00:17:24 +04:00
# But if we disable the wrong lines, we still fail
2011-10-21 23:08:44 +04:00
Settings . SAFE_HEAP_LINES = [ " src.cpp:99 " ]
2011-04-22 00:17:24 +04:00
2010-11-22 04:43:22 +03:00
try :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *nothingatall* ' )
2010-11-22 04:43:22 +03:00
except Exception , e :
2010-12-24 01:09:16 +03:00
# This test *should* fail, by throwing this exception
2010-11-22 04:43:22 +03:00
assert ' Assertion failed: Load-store consistency assumption failure! ' in str ( e ) , str ( e )
2011-05-26 02:00:11 +04:00
# And reverse the checks with = 2
2011-10-21 23:08:44 +04:00
Settings . SAFE_HEAP = 2
Settings . SAFE_HEAP_LINES = [ " src.cpp:99 " ]
2011-05-26 02:00:11 +04:00
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *ok* ' )
2011-05-26 02:00:11 +04:00
2011-12-05 06:51:43 +04:00
Settings . SAFE_HEAP = 1
# Linking multiple files should work too
module = '''
#include<stdio.h>
void callFunc ( ) {
int * x = new int ;
* x = 20 ;
float * y = ( float * ) x ;
printf ( " %f \\ n " , * y ) ;
}
'''
module_name = os . path . join ( self . get_dir ( ) , ' module.cpp ' )
open ( module_name , ' w ' ) . write ( module )
main = '''
#include<stdio.h>
extern void callFunc ( ) ;
int main ( ) {
callFunc ( ) ;
int * x = new int ;
* x = 20 ;
float * y = ( float * ) x ;
printf ( " %f \\ n " , * y ) ;
printf ( " *ok* \\ n " ) ;
return 0 ;
}
'''
main_name = os . path . join ( self . get_dir ( ) , ' main.cpp ' )
open ( main_name , ' w ' ) . write ( main )
2011-12-18 04:52:17 +04:00
Building . emcc ( module_name , [ ' -g ' ] )
Building . emcc ( main_name , [ ' -g ' ] )
2011-12-05 06:51:43 +04:00
all_name = os . path . join ( self . get_dir ( ) , ' all.bc ' )
Building . link ( [ module_name + ' .o ' , main_name + ' .o ' ] , all_name )
try :
self . do_ll_run ( all_name , ' *nothingatall* ' )
except Exception , e :
# This test *should* fail, by throwing this exception
assert ' Assertion failed: Load-store consistency assumption failure! ' in str ( e ) , str ( e )
# And we should not fail if we disable checking on those lines
Settings . SAFE_HEAP = 3
Settings . SAFE_HEAP_LINES = [ " module.cpp:7 " , " main.cpp:9 " ]
self . do_ll_run ( all_name , ' *ok* ' )
# But we will fail if we do not disable exactly what we need to - any mistake leads to error
for lines in [ [ " module.cpp:22 " , " main.cpp:9 " ] , [ " module.cpp:7 " , " main.cpp:29 " ] , [ " module.cpp:127 " , " main.cpp:449 " ] , [ " module.cpp:7 " ] , [ " main.cpp:9 " ] ] :
Settings . SAFE_HEAP_LINES = lines
try :
self . do_ll_run ( all_name , ' *nothingatall* ' )
except Exception , e :
# This test *should* fail, by throwing this exception
assert ' Assertion failed: Load-store consistency assumption failure! ' in str ( e ) , str ( e )
2010-12-20 00:43:26 +03:00
def test_check_overflow ( self ) :
2011-10-21 23:08:44 +04:00
Settings . CHECK_OVERFLOWS = 1
Settings . CORRECT_OVERFLOWS = 0
2011-01-02 03:56:22 +03:00
2010-12-20 00:43:26 +03:00
src = '''
#include<stdio.h>
int main ( ) {
int t = 77 ;
for ( int i = 0 ; i < 30 ; i + + ) {
/ / t = ( t << 2 ) + t + 1 ; / / This would have worked , since << forces into 32 - bit int . . .
t = t * 5 + 1 ; / / Python lookdict_string has ~ the above line , which turns into this one with optimizations . . .
printf ( " %d , %d \\ n " , t , t & 127 ) ;
}
return 0 ;
}
'''
try :
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *nothingatall* ' )
2010-12-20 00:43:26 +03:00
except Exception , e :
2010-12-24 01:09:16 +03:00
# This test *should* fail, by throwing this exception
2011-02-20 09:44:16 +03:00
assert ' Too many corrections ' in str ( e ) , str ( e )
2010-12-20 00:43:26 +03:00
2011-02-13 06:36:02 +03:00
def test_debug ( self ) :
src = '''
#include <stdio.h>
#include <assert.h>
void checker ( int x ) {
x + = 20 ;
assert ( x < 15 ) ; / / this is line 7 !
}
int main ( ) {
checker ( 10 ) ;
return 0 ;
}
'''
try :
2011-12-21 09:23:21 +04:00
post = r '''
2011-12-21 09:15:48 +04:00
def process ( filename ) :
lines = open ( filename , ' r ' ) . readlines ( )
lines = filter ( lambda line : ' ___assert_fail( ' in line or ' ___assert_func( ' in line , lines )
found_line_num = any ( ( ' //@line 7 " ' in line ) for line in lines )
found_filename = any ( ( ' src.cpp " \n ' in line ) for line in lines )
assert found_line_num , ' Must have debug info with the line number '
assert found_filename , ' Must have debug info with the filename '
'''
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *nothingatall* ' , post_build = post )
2011-02-13 06:36:02 +03:00
except Exception , e :
# This test *should* fail
assert ' Assertion failed ' in str ( e ) , str ( e )
2011-02-28 03:54:21 +03:00
def test_linespecific ( self ) :
2012-01-24 06:24:34 +04:00
if self . emcc_args : self . emcc_args + = [ ' --llvm-opts ' , ' 0 ' ] # llvm full opts make the expected failures here not happen
2011-10-21 23:08:44 +04:00
Settings . CHECK_SIGNS = 0
Settings . CHECK_OVERFLOWS = 0
2011-11-12 09:21:58 +04:00
2011-03-05 07:02:31 +03:00
# Signs
2011-02-20 02:45:17 +03:00
src = '''
#include <stdio.h>
#include <assert.h>
int main ( )
{
int varey = 100 ;
unsigned int MAXEY = - 1 ;
printf ( " * %d * \\ n " , varey > = MAXEY ) ; / / 100 > = - 1 ? not in unsigned !
}
'''
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 0
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *1* ' ) # This is a fail - we expect 0
2011-02-20 02:45:17 +03:00
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 1
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *0* ' ) # Now it will work properly
2011-02-20 02:45:17 +03:00
# And now let's fix just that one line
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 2
Settings . CORRECT_SIGNS_LINES = [ " src.cpp:9 " ]
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *0* ' )
2011-02-20 02:45:17 +03:00
# Fixing the wrong line should not work
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 2
Settings . CORRECT_SIGNS_LINES = [ " src.cpp:3 " ]
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *1* ' )
2011-02-20 02:45:17 +03:00
2011-05-26 02:00:11 +04:00
# And reverse the checks with = 2
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 3
Settings . CORRECT_SIGNS_LINES = [ " src.cpp:3 " ]
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *0* ' )
2011-10-21 23:08:44 +04:00
Settings . CORRECT_SIGNS = 3
Settings . CORRECT_SIGNS_LINES = [ " src.cpp:9 " ]
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *1* ' )
2011-05-26 02:00:11 +04:00
2011-11-25 08:12:17 +04:00
Settings . CORRECT_SIGNS = 0
2011-05-27 00:32:57 +04:00
# Overflows
2011-02-20 02:45:17 +03:00
src = '''
#include<stdio.h>
int main ( ) {
int t = 77 ;
for ( int i = 0 ; i < 30 ; i + + ) {
t = t * 5 + 1 ;
}
printf ( " * %d , %d * \\ n " , t , t & 127 ) ;
return 0 ;
}
'''
correct = ' *186854335,63* '
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 0
2011-02-20 02:45:17 +03:00
try :
2011-10-13 18:40:29 +04:00
self . do_run ( src , correct )
2011-02-20 02:45:17 +03:00
raise Exception ( ' UNEXPECTED-PASS ' )
except Exception , e :
assert ' UNEXPECTED ' not in str ( e ) , str ( e )
assert ' Expected to find ' in str ( e ) , str ( e )
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 1
2011-10-13 18:40:29 +04:00
self . do_run ( src , correct ) # Now it will work properly
2011-02-20 02:45:17 +03:00
# And now let's fix just that one line
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 2
Settings . CORRECT_OVERFLOWS_LINES = [ " src.cpp:6 " ]
2011-10-13 18:40:29 +04:00
self . do_run ( src , correct )
2011-02-20 02:45:17 +03:00
# Fixing the wrong line should not work
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 2
Settings . CORRECT_OVERFLOWS_LINES = [ " src.cpp:3 " ]
2011-02-20 02:45:17 +03:00
try :
2011-10-13 18:40:29 +04:00
self . do_run ( src , correct )
2011-02-20 02:45:17 +03:00
raise Exception ( ' UNEXPECTED-PASS ' )
except Exception , e :
assert ' UNEXPECTED ' not in str ( e ) , str ( e )
assert ' Expected to find ' in str ( e ) , str ( e )
2010-12-20 00:43:26 +03:00
2011-05-26 02:00:11 +04:00
# And reverse the checks with = 2
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 3
Settings . CORRECT_OVERFLOWS_LINES = [ " src.cpp:3 " ]
2011-10-13 18:40:29 +04:00
self . do_run ( src , correct )
2011-10-21 23:08:44 +04:00
Settings . CORRECT_OVERFLOWS = 3
Settings . CORRECT_OVERFLOWS_LINES = [ " src.cpp:6 " ]
2011-05-26 02:00:11 +04:00
try :
2011-10-13 18:40:29 +04:00
self . do_run ( src , correct )
2011-05-26 02:00:11 +04:00
raise Exception ( ' UNEXPECTED-PASS ' )
except Exception , e :
assert ' UNEXPECTED ' not in str ( e ) , str ( e )
assert ' Expected to find ' in str ( e ) , str ( e )
2011-11-25 08:12:17 +04:00
Settings . CORRECT_OVERFLOWS = 0
2011-03-05 07:02:31 +03:00
# Roundings
src = '''
#include <stdio.h>
#include <assert.h>
int main ( )
{
TYPE x = - 5 ;
printf ( " * %d * " , x / 2 ) ;
x = 5 ;
printf ( " * %d * " , x / 2 ) ;
float y = - 5.33 ;
x = y ;
printf ( " * %d * " , x ) ;
y = 5.33 ;
x = y ;
printf ( " * %d * " , x ) ;
printf ( " \\ n " ) ;
}
'''
2011-12-08 01:47:08 +04:00
if Settings . I64_MODE == 0 : # the errors here are very specific to non-i64 mode 1
Settings . CORRECT_ROUNDINGS = 0
self . do_run ( src . replace ( ' TYPE ' , ' long long ' ) , ' *-3**2**-6**5* ' ) # JS floor operations, always to the negative. This is an undetected error here!
self . do_run ( src . replace ( ' TYPE ' , ' int ' ) , ' *-2**2**-5**5* ' ) # We get these right, since they are 32-bit and we can shortcut using the |0 trick
self . do_run ( src . replace ( ' TYPE ' , ' unsigned int ' ) , ' *-3**2**-6**5* ' ) # We fail, since no fast shortcut for 32-bit unsigneds
2011-03-05 07:02:31 +03:00
2011-10-21 23:08:44 +04:00
Settings . CORRECT_ROUNDINGS = 1
2011-12-08 01:47:08 +04:00
Settings . CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well
2011-10-13 18:40:29 +04:00
self . do_run ( src . replace ( ' TYPE ' , ' long long ' ) , ' *-2**2**-5**5* ' ) # Correct
self . do_run ( src . replace ( ' TYPE ' , ' int ' ) , ' *-2**2**-5**5* ' ) # Correct
2011-11-25 08:12:17 +04:00
self . do_run ( src . replace ( ' TYPE ' , ' unsigned int ' ) , ' *2147483645**2**-5**5* ' ) # Correct
Settings . CORRECT_SIGNS = 0
2011-03-05 07:02:31 +03:00
2011-12-08 01:47:08 +04:00
if Settings . I64_MODE == 0 : # the errors here are very specific to non-i64 mode 1
Settings . CORRECT_ROUNDINGS = 2
Settings . CORRECT_ROUNDINGS_LINES = [ " src.cpp:13 " ] # Fix just the last mistake
self . do_run ( src . replace ( ' TYPE ' , ' long long ' ) , ' *-3**2**-5**5* ' )
self . do_run ( src . replace ( ' TYPE ' , ' int ' ) , ' *-2**2**-5**5* ' ) # Here we are lucky and also get the first one right
self . do_run ( src . replace ( ' TYPE ' , ' unsigned int ' ) , ' *-3**2**-5**5* ' ) # No such luck here
2011-03-05 07:02:31 +03:00
2011-05-26 02:00:11 +04:00
# And reverse the check with = 2
2011-12-08 01:47:08 +04:00
if Settings . I64_MODE == 0 : # the errors here are very specific to non-i64 mode 1
Settings . CORRECT_ROUNDINGS = 3
Settings . CORRECT_ROUNDINGS_LINES = [ " src.cpp:999 " ]
self . do_run ( src . replace ( ' TYPE ' , ' long long ' ) , ' *-2**2**-5**5* ' )
self . do_run ( src . replace ( ' TYPE ' , ' int ' ) , ' *-2**2**-5**5* ' )
Settings . CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well
self . do_run ( src . replace ( ' TYPE ' , ' unsigned int ' ) , ' *2147483645**2**-5**5* ' )
Settings . CORRECT_SIGNS = 0
2011-05-26 02:00:11 +04:00
2011-11-17 22:16:42 +04:00
def test_pgo ( self ) :
Settings . PGO = Settings . CHECK_OVERFLOWS = Settings . CORRECT_OVERFLOWS = Settings . CHECK_SIGNS = Settings . CORRECT_SIGNS = 1
2011-05-27 00:32:57 +04:00
src = '''
#include<stdio.h>
int main ( ) {
int t = 77 ;
for ( int i = 0 ; i < 30 ; i + + ) {
t = t * 5 + 1 ;
}
printf ( " * %d , %d * \\ n " , t , t & 127 ) ;
2011-05-27 03:29:59 +04:00
int varey = 100 ;
unsigned int MAXEY = - 1 ;
for ( int j = 0 ; j < 2 ; j + + ) {
printf ( " * %d * \\ n " , varey > = MAXEY ) ; / / 100 > = - 1 ? not in unsigned !
MAXEY = 1 ; / / So we succeed the second time around
}
2011-05-27 00:32:57 +04:00
return 0 ;
}
'''
def check ( output ) :
# TODO: check the line #
2012-01-24 03:05:26 +04:00
if self . emcc_args is None or self . emcc_args == [ ] : # LLVM full opts optimize out some corrections
assert ' Overflow|src.cpp:6 : 60 hits, % 20 failures ' in output , ' no indication of Overflow corrections: ' + output
assert ' UnSign|src.cpp:13 : 6 hits, % 17 failures ' in output , ' no indication of Sign corrections: ' + output
2011-05-27 00:32:57 +04:00
return output
2011-10-13 18:40:29 +04:00
self . do_run ( src , ' *186854335,63* \n ' , output_nicerizer = check )
2011-05-27 00:32:57 +04:00
2011-11-17 22:16:42 +04:00
Settings . PGO = Settings . CHECK_OVERFLOWS = Settings . CORRECT_OVERFLOWS = Settings . CHECK_SIGNS = Settings . CORRECT_SIGNS = 0
# Now, recompile with the PGO data, and it should work
pgo_data = read_pgo_data ( self . get_stdout_path ( ) )
Settings . CORRECT_SIGNS = 2
Settings . CORRECT_SIGNS_LINES = pgo_data [ ' signs_lines ' ]
Settings . CORRECT_OVERFLOWS = 2
Settings . CORRECT_OVERFLOWS_LINES = pgo_data [ ' overflows_lines ' ]
self . do_run ( src , ' *186854335,63* \n ' )
# Sanity check: Without PGO, we will fail
try :
self . do_run ( src , ' *186854335,63* \n ' )
except :
pass
2011-11-09 01:13:59 +04:00
def test_exit_status ( self ) :
Settings . CATCH_EXIT_CODE = 1
src = '''
#include <stdio.h>
#include <stdlib.h>
int main ( )
{
printf ( " hello, world! \\ n " ) ;
exit ( 118 ) ; / / Unusual exit status to make sure it ' s working!
}
'''
self . do_run ( src , ' hello, world! \n Exit Status: 118 ' )
2011-03-05 07:02:31 +03:00
2011-12-13 04:02:19 +04:00
2011-12-06 22:39:21 +04:00
# Generate tests for everything
2011-12-21 04:38:14 +04:00
def make_run ( fullname , name = - 1 , compiler = - 1 , llvm_opts = 0 , embetter = 0 , quantum_size = 0 , typed_arrays = 0 , emcc_args = None ) :
2010-12-30 08:33:28 +03:00
exec ( '''
class % s ( T ) :
2011-10-13 03:36:50 +04:00
def tearDown ( self ) :
super ( % s , self ) . tearDown ( )
2010-12-30 08:33:28 +03:00
def setUp ( self ) :
2011-10-13 03:36:50 +04:00
super ( % s , self ) . setUp ( )
2011-12-06 22:39:21 +04:00
Building . COMPILER_TEST_OPTS = [ ' -g ' ]
os . chdir ( self . get_dir ( ) ) # Ensure the directory exists and go there
2011-10-27 07:41:51 +04:00
Building . COMPILER = % r
2011-12-06 22:39:21 +04:00
2011-12-21 04:38:14 +04:00
self . emcc_args = % s
if self . emcc_args is not None :
2011-12-21 06:49:42 +04:00
Settings . load ( self . emcc_args )
2011-12-10 05:32:33 +04:00
Building . LLVM_OPTS = 0
2011-12-06 22:39:21 +04:00
return
2011-11-17 00:49:07 +04:00
llvm_opts = % d # 1 is yes, 2 is yes and unsafe
2011-01-01 09:49:25 +03:00
embetter = % d
2011-04-23 00:23:37 +04:00
quantum_size = % d
2011-12-01 02:48:41 +04:00
# TODO: Move much of these to a init() function in shared.py, and reuse that
2011-10-21 23:08:44 +04:00
Settings . USE_TYPED_ARRAYS = % d
Settings . INVOKE_RUN = 1
2011-12-21 04:38:14 +04:00
Settings . RELOOP = 0 # we only do them in the "o2" pass
Settings . MICRO_OPTS = embetter
2011-10-21 23:08:44 +04:00
Settings . QUANTUM_SIZE = quantum_size
Settings . ASSERTIONS = 1 - embetter
Settings . SAFE_HEAP = 1 - ( embetter and llvm_opts )
2011-10-27 07:41:51 +04:00
Building . LLVM_OPTS = llvm_opts
2011-11-17 22:16:42 +04:00
Settings . PGO = 0
2011-10-21 23:08:44 +04:00
Settings . CHECK_OVERFLOWS = 1 - ( embetter or llvm_opts )
Settings . CORRECT_OVERFLOWS = 1 - ( embetter and llvm_opts )
Settings . CORRECT_SIGNS = 0
Settings . CORRECT_ROUNDINGS = 0
Settings . CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = CORRECT_ROUNDINGS_LINES = SAFE_HEAP_LINES = [ ]
Settings . CHECK_SIGNS = 0 #1-(embetter or llvm_opts)
Settings . INIT_STACK = 0
Settings . RUNTIME_TYPE_INFO = 0
Settings . DISABLE_EXCEPTION_CATCHING = 0
Settings . PROFILE = 0
2011-12-01 02:48:41 +04:00
Settings . INCLUDE_FULL_LIBRARY = 0
Settings . BUILD_AS_SHARED_LIB = 0
2011-12-06 03:43:20 +04:00
Settings . RUNTIME_LINKED_LIBS = [ ]
2011-12-03 08:14:12 +04:00
Settings . CATCH_EXIT_CODE = 0
2011-12-21 06:49:42 +04:00
Settings . EMULATE_UNALIGNED_ACCESSES = int ( Settings . USE_TYPED_ARRAYS == 2 and Building . LLVM_OPTS == 2 )
2011-12-07 04:32:03 +04:00
Settings . DOUBLE_MODE = 1 if Settings . USE_TYPED_ARRAYS and Building . LLVM_OPTS == 0 else 0
2011-11-11 22:10:11 +04:00
if Settings . USE_TYPED_ARRAYS == 2 :
Settings . I64_MODE = 1
2011-11-14 00:56:43 +04:00
Settings . SAFE_HEAP = 1 # only checks for alignment problems, which is very important with unsafe opts
2011-12-01 02:48:41 +04:00
else :
Settings . I64_MODE = 0
2011-10-21 23:08:44 +04:00
2012-01-24 02:11:41 +04:00
Building . pick_llvm_opts ( 3 )
2011-10-10 08:26:50 +04:00
2010-12-30 08:33:28 +03:00
TT = % s
2011-12-21 04:38:14 +04:00
''' % (fullname, fullname, fullname, compiler, str(emcc_args), llvm_opts, embetter, quantum_size, typed_arrays, fullname))
2010-10-10 03:54:23 +04:00
return TT
2010-12-30 08:33:28 +03:00
2011-12-06 22:39:21 +04:00
# Make one run with the defaults
2011-12-21 04:38:14 +04:00
exec ( ' default = make_run( " default " , compiler=CLANG, emcc_args=[]) ' )
# Make one run with -O1, with safe heap
exec ( ' o1 = make_run( " o1 " , compiler=CLANG, emcc_args=[ " -O1 " , " -s " , " SAFE_HEAP=1 " ]) ' )
# Make one run with -O2, but without closure (we enable closure in specific tests, otherwise on everything it is too slow)
exec ( ' o2 = make_run( " o2 " , compiler=CLANG, emcc_args=[ " -O2 " , " --closure " , " 0 " ]) ' )
2011-12-06 22:39:21 +04:00
# Make custom runs with various options
2011-12-07 01:50:44 +04:00
for compiler , quantum , embetter , typed_arrays , llvm_opts in [
2011-12-10 05:37:34 +04:00
( CLANG , 1 , 1 , 0 , 0 ) ,
( CLANG , 1 , 1 , 1 , 1 ) ,
2011-12-07 01:50:44 +04:00
( CLANG , 4 , 0 , 0 , 0 ) ,
( CLANG , 4 , 0 , 0 , 1 ) ,
( CLANG , 4 , 1 , 1 , 0 ) ,
( CLANG , 4 , 1 , 1 , 1 ) ,
2011-11-17 00:49:07 +04:00
] :
2011-12-07 01:50:44 +04:00
fullname = ' s_ %d _ %d %s %s ' % (
llvm_opts , embetter , ' ' if quantum == 4 else ' _q ' + str ( quantum ) , ' ' if typed_arrays in [ 0 , 1 ] else ' _t ' + str ( typed_arrays )
2011-11-17 00:49:07 +04:00
)
2011-12-21 04:38:14 +04:00
exec ( ' %s = make_run(fullname, %r , %r , %d , %d , %d , %d ) ' % ( fullname , fullname , compiler , llvm_opts , embetter , quantum , typed_arrays ) )
2011-04-23 00:23:37 +04:00
2010-10-10 03:54:23 +04:00
del T # T is just a shape for the specific subclasses, we don't test it itself
2011-11-17 22:54:32 +04:00
class other ( RunnerCore ) :
2011-11-21 09:02:46 +04:00
def test_emcc ( self ) :
2012-02-01 07:09:32 +04:00
emcc_debug = os . environ . get ( ' EMCC_DEBUG ' )
2011-12-12 08:43:08 +04:00
def clear ( ) :
for name in os . listdir ( self . get_dir ( ) ) :
try_delete ( name )
2012-02-01 07:09:32 +04:00
if emcc_debug :
for name in os . listdir ( EMSCRIPTEN_TEMP_DIR ) :
try_delete ( os . path . join ( EMSCRIPTEN_TEMP_DIR , name ) )
2011-12-12 08:43:08 +04:00
2011-12-11 22:23:03 +04:00
for compiler in [ EMCC , EMXX ] :
2011-12-11 23:39:00 +04:00
shortcompiler = os . path . basename ( compiler )
2011-12-12 03:24:04 +04:00
suffix = ' .c ' if compiler == EMCC else ' .cpp '
2011-12-11 23:39:00 +04:00
2011-12-11 22:23:03 +04:00
# --version
2011-12-13 06:07:07 +04:00
output = Popen ( [ compiler , ' --version ' ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-11 22:23:03 +04:00
self . assertContained ( ''' emcc (Emscripten GCC-like replacement) 2.0
Copyright ( C ) 2011 the Emscripten authors .
This is free and open source software under the MIT license .
There is NO warranty ; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2011-12-11 23:54:22 +04:00
''' , output[0], output[1])
2011-12-11 22:23:03 +04:00
2011-12-11 23:39:00 +04:00
# --help
2011-12-13 06:07:07 +04:00
output = Popen ( [ compiler , ' --help ' ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-11 23:39:00 +04:00
self . assertContained ( ''' %s [options] file...
Most normal gcc / g + + options will work , for example :
- - help Display this information
- - version Display compiler version information
Options that are modified or new in % s include :
2011-12-13 01:35:51 +04:00
- O0 No optimizations ( default )
2011-12-13 22:09:59 +04:00
''' % (shortcompiler, shortcompiler), output[0], output[1])
2011-12-11 23:39:00 +04:00
2011-12-14 22:50:22 +04:00
# emcc src.cpp ==> writes a.out.js
2011-12-12 08:43:08 +04:00
clear ( )
2011-12-13 06:07:07 +04:00
output = Popen ( [ compiler , path_from_root ( ' tests ' , ' hello_world ' + suffix ) ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-12 03:24:04 +04:00
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
2011-12-14 22:50:22 +04:00
assert os . path . exists ( ' a.out.js ' ) , ' \n ' . join ( output )
self . assertContained ( ' hello, world! ' , run_js ( ' a.out.js ' ) )
2011-12-12 06:31:10 +04:00
2011-12-20 04:01:01 +04:00
# properly report source code errors, and stop there
clear ( )
assert not os . path . exists ( ' a.out.js ' )
output = Popen ( [ compiler , path_from_root ( ' tests ' , ' hello_world_error ' + suffix ) ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
assert not os . path . exists ( ' a.out.js ' ) , ' compilation failed, so no output file is expected '
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
self . assertNotContained ( ' IOError ' , output [ 1 ] ) # no python stack
self . assertNotContained ( ' Traceback ' , output [ 1 ] ) # no python stack
self . assertContained ( ' error: invalid preprocessing directive ' , output [ 1 ] )
2012-02-01 07:09:32 +04:00
self . assertContained ( " error: use of undeclared identifier ' cheez " , output [ 1 ] )
2011-12-20 04:01:01 +04:00
self . assertContained ( ' 2 errors generated ' , output [ 1 ] )
assert output [ 1 ] . split ( ' 2 errors generated. ' ) [ 1 ] . replace ( ' \n ' , ' ' ) == ' emcc: compiler frontend failed to generate LLVM bitcode, halting '
2011-12-12 08:43:08 +04:00
# emcc src.cpp -c and emcc src.cpp -o src.[o|bc] ==> should give a .bc file
2012-01-05 06:14:18 +04:00
# regression check: -o js should create "js", with bitcode content
for args in [ [ ' -c ' ] , [ ' -o ' , ' src.o ' ] , [ ' -o ' , ' src.bc ' ] , [ ' -o ' , ' js ' ] ] :
2011-12-15 05:01:16 +04:00
target = args [ 1 ] if len ( args ) == 2 else ' hello_world.o '
2011-12-12 08:43:08 +04:00
clear ( )
2012-01-27 23:51:21 +04:00
Popen ( [ compiler , path_from_root ( ' tests ' , ' hello_world ' + suffix ) ] + args , stdout = PIPE , stderr = PIPE ) . communicate ( )
2012-01-27 23:01:03 +04:00
syms = Building . llvm_nm ( target )
assert len ( syms . defs ) == 1 and ' main ' in syms . defs , ' Failed to generate valid bitcode '
if target == ' js ' : # make sure emcc can recognize the target as a bitcode file
shutil . move ( target , target + ' .bc ' )
target + = ' .bc '
output = Popen ( [ compiler , target , ' -o ' , target + ' .js ' ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-12 08:43:08 +04:00
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
2012-01-27 23:01:03 +04:00
assert os . path . exists ( target + ' .js ' ) , ' Expected %s to exist since args are %s : %s ' % ( target + ' .js ' , str ( args ) , ' \n ' . join ( output ) )
self . assertContained ( ' hello, world! ' , run_js ( target + ' .js ' ) )
2011-12-12 08:43:08 +04:00
2011-12-17 06:14:02 +04:00
# emcc src.ll ==> generates .js
clear ( )
output = Popen ( [ compiler , path_from_root ( ' tests ' , ' hello_world.ll ' ) ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
assert os . path . exists ( ' a.out.js ' ) , ' \n ' . join ( output )
self . assertContained ( ' hello, world! ' , run_js ( ' a.out.js ' ) )
2012-01-06 06:11:31 +04:00
# emcc [..] -o [path] ==> should work with absolute paths
try :
os . mkdir ( ' a_dir ' )
os . chdir ( ' a_dir ' )
os . mkdir ( ' b_dir ' )
for path in [ os . path . abspath ( os . path . join ( ' .. ' , ' file1.js ' ) ) , os . path . join ( ' b_dir ' , ' file2.js ' ) ] :
clear ( )
output = Popen ( [ compiler , path_from_root ( ' tests ' , ' hello_world.ll ' ) , ' -o ' , path ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
assert os . path . exists ( path ) , path + ' does not exist; ' + ' \n ' . join ( output )
self . assertContained ( ' hello, world! ' , run_js ( path ) )
finally :
os . chdir ( self . get_dir ( ) )
try :
shutil . rmtree ( ' a_dir ' )
except :
pass
2011-12-17 00:36:12 +04:00
# dlmalloc. dlmalloc is special in that it is the only part of libc that is (1) hard to write well, and
# very speed-sensitive. So we do not implement it in JS in library.js, instead we compile it from source
for source , has_malloc in [ ( ' hello_world ' + suffix , False ) , ( ' hello_malloc.cpp ' , True ) ] :
clear ( )
output = Popen ( [ compiler , path_from_root ( ' tests ' , source ) ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
assert os . path . exists ( ' a.out.js ' ) , ' \n ' . join ( output )
self . assertContained ( ' hello, world! ' , run_js ( ' a.out.js ' ) )
generated = open ( ' a.out.js ' ) . read ( )
assert ( ' function _malloc(bytes) { ' in generated ) == ( not has_malloc ) , ' If malloc is needed, it should be there, if not not '
2011-12-14 23:59:09 +04:00
# Optimization: emcc src.cpp -o something.js [-Ox]. -O0 is the same as not specifying any optimization setting
2011-12-17 00:36:12 +04:00
for params , opt_level , bc_params , closure , has_malloc in [ # bc params are used after compiling to bitcode
( [ ' -o ' , ' something.js ' ] , 0 , None , 0 , 1 ) ,
( [ ' -o ' , ' something.js ' , ' -O0 ' ] , 0 , None , 0 , 0 ) ,
( [ ' -o ' , ' something.js ' , ' -O1 ' ] , 1 , None , 0 , 0 ) ,
( [ ' -o ' , ' something.js ' , ' -O1 ' , ' --closure ' , ' 1 ' ] , 1 , None , 1 , 0 ) ,
( [ ' -o ' , ' something.js ' , ' -O2 ' ] , 2 , None , 1 , 1 ) ,
( [ ' -o ' , ' something.js ' , ' -O2 ' , ' --closure ' , ' 0 ' ] , 2 , None , 0 , 0 ) ,
( [ ' -o ' , ' something.js ' , ' -O3 ' ] , 3 , None , 1 , 1 ) ,
( [ ' -o ' , ' something.js ' , ' -O3 ' , ' --closure ' , ' 0 ' ] , 3 , None , 0 , 0 ) ,
2011-12-15 02:16:41 +04:00
# and, test compiling to bitcode first
2011-12-17 00:36:12 +04:00
( [ ' -o ' , ' something.bc ' ] , 0 , [ ] , 0 , 0 ) ,
( [ ' -o ' , ' something.bc ' ] , 0 , [ ' -O0 ' ] , 0 , 0 ) ,
( [ ' -o ' , ' something.bc ' ] , 1 , [ ' -O1 ' ] , 0 , 0 ) ,
( [ ' -o ' , ' something.bc ' ] , 2 , [ ' -O2 ' ] , 1 , 0 ) ,
( [ ' -o ' , ' something.bc ' ] , 3 , [ ' -O3 ' ] , 1 , 0 ) ,
2012-01-08 06:36:42 +04:00
( [ ' -O1 ' , ' -o ' , ' something.bc ' ] , 0 , [ ] , 0 , 0 ) , # -Ox is ignored and warned about
2011-12-14 23:59:09 +04:00
] :
2011-12-15 09:17:53 +04:00
#print params, opt_level, bc_params, closure
2011-12-13 01:35:51 +04:00
clear ( )
2011-12-17 00:36:12 +04:00
output = Popen ( [ compiler , path_from_root ( ' tests ' , ' hello_world_loop ' + ( ' _malloc ' if has_malloc else ' ' ) + ' .cpp ' ) ] + params ,
2011-12-13 06:07:07 +04:00
stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-13 01:35:51 +04:00
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
2011-12-15 02:16:41 +04:00
if bc_params is not None :
2012-01-08 06:36:42 +04:00
if ' -O1 ' in params and ' something.bc ' in params :
assert ' warning: -Ox flags ignored, since not generating JavaScript ' in output [ 1 ]
2011-12-15 02:16:41 +04:00
assert os . path . exists ( ' something.bc ' ) , output [ 1 ]
output = Popen ( [ compiler , ' something.bc ' , ' -o ' , ' something.js ' ] + bc_params , stdout = PIPE , stderr = PIPE ) . communicate ( )
assert os . path . exists ( ' something.js ' ) , output [ 1 ]
2011-12-13 04:55:42 +04:00
assert ( ' Warning: Applying some potentially unsafe optimizations! ' in output [ 1 ] ) == ( opt_level > = 3 ) , ' unsafe warning should appear in opt >= 3 '
2011-12-13 01:35:51 +04:00
self . assertContained ( ' hello, world! ' , run_js ( ' something.js ' ) )
2011-12-13 05:41:03 +04:00
# Verify optimization level etc. in the generated code
2011-12-13 01:35:51 +04:00
# XXX these are quite sensitive, and will need updating when code generation changes
generated = open ( ' something.js ' ) . read ( ) # TODO: parse out the _main function itself, not support code, if the tests below need that some day
2011-12-13 05:41:03 +04:00
assert ' new Uint16Array ' in generated and ' new Uint32Array ' in generated , ' typed arrays 2 should be used by default '
2011-12-13 01:35:51 +04:00
assert ' SAFE_HEAP ' not in generated , ' safe heap should not be used by default '
2011-12-13 05:41:03 +04:00
assert ' : while( ' not in generated , ' when relooping we also js-optimize, so there should be no labelled whiles '
2011-12-15 09:17:53 +04:00
if closure :
2012-01-13 06:25:01 +04:00
assert ' Module._main= ' in generated , ' closure compiler should have been run (and output should be minified) '
2011-12-14 02:08:44 +04:00
else :
# closure has not been run, we can do some additional checks. TODO: figure out how to do these even with closure
2011-12-16 06:39:03 +04:00
assert ' Module._main = ' not in generated , ' closure compiler should not have been run '
# XXX find a way to test this: assert ('& 255' in generated or '&255' in generated) == (opt_level <= 2), 'corrections should be in opt <= 2'
2011-12-15 09:17:53 +04:00
assert ( ' (__label__) ' in generated ) == ( opt_level < = 1 ) , ' relooping should be in opt >= 2 '
2012-01-05 20:43:28 +04:00
assert ( ' assert(STACKTOP < STACK_MAX ' in generated ) == ( opt_level == 0 ) , ' assertions should be in opt == 0 '
2012-02-01 07:09:32 +04:00
assert ' var $i; ' in generated or ' var $storemerge3; ' in generated or ' var $storemerge4; ' in generated or ' var $i_04; ' in generated , ' micro opts should always be on '
2012-01-30 07:39:34 +04:00
if opt_level > = 1 :
2012-02-01 07:09:32 +04:00
assert ' HEAP8[HEAP32[ ' in generated or ' HEAP8[$vla1 + $storemerge4 / 2 | 0] ' in generated or ' HEAP8[$vla1 + ($storemerge4 / 2 | 0)] ' in generated or ' HEAP8[$vla1 + $i_04 / 2 | 0] ' in generated or ' HEAP8[$vla1 + ($i_04 / 2 | 0)] ' in generated , ' eliminator should create compound expressions, and fewer one-time vars '
2011-12-14 02:08:44 +04:00
assert ( ' _puts( ' in generated ) == ( opt_level > = 1 ) , ' with opt >= 1, llvm opts are run and they should optimize printf to puts '
2011-12-17 00:36:12 +04:00
assert ( ' function _malloc(bytes) { ' in generated ) == ( not has_malloc ) , ' If malloc is needed, it should be there, if not not '
2012-01-13 06:25:01 +04:00
assert ' function _main() { ' in generated , ' Should be unminified, including whitespace '
2012-02-02 06:37:13 +04:00
assert ' function _dump ' in generated , ' No inlining by default '
2011-12-13 01:35:51 +04:00
2011-12-13 22:09:59 +04:00
# emcc -s RELOOP=1 src.cpp ==> should pass -s to emscripten.py. --typed-arrays is a convenient alias for -s USE_TYPED_ARRAYS
2011-12-13 06:27:53 +04:00
for params , test , text in [
2012-02-02 06:37:13 +04:00
( [ ' -s ' , ' INLINING_LIMIT=0 ' ] , lambda generated : ' function _dump ' in generated , ' no inlining without opts ' ) ,
( [ ' -O1 ' , ' -s ' , ' INLINING_LIMIT=0 ' ] , lambda generated : ' function _dump ' not in generated , ' inlining ' ) ,
2011-12-13 06:27:53 +04:00
( [ ' -s ' , ' USE_TYPED_ARRAYS=0 ' ] , lambda generated : ' new Int32Array ' not in generated , ' disable typed arrays ' ) ,
( [ ' -s ' , ' USE_TYPED_ARRAYS=1 ' ] , lambda generated : ' IHEAPU = ' in generated , ' typed arrays 1 selected ' ) ,
( [ ] , lambda generated : ' Module[ " _dump " ] ' not in generated , ' dump is not exported by default ' ) ,
2011-12-13 22:38:06 +04:00
( [ ' -s ' , ' EXPORTED_FUNCTIONS=[ " _main " , " _dump " ] ' ] , lambda generated : ' Module[ " _dump " ] ' in generated , ' dump is now exported ' ) ,
2011-12-13 22:09:59 +04:00
( [ ' --typed-arrays ' , ' 0 ' ] , lambda generated : ' new Int32Array ' not in generated , ' disable typed arrays ' ) ,
( [ ' --typed-arrays ' , ' 1 ' ] , lambda generated : ' IHEAPU = ' in generated , ' typed arrays 1 selected ' ) ,
2011-12-14 02:08:44 +04:00
( [ ' --typed-arrays ' , ' 2 ' ] , lambda generated : ' new Uint16Array ' in generated and ' new Uint32Array ' in generated , ' typed arrays 2 selected ' ) ,
( [ ' --llvm-opts ' , ' 1 ' ] , lambda generated : ' _puts( ' in generated , ' llvm opts requested ' ) ,
2011-12-13 06:27:53 +04:00
] :
clear ( )
2011-12-14 06:23:00 +04:00
output = Popen ( [ compiler , path_from_root ( ' tests ' , ' hello_world_loop.cpp ' ) , ' -o ' , ' a.out.js ' ] + params , stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-13 06:27:53 +04:00
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
assert os . path . exists ( ' a.out.js ' ) , ' \n ' . join ( output )
self . assertContained ( ' hello, world! ' , run_js ( ' a.out.js ' ) )
assert test ( open ( ' a.out.js ' ) . read ( ) ) , text
2011-12-14 23:39:53 +04:00
# Compiling two source files into a final JS.
2011-12-14 04:32:40 +04:00
for args , target in [ ( [ ] , ' a.out.js ' ) , ( [ ' -o ' , ' combined.js ' ] , ' combined.js ' ) ] :
clear ( )
output = Popen ( [ compiler , path_from_root ( ' tests ' , ' twopart_main.cpp ' ) , path_from_root ( ' tests ' , ' twopart_side.cpp ' ) ] + args ,
stdout = PIPE , stderr = PIPE ) . communicate ( )
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
assert os . path . exists ( target ) , ' \n ' . join ( output )
self . assertContained ( ' side got: hello from main, over ' , run_js ( target ) )
2011-12-14 06:23:00 +04:00
# Compiling two files with -c will generate separate .bc files
clear ( )
2011-12-14 23:39:53 +04:00
output = Popen ( [ compiler , path_from_root ( ' tests ' , ' twopart_main.cpp ' ) , path_from_root ( ' tests ' , ' twopart_side.cpp ' ) , ' -c ' ] + args ,
2011-12-14 06:23:00 +04:00
stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-14 23:12:19 +04:00
if ' -o ' in args :
# specifying -o and -c is an error
assert ' fatal error ' in output [ 1 ] , output [ 1 ]
continue
2011-12-15 05:01:16 +04:00
assert os . path . exists ( ' twopart_main.o ' ) , ' \n ' . join ( output )
assert os . path . exists ( ' twopart_side.o ' ) , ' \n ' . join ( output )
2011-12-14 06:23:00 +04:00
assert not os . path . exists ( target ) , ' We should only have created bitcode here: ' + ' \n ' . join ( output )
# Compiling one of them alone is expected to fail
2011-12-15 05:01:16 +04:00
output = Popen ( [ compiler , ' twopart_main.o ' ] + args , stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-14 06:23:00 +04:00
assert os . path . exists ( target ) , ' \n ' . join ( output )
#print '\n'.join(output)
2011-12-14 23:39:53 +04:00
self . assertContained ( ' is not a function ' , run_js ( target , stderr = STDOUT ) )
try_delete ( target )
2011-12-14 06:23:00 +04:00
# Combining those bc files into js should work
2011-12-15 05:01:16 +04:00
output = Popen ( [ compiler , ' twopart_main.o ' , ' twopart_side.o ' ] + args , stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-14 06:23:00 +04:00
assert os . path . exists ( target ) , ' \n ' . join ( output )
2011-12-14 23:39:53 +04:00
self . assertContained ( ' side got: hello from main, over ' , run_js ( target ) )
2011-12-14 06:23:00 +04:00
2011-12-15 06:46:48 +04:00
# Combining bc files into another bc should also work
try_delete ( target )
assert not os . path . exists ( target )
output = Popen ( [ compiler , ' twopart_main.o ' , ' twopart_side.o ' , ' -o ' , ' combined.bc ' ] + args , stdout = PIPE , stderr = PIPE ) . communicate ( )
2012-01-27 23:01:03 +04:00
syms = Building . llvm_nm ( ' combined.bc ' )
assert len ( syms . defs ) == 2 and ' main ' in syms . defs , ' Failed to generate valid bitcode '
output = Popen ( [ compiler , ' combined.bc ' , ' -o ' , ' combined.bc.js ' ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
assert os . path . exists ( ' combined.bc.js ' ) , ' Expected %s to exist ' % ( ' combined.bc.js ' )
self . assertContained ( ' side got: hello from main, over ' , run_js ( ' combined.bc.js ' ) )
2011-12-15 06:46:48 +04:00
2012-01-05 02:36:02 +04:00
# --js-transform <transform>
clear ( )
trans = os . path . join ( self . get_dir ( ) , ' t.py ' )
trans_file = open ( trans , ' w ' )
trans_file . write ( '''
import sys
f = open ( sys . argv [ 1 ] , ' w ' )
f . write ( ' transformed! ' )
f . close ( )
''' )
trans_file . close ( )
output = Popen ( [ compiler , path_from_root ( ' tests ' , ' hello_world ' + suffix ) , ' --js-transform ' , ' python t.py ' ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
assert open ( ' a.out.js ' ) . read ( ) == ' transformed! ' , ' Transformed output must be as expected '
# TODO: Add in files test a clear example of using disablePermissions, and link to it from the wiki
2011-12-14 23:59:09 +04:00
# TODO: test normal project linking, static and dynamic: get_library should not need to be told what to link!
2011-12-17 05:46:05 +04:00
# TODO: deprecate llvm optimizations, dlmalloc, etc. in emscripten.py.
2011-11-21 09:02:46 +04:00
2012-01-28 03:04:06 +04:00
# For browser tests which report their success
def run_test_server ( expectedResult ) :
class TestServerHandler ( BaseHTTPServer . BaseHTTPRequestHandler ) :
def do_GET ( s ) :
assert s . path == expectedResult , ' Expected %s , got %s ' % ( expectedResult , s . path )
httpd = BaseHTTPServer . HTTPServer ( ( ' localhost ' , 8888 ) , TestServerHandler )
2012-02-02 00:15:50 +04:00
httpd . handle_request ( )
2012-01-28 03:04:06 +04:00
2011-12-13 04:02:19 +04:00
# Finally, do some web browser tests
2012-01-28 03:04:06 +04:00
def run_browser ( html_file , message , expectedResult = None ) :
2012-01-28 00:18:32 +04:00
webbrowser . open_new ( os . path . abspath ( html_file ) )
2011-12-13 04:02:19 +04:00
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..) '
2012-01-28 03:04:06 +04:00
if expectedResult is not None :
run_test_server ( expectedResult )
else :
time . sleep ( 5 )
2011-12-13 04:02:19 +04:00
print ' (moving on..) '
# test HTML generation.
2011-12-12 23:24:16 +04:00
clear ( )
2011-12-13 06:07:07 +04:00
output = Popen ( [ EMCC , path_from_root ( ' tests ' , ' hello_world_sdl.cpp ' ) , ' -o ' , ' something.html ' ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-12 23:24:16 +04:00
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
assert os . path . exists ( ' something.html ' ) , output
2011-12-13 04:02:19 +04:00
run_browser ( ' something.html ' , ' You should see " hello, world! " and a colored cube. ' )
# And test running in a web worker
clear ( )
2011-12-13 06:07:07 +04:00
output = Popen ( [ EMCC , path_from_root ( ' tests ' , ' hello_world_worker.cpp ' ) , ' -o ' , ' worker.js ' ] , stdout = PIPE , stderr = PIPE ) . communicate ( )
2011-12-13 04:02:19 +04:00
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
assert os . path . exists ( ' worker.js ' ) , output
self . assertContained ( ' you should not see this text when in a worker! ' , run_js ( ' worker.js ' ) ) # code should run standalone
html_file = open ( ' main.html ' , ' w ' )
html_file . write ( '''
< html >
< body >
< script >
var worker = new Worker ( ' worker.js ' ) ;
worker . onmessage = function ( event ) {
document . write ( " <hr>Called back by the worker: " + event . data + " <br><hr> " ) ;
} ;
< / script >
< / body >
< / html >
''' )
html_file . close ( )
run_browser ( ' main.html ' , ' You should see that the worker was called, and said " hello from worker! " ' )
2011-12-12 23:24:16 +04:00
2012-01-28 01:57:56 +04:00
# test the OpenGL ES implementation
clear ( )
2012-01-28 03:04:06 +04:00
output = Popen ( [ EMCC , path_from_root ( ' tests ' , ' hello_world_gles.c ' ) , ' -o ' , ' something.html ' ,
' -DHAVE_BUILTIN_SINCOS ' ,
' --shell-file ' , path_from_root ( ' tests ' , ' hello_world_gles_shell.html ' ) ] ,
stdout = PIPE , stderr = PIPE ) . communicate ( )
2012-01-28 01:57:56 +04:00
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
assert os . path . exists ( ' something.html ' ) , output
2012-01-28 03:04:06 +04:00
run_browser ( ' something.html ' , ' You should see animating gears. ' , ' /report_gl_result?true ' )
2012-01-28 01:57:56 +04:00
2012-02-02 00:15:50 +04:00
# Make sure that OpenGL ES is not available if typed arrays are not used
clear ( )
output = Popen ( [ EMCC , path_from_root ( ' tests ' , ' hello_world_gles.c ' ) , ' -o ' , ' something.html ' ,
' -DHAVE_BUILTIN_SINCOS ' ,
' -s ' , ' USE_TYPED_ARRAYS=0 ' ,
' --shell-file ' , path_from_root ( ' tests ' , ' hello_world_gles_shell.html ' ) ] ,
stdout = PIPE , stderr = PIPE ) . communicate ( )
assert len ( output [ 0 ] ) == 0 , output [ 0 ]
assert os . path . exists ( ' something.html ' ) , output
run_browser ( ' something.html ' , ' You should not see animating gears. ' , ' /report_gl_result?false ' )
2011-08-24 05:25:31 +04:00
def test_eliminator ( self ) :
input = open ( path_from_root ( ' tools ' , ' eliminator ' , ' eliminator-test.js ' ) ) . read ( )
expected = open ( path_from_root ( ' tools ' , ' eliminator ' , ' eliminator-test-output.js ' ) ) . read ( )
2012-01-11 01:31:25 +04:00
output = Popen ( [ NODE_JS , COFFEESCRIPT , VARIABLE_ELIMINATOR ] , stdin = PIPE , stdout = PIPE ) . communicate ( input ) [ 0 ]
2011-11-01 04:38:27 +04:00
self . assertIdentical ( expected , output )
2011-08-24 05:25:31 +04:00
2012-01-11 05:54:59 +04:00
def test_fix_closure ( self ) :
input = path_from_root ( ' tests ' , ' test-fix-closure.js ' )
expected = path_from_root ( ' tests ' , ' test-fix-closure.out.js ' )
Popen ( [ ' python ' , path_from_root ( ' tools ' , ' fix_closure.py ' ) , input , ' out.js ' ] ) . communicate ( input )
output = open ( ' out.js ' ) . read ( )
2012-01-12 00:13:02 +04:00
assert ' 0,zzz_Q_39fa,0 ' in output
2012-01-11 06:31:54 +04:00
assert ' function(a,c) ' not in output # should be uninlined, so it gets a name
2012-01-11 05:54:59 +04:00
assert run_js ( input ) == run_js ( ' out.js ' )
2011-11-20 09:38:22 +04:00
def test_js_optimizer ( self ) :
2011-12-27 02:41:32 +04:00
for input , expected , passes in [
2012-01-11 07:46:31 +04:00
( path_from_root ( ' tools ' , ' test-js-optimizer.js ' ) , open ( path_from_root ( ' tools ' , ' test-js-optimizer-output.js ' ) ) . read ( ) ,
2011-12-29 00:04:42 +04:00
[ ' hoistMultiples ' , ' loopOptimizer ' , ' unGlobalize ' , ' removeAssignsToUndefined ' , ' simplifyExpressionsPre ' , ' simplifyExpressionsPost ' ] ) ,
2012-01-11 07:46:31 +04:00
( path_from_root ( ' tools ' , ' test-js-optimizer-t2c.js ' ) , open ( path_from_root ( ' tools ' , ' test-js-optimizer-t2c-output.js ' ) ) . read ( ) ,
2011-12-31 07:02:16 +04:00
[ ' simplifyExpressionsPre ' , ' optimizeShiftsConservative ' ] ) ,
2012-01-11 07:46:31 +04:00
( path_from_root ( ' tools ' , ' test-js-optimizer-t2.js ' ) , open ( path_from_root ( ' tools ' , ' test-js-optimizer-t2-output.js ' ) ) . read ( ) ,
2011-12-31 21:41:15 +04:00
[ ' simplifyExpressionsPre ' , ' optimizeShiftsAggressive ' ] ) ,
2011-12-27 02:41:32 +04:00
] :
2012-01-11 07:46:31 +04:00
output = Popen ( [ NODE_JS , JS_OPTIMIZER , input ] + passes , stdin = PIPE , stdout = PIPE ) . communicate ( ) [ 0 ]
2011-12-27 02:41:32 +04:00
self . assertIdentical ( expected , output . replace ( ' \n \n ' , ' \n ' ) )
2011-11-20 09:38:22 +04:00
2011-12-18 23:34:19 +04:00
elif ' benchmark ' in str ( sys . argv ) :
2011-08-30 22:41:52 +04:00
# Benchmarks. Run them with argument |benchmark|. To run a specific test, do
# |benchmark.test_X|.
2010-10-10 03:54:23 +04:00
2011-10-30 23:55:36 +04:00
fingerprint = [ time . asctime ( ) ]
try :
fingerprint . append ( ' em: ' + Popen ( [ ' git ' , ' show ' ] , stdout = PIPE ) . communicate ( ) [ 0 ] . split ( ' \n ' ) [ 0 ] )
except :
pass
try :
d = os . getcwd ( )
os . chdir ( os . path . expanduser ( ' ~/Dev/mozilla-central ' ) )
fingerprint . append ( ' sm: ' + filter ( lambda line : ' changeset ' in line ,
Popen ( [ ' hg ' , ' tip ' ] , stdout = PIPE ) . communicate ( ) [ 0 ] . split ( ' \n ' ) ) [ 0 ] )
except :
pass
finally :
os . chdir ( d )
print ' Running Emscripten benchmarks... [ %s ] ' % ' | ' . join ( fingerprint )
2011-01-02 09:59:55 +03:00
2010-10-10 03:54:23 +04:00
sys . argv = filter ( lambda x : x != ' benchmark ' , sys . argv )
2010-10-13 07:38:12 +04:00
assert ( os . path . exists ( CLOSURE_COMPILER ) )
2011-10-12 06:04:06 +04:00
try :
index = SPIDERMONKEY_ENGINE . index ( " options( ' strict ' ) " )
SPIDERMONKEY_ENGINE = SPIDERMONKEY_ENGINE [ : index - 1 ] + SPIDERMONKEY_ENGINE [ index + 1 : ] # closure generates non-strict
except :
pass
2011-05-25 21:53:50 +04:00
2011-10-27 07:41:51 +04:00
Building . COMPILER = CLANG
2011-12-04 22:38:17 +04:00
2011-12-18 04:48:26 +04:00
# Pick the JS engine to benchmark. If you specify one, it will be picked. For example, python tests/runner.py benchmark SPIDERMONKEY_ENGINE
JS_ENGINE = JS_ENGINES [ 0 ]
for i in range ( 1 , len ( sys . argv ) ) :
arg = sys . argv [ i ]
2011-12-18 23:34:19 +04:00
if not arg . startswith ( ' benchmark.test_ ' ) :
2011-12-18 04:48:26 +04:00
JS_ENGINE = eval ( arg )
sys . argv [ i ] = None
sys . argv = filter ( lambda arg : arg is not None , sys . argv )
2011-12-04 22:38:17 +04:00
print ' Benchmarking JS engine: ' , JS_ENGINE
2010-10-10 22:49:50 +04:00
2011-10-27 07:41:51 +04:00
Building . COMPILER_TEST_OPTS = [ ]
2011-02-21 06:03:11 +03:00
2011-11-02 04:10:06 +04:00
TEST_REPS = 10
2012-01-10 04:49:19 +04:00
TOTAL_TESTS = 8
2010-10-10 03:54:23 +04:00
tests_done = 0
2011-10-12 04:42:00 +04:00
total_times = map ( lambda x : 0. , range ( TOTAL_TESTS ) )
total_native_times = map ( lambda x : 0. , range ( TOTAL_TESTS ) )
2010-10-10 03:54:23 +04:00
2011-08-30 22:41:52 +04:00
class benchmark ( RunnerCore ) :
2011-11-28 00:29:59 +04:00
def print_stats ( self , times , native_times , last = False ) :
2010-10-10 03:54:23 +04:00
mean = sum ( times ) / len ( times )
squared_times = map ( lambda x : x * x , times )
mean_of_squared = sum ( squared_times ) / len ( times )
std = math . sqrt ( mean_of_squared - mean * mean )
2011-11-28 00:29:59 +04:00
sorted_times = times [ : ]
sorted_times . sort ( )
median = sum ( sorted_times [ len ( sorted_times ) / 2 - 1 : len ( sorted_times ) / 2 + 1 ] ) / 2
2011-06-12 00:52:03 +04:00
mean_native = sum ( native_times ) / len ( native_times )
squared_native_times = map ( lambda x : x * x , native_times )
mean_of_squared_native = sum ( squared_native_times ) / len ( native_times )
std_native = math . sqrt ( mean_of_squared_native - mean_native * mean_native )
2011-11-28 00:29:59 +04:00
sorted_native_times = native_times [ : ]
sorted_native_times . sort ( )
median_native = sum ( sorted_native_times [ len ( sorted_native_times ) / 2 - 1 : len ( sorted_native_times ) / 2 + 1 ] ) / 2
2011-06-12 00:52:03 +04:00
2011-11-28 00:29:59 +04:00
final = mean / mean_native
if last :
norm = 0
2011-10-12 04:42:00 +04:00
for i in range ( len ( times ) ) :
2011-11-28 00:29:59 +04:00
norm + = times [ i ] / native_times [ i ]
norm / = len ( times )
print
print ' JavaScript: %.3f Native: %.3f Ratio: %.3f Normalized ratio: %.3f ' % ( mean , mean_native , final , norm )
return
2011-10-12 04:42:00 +04:00
2011-06-12 00:52:03 +04:00
print
2011-11-28 00:29:59 +04:00
print ' JavaScript: mean: %.3f (+- %.3f ) secs median: %.3f range: %.3f - %.3f (noise: %3.3f %% ) ( %d runs) ' % ( mean , std , median , min ( times ) , max ( times ) , 100 * std / mean , TEST_REPS )
print ' Native : mean: %.3f (+- %.3f ) secs median: %.3f range: %.3f - %.3f (noise: %3.3f %% ) JS is %.2f X slower ' % ( mean_native , std_native , median_native , min ( native_times ) , max ( native_times ) , 100 * std_native / mean_native , final )
2010-10-10 03:54:23 +04:00
2011-12-14 09:14:52 +04:00
def do_benchmark ( self , src , args = [ ] , expected_output = ' FAIL ' , emcc_args = [ ] ) :
2010-10-10 03:54:23 +04:00
dirname = self . get_dir ( )
filename = os . path . join ( dirname , ' src.cpp ' )
2011-12-14 09:14:52 +04:00
f = open ( filename , ' w ' )
f . write ( src )
f . close ( )
final_filename = os . path . join ( dirname , ' src.js ' )
2011-12-18 23:34:19 +04:00
try_delete ( final_filename )
2012-02-02 05:41:37 +04:00
output = Popen ( [ EMCC , filename , ' -O3 ' ,
2012-02-02 06:37:13 +04:00
' -s ' , ' INLINING_LIMIT=0 ' ,
2011-12-14 09:14:52 +04:00
' -s ' , ' TOTAL_MEMORY=100*1024*1024 ' , ' -s ' , ' FAST_MEMORY=10*1024*1024 ' ,
2012-01-03 07:21:57 +04:00
' -o ' , final_filename ] + emcc_args , stdout = PIPE , stderr = self . stderr_redirect ) . communicate ( )
2011-12-18 23:34:19 +04:00
assert os . path . exists ( final_filename ) , ' Failed to compile file: ' + ' \n ' . join ( output )
2010-10-13 07:38:12 +04:00
2011-06-12 00:52:03 +04:00
# Run JS
2011-10-12 04:42:00 +04:00
global total_times , tests_done
2010-10-10 03:54:23 +04:00
times = [ ]
for i in range ( TEST_REPS ) :
start = time . time ( )
2011-01-20 09:57:53 +03:00
js_output = self . run_generated_code ( JS_ENGINE , final_filename , args , check_timeout = False )
2010-10-10 03:54:23 +04:00
curr = time . time ( ) - start
times . append ( curr )
2011-10-12 04:42:00 +04:00
total_times [ tests_done ] + = curr
2010-10-15 10:07:23 +04:00
if i == 0 :
# Sanity check on output
self . assertContained ( expected_output , js_output )
2010-10-10 03:54:23 +04:00
2011-06-12 00:52:03 +04:00
# Run natively
self . build_native ( filename )
global total_native_times
native_times = [ ]
for i in range ( TEST_REPS ) :
start = time . time ( )
self . run_native ( filename , args )
curr = time . time ( ) - start
native_times . append ( curr )
2011-10-12 04:42:00 +04:00
total_native_times [ tests_done ] + = curr
2011-06-12 00:52:03 +04:00
self . print_stats ( times , native_times )
2010-10-10 03:54:23 +04:00
tests_done + = 1
if tests_done == TOTAL_TESTS :
2011-11-28 00:29:59 +04:00
print ' Total stats: ' ,
self . print_stats ( total_times , total_native_times , last = True )
2011-06-11 23:03:10 +04:00
2011-01-03 08:26:22 +03:00
def test_primes ( self ) :
src = '''
#include<stdio.h>
#include<math.h>
int main ( ) {
int primes = 0 , curri = 2 ;
2011-06-12 00:52:03 +04:00
while ( primes < 100000 ) {
2011-01-03 08:26:22 +03:00
int ok = true ;
for ( int j = 2 ; j < sqrtf ( curri ) ; j + + ) {
if ( curri % j == 0 ) {
ok = false ;
break ;
}
}
if ( ok ) {
primes + + ;
}
curri + + ;
}
printf ( " lastprime: %d . \\ n " , curri - 1 ) ;
return 1 ;
}
'''
2011-11-17 06:43:29 +04:00
self . do_benchmark ( src , [ ] , ' lastprime: 1297001. ' )
2011-01-03 08:26:22 +03:00
2011-06-12 06:05:20 +04:00
def test_memops ( self ) :
src = '''
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main ( ) {
2011-06-30 01:54:23 +04:00
int N = 1024 * 1024 ;
2011-07-02 06:56:14 +04:00
int M = 190 ;
2011-06-12 06:05:20 +04:00
int final = 0 ;
char * buf = ( char * ) malloc ( N ) ;
2011-06-30 01:54:23 +04:00
for ( int t = 0 ; t < M ; t + + ) {
2011-06-12 06:05:20 +04:00
for ( int i = 0 ; i < N ; i + + )
2011-06-30 01:54:23 +04:00
buf [ i ] = ( i + final ) % 256 ;
2011-06-12 06:05:20 +04:00
for ( int i = 0 ; i < N ; i + + )
final + = buf [ i ] & 1 ;
2011-06-30 01:54:23 +04:00
final = final % 1000 ;
2011-06-12 06:05:20 +04:00
}
printf ( " final: %d . \\ n " , final ) ;
return 1 ;
}
'''
2011-11-17 06:43:29 +04:00
self . do_benchmark ( src , [ ] , ' final: 720. ' )
2011-06-12 06:05:20 +04:00
2012-01-10 04:49:19 +04:00
def test_copy ( self ) :
2012-01-07 06:27:58 +04:00
src = r '''
#include<stdio.h>
struct vec {
int x , y , z ;
int r , g , b ;
vec ( int x_ , int y_ , int z_ , int r_ , int g_ , int b_ ) : x ( x_ ) , y ( y_ ) , z ( z_ ) , r ( r_ ) , g ( g_ ) , b ( b_ ) { }
static vec add ( vec a , vec b ) {
return vec ( a . x + b . x , a . y + b . y , a . z + b . z , a . r + b . r , a . g + b . g , a . b + b . b ) ;
}
void norm ( ) {
x % = 1024 ;
y % = 1024 ;
z % = 1024 ;
r % = 1024 ;
b % = 1024 ;
g % = 1024 ;
}
int sum ( ) { return x + y + z + r + g + b ; }
} ;
int main ( ) {
int total = 0 ;
2012-01-10 04:49:19 +04:00
for ( int i = 0 ; i < 1250 ; i + + ) {
2012-01-07 06:27:58 +04:00
for ( int j = 0 ; j < 1000 ; j + + ) {
vec c ( i , i + i % 10 , j * 2 , i % 255 , j % 120 , i % 15 ) ;
vec d ( j + i % 10 , j * 2 , j % 255 , i % 120 , j % 15 , j ) ;
vec e = c ;
c . norm ( ) ;
d . norm ( ) ;
vec f = vec : : add ( c , d ) ;
f = vec : : add ( e , f ) ;
f . norm ( ) ;
f = vec : : add ( d , f ) ;
total + = f . sum ( ) % 100 ;
total % = 10240 ;
}
}
printf ( " sum: %d \n " , total ) ;
return 1 ;
}
'''
2012-01-10 04:49:19 +04:00
self . do_benchmark ( src , [ ] , ' sum:9928 \n ' , emcc_args = [ ' -s ' , ' QUANTUM_SIZE=4 ' , ' -s ' , ' USE_TYPED_ARRAYS=2 ' ] )
2012-01-07 06:27:58 +04:00
2010-10-10 03:54:23 +04:00
def test_fannkuch ( self ) :
2011-01-15 09:44:52 +03:00
src = open ( path_from_root ( ' tests ' , ' fannkuch.cpp ' ) , ' r ' ) . read ( )
2011-11-17 06:43:29 +04:00
self . do_benchmark ( src , [ ' 10 ' ] , ' Pfannkuchen(10) = 38. ' )
2010-10-10 03:54:23 +04:00
2011-11-25 00:31:28 +04:00
def test_corrections ( self ) :
2011-11-27 01:58:30 +04:00
src = r '''
2011-11-25 00:31:28 +04:00
#include<stdio.h>
2011-11-25 08:50:45 +04:00
#include<math.h>
2011-11-25 00:31:28 +04:00
int main ( ) {
2011-11-27 01:58:30 +04:00
int N = 4100 ;
int M = 4100 ;
2011-11-25 03:44:56 +04:00
unsigned int f = 0 ;
2011-11-27 01:58:30 +04:00
unsigned short s = 0 ;
2011-11-25 00:31:28 +04:00
for ( int t = 0 ; t < M ; t + + ) {
for ( int i = 0 ; i < N ; i + + ) {
2011-11-25 03:44:56 +04:00
f + = i / ( ( t % 5 ) + 1 ) ;
if ( f > 1000 ) f / = ( t % 3 ) + 1 ;
2011-11-25 08:50:45 +04:00
if ( i % 4 == 0 ) f + = sqrtf ( i ) * ( i % 8 == 0 ? 1 : - 1 ) ;
2011-11-27 01:58:30 +04:00
s + = ( short ( f ) * short ( f ) ) % 256 ;
2011-11-25 00:31:28 +04:00
}
}
2011-11-27 01:58:30 +04:00
printf ( " final: %d : %d . \n " , f , s ) ;
2011-11-25 00:31:28 +04:00
return 1 ;
}
'''
2011-12-14 09:14:52 +04:00
self . do_benchmark ( src , [ ] , ' final: 826:14324. ' , emcc_args = [ ' -s ' , ' CORRECT_SIGNS=1 ' , ' -s ' , ' CORRECT_OVERFLOWS=1 ' , ' -s ' , ' CORRECT_ROUNDINGS=1 ' ] )
2011-11-25 00:31:28 +04:00
2012-02-01 23:35:43 +04:00
def fasta ( self , double_rep ) :
src = open ( path_from_root ( ' tests ' , ' fasta.cpp ' ) , ' r ' ) . read ( ) . replace ( ' double ' , double_rep )
self . do_benchmark ( src , [ ' 2100000 ' ] , ''' GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA \n TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT \n AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG \n GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG \n CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT \n GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA \n GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA \n TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG \n AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA \n GCCTGGGCGA ''' )
2011-12-21 01:41:47 +04:00
2012-02-01 23:35:43 +04:00
def test_fasta_float ( self ) :
self . fasta ( ' float ' )
2011-12-21 01:41:47 +04:00
2012-02-01 23:35:43 +04:00
def zzztest_fasta_double ( self ) :
self . fasta ( ' double ' )
2011-04-02 21:35:22 +04:00
2011-11-07 22:17:11 +04:00
def test_skinning ( self ) :
src = open ( path_from_root ( ' tests ' , ' skinning_test_no_simd.cpp ' ) , ' r ' ) . read ( )
2011-11-17 06:43:29 +04:00
self . do_benchmark ( src , [ ' 10000 ' , ' 1000 ' ] , ' blah=0.000000 ' )
2011-11-07 22:17:11 +04:00
2011-06-17 03:19:58 +04:00
def test_dlmalloc ( self ) :
2011-12-14 09:21:09 +04:00
# XXX This seems to have regressed slightly with emcc. Are -g and the signs lines passed properly?
2012-01-19 07:39:01 +04:00
src = open ( path_from_root ( ' system ' , ' lib ' , ' dlmalloc.c ' ) , ' r ' ) . read ( ) + ' \n \n \n ' + open ( path_from_root ( ' tests ' , ' dlmalloc_test.c ' ) , ' r ' ) . read ( )
2011-12-14 09:14:52 +04:00
self . do_benchmark ( src , [ ' 400 ' , ' 400 ' ] , ' *400,0* ' , emcc_args = [ ' -g ' , ' -s ' , ' CORRECT_SIGNS=2 ' , ' -s ' , ' CORRECT_SIGNS_LINES=[4820, 4195, 4250, 4203, 4209, 4239, 4231] ' ] )
2011-12-18 23:34:19 +04:00
elif ' sanity ' in str ( sys . argv ) :
# Run some sanity checks on the test runner and emcc.
sys . argv = filter ( lambda x : x != ' sanity ' , sys . argv )
2011-12-19 02:47:33 +04:00
print
print ' Running sanity checks. '
2012-01-29 00:29:43 +04:00
print ' WARNING: This will modify %s , and in theory can break it although it should be restored properly. A backup will be saved in %s _backup ' % ( EM_CONFIG , EM_CONFIG )
2011-12-19 02:47:33 +04:00
print
2011-12-18 23:34:19 +04:00
2012-01-29 00:29:43 +04:00
assert os . path . exists ( CONFIG_FILE ) , ' To run these tests, we need a (working!) %s file to already exist ' % EM_CONFIG
2011-12-18 23:34:19 +04:00
shutil . copyfile ( CONFIG_FILE , CONFIG_FILE + ' _backup ' )
def restore ( ) :
shutil . copyfile ( CONFIG_FILE + ' _backup ' , CONFIG_FILE )
2011-12-19 02:47:33 +04:00
SANITY_FILE = CONFIG_FILE + ' _sanity '
2011-12-18 23:34:19 +04:00
def wipe ( ) :
try_delete ( CONFIG_FILE )
2011-12-19 02:47:33 +04:00
try_delete ( SANITY_FILE )
2011-12-18 23:34:19 +04:00
commands = [ [ EMCC ] , [ ' python ' , path_from_root ( ' tests ' , ' runner.py ' ) , ' blahblah ' ] ]
2012-01-18 06:10:40 +04:00
def mtime ( filename ) :
return os . stat ( filename ) . st_mtime
2011-12-18 23:34:19 +04:00
class sanity ( RunnerCore ) :
def setUp ( self ) :
wipe ( )
def tearDown ( self ) :
restore ( )
2011-12-19 02:47:33 +04:00
def do ( self , command ) :
if type ( command ) is not list :
command = [ command ]
return Popen ( command , stdout = PIPE , stderr = STDOUT ) . communicate ( ) [ 0 ]
2011-12-20 03:37:47 +04:00
def check_working ( self , command , expected = None ) :
2011-12-19 02:47:33 +04:00
if type ( command ) is not list :
command = [ command ]
2011-12-20 03:37:47 +04:00
if expected is None :
if command [ 0 ] == EMCC :
expected = ' no input files '
else :
expected = " has no attribute ' blahblah ' "
2011-12-19 02:47:33 +04:00
output = self . do ( command )
2011-12-20 03:37:47 +04:00
self . assertContained ( expected , output )
2011-12-19 02:47:33 +04:00
return output
def test_aaa_normal ( self ) : # this should be the very first thing that runs. if this fails, everything else is irrelevant!
2011-12-18 23:34:19 +04:00
for command in commands :
2012-01-29 00:29:43 +04:00
# Your existing EM_CONFIG should work!
2011-12-18 23:34:19 +04:00
restore ( )
2011-12-19 02:47:33 +04:00
self . check_working ( command )
2011-12-18 23:34:19 +04:00
def test_firstrun ( self ) :
for command in commands :
wipe ( )
2011-12-19 02:47:33 +04:00
output = self . do ( command )
2011-12-18 23:34:19 +04:00
self . assertContained ( ' Welcome to Emscripten! ' , output )
self . assertContained ( ' This is the first time any of the Emscripten tools has been run. ' , output )
2012-01-29 00:29:43 +04:00
self . assertContained ( ' A settings file has been copied to %s , at absolute path: %s ' % ( EM_CONFIG , CONFIG_FILE ) , output )
2011-12-18 23:34:19 +04:00
self . assertContained ( ' Please edit that file and change the paths to fit your system ' , output )
self . assertContained ( ' make sure LLVM_ROOT and NODE_JS are correct ' , output )
self . assertContained ( ' This command will now exit. When you are done editing those paths, re-run it. ' , output )
assert output . replace ( ' \n ' , ' ' ) . endswith ( ' ==== ' ) , ' We should have stopped: ' + output
assert ( open ( CONFIG_FILE ) . read ( ) == open ( path_from_root ( ' settings.py ' ) ) . read ( ) ) , ' Settings should be copied from settings.py '
2012-01-29 00:29:43 +04:00
# Second run, with bad EM_CONFIG
2011-12-18 23:34:19 +04:00
for settings in [ ' blah ' , ' LLVM_ROOT= " blah " ; JS_ENGINES=[]; COMPILER_ENGINE=NODE_JS=SPIDERMONKEY_ENGINE=[] ' ] :
f = open ( CONFIG_FILE , ' w ' )
f . write ( settings )
f . close ( )
2011-12-19 02:47:33 +04:00
output = self . do ( command )
2011-12-18 23:34:19 +04:00
if ' LLVM_ROOT ' not in settings :
2012-01-29 00:29:43 +04:00
self . assertContained ( ' Error in evaluating %s ' % EM_CONFIG , output )
2011-12-18 23:34:19 +04:00
else :
2011-12-19 02:47:33 +04:00
self . assertContained ( ' FATAL ' , output ) # sanity check should fail
2011-12-20 03:37:47 +04:00
def test_closure_compiler ( self ) :
CLOSURE_FATAL = ' fatal: Closure compiler '
CLOSURE_WARNING = ' WARNING: Closure compiler '
# Sanity check should find closure
restore ( )
output = self . check_working ( EMCC )
self . assertNotContained ( CLOSURE_FATAL , output )
self . assertNotContained ( CLOSURE_WARNING , output )
# Append a bad path for closure, will warn
f = open ( CONFIG_FILE , ' a ' )
f . write ( ' CLOSURE_COMPILER = " /tmp/nowhere/nothingtoseehere/kjadsfkjwelkjsdfkqgas/nonexistent.txt " \n ' )
f . close ( )
output = self . check_working ( EMCC , CLOSURE_WARNING )
# And if you actually try to use the bad path, will be fatal
f = open ( CONFIG_FILE , ' a ' )
f . write ( ' CLOSURE_COMPILER = " /tmp/nowhere/nothingtoseehere/kjadsfkjwelkjsdfkqgas/nonexistent.txt " \n ' )
f . close ( )
output = self . check_working ( [ EMCC , ' -O2 ' , ' tests/hello_world.cpp ' ] , CLOSURE_FATAL )
# With a working path, all is well
restore ( )
try_delete ( ' a.out.js ' )
2012-02-07 03:03:03 +04:00
output = self . check_working ( [ EMCC , ' -O2 ' , ' tests/hello_world.cpp ' ] , ' ' )
2011-12-20 03:37:47 +04:00
assert os . path . exists ( ' a.out.js ' )
2011-12-19 02:47:33 +04:00
def test_emcc ( self ) :
SANITY_MESSAGE = ' Emscripten: Running sanity checks '
SANITY_FAIL_MESSAGE = ' sanity check failed to run '
2012-01-29 00:29:43 +04:00
# emcc should check sanity if no ${EM_CONFIG}_sanity
2011-12-19 02:47:33 +04:00
restore ( )
time . sleep ( 0.1 )
assert not os . path . exists ( SANITY_FILE ) # restore is just the settings, not the sanity
output = self . check_working ( EMCC )
self . assertContained ( SANITY_MESSAGE , output )
assert os . path . exists ( SANITY_FILE ) # EMCC should have checked sanity successfully
assert mtime ( SANITY_FILE ) > = mtime ( CONFIG_FILE )
self . assertNotContained ( SANITY_FAIL_MESSAGE , output )
# emcc run again should not sanity check, because the sanity file is newer
output = self . check_working ( EMCC )
self . assertNotContained ( SANITY_MESSAGE , output )
self . assertNotContained ( SANITY_FAIL_MESSAGE , output )
# But the test runner should
output = self . check_working ( commands [ 1 ] )
self . assertContained ( SANITY_MESSAGE , output )
self . assertNotContained ( SANITY_FAIL_MESSAGE , output )
# Make sure the test runner didn't do anything to the setup
output = self . check_working ( EMCC )
self . assertNotContained ( SANITY_MESSAGE , output )
self . assertNotContained ( SANITY_FAIL_MESSAGE , output )
# emcc should also check sanity if the file is outdated
time . sleep ( 0.1 )
restore ( )
assert mtime ( SANITY_FILE ) < mtime ( CONFIG_FILE )
output = self . check_working ( EMCC )
self . assertContained ( SANITY_MESSAGE , output )
assert mtime ( SANITY_FILE ) > = mtime ( CONFIG_FILE )
self . assertNotContained ( SANITY_FAIL_MESSAGE , output )
2011-12-18 23:34:19 +04:00
2012-01-18 06:10:40 +04:00
def test_emcc_caching ( self ) :
2012-01-18 22:46:47 +04:00
INCLUDING_MESSAGE = ' emcc: including X '
BUILDING_MESSAGE = ' emcc: building X for cache '
2012-01-18 06:10:40 +04:00
EMCC_CACHE = Cache . dirname
restore ( )
Cache . erase ( )
assert not os . path . exists ( EMCC_CACHE )
try :
emcc_debug = os . environ . get ( ' EMCC_DEBUG ' )
os . environ [ ' EMCC_DEBUG ' ] = ' 1 '
# Building a file that doesn't need cached stuff should not trigger cache generation
output = self . do ( [ EMCC , path_from_root ( ' tests ' , ' hello_world.cpp ' ) ] )
2012-01-18 22:46:47 +04:00
assert INCLUDING_MESSAGE . replace ( ' X ' , ' dlmalloc ' ) not in output
assert BUILDING_MESSAGE . replace ( ' X ' , ' dlmalloc ' ) not in output
2012-01-18 06:10:40 +04:00
self . assertContained ( ' hello, world! ' , run_js ( ' a.out.js ' ) )
assert not os . path . exists ( EMCC_CACHE )
try_delete ( ' a.out.js ' )
2012-02-01 07:09:32 +04:00
basebc_name = os . path . join ( EMSCRIPTEN_TEMP_DIR , ' emcc-0-basebc.bc ' )
dcebc_name = os . path . join ( EMSCRIPTEN_TEMP_DIR , ' emcc-1-dce.bc ' )
2012-01-18 06:10:40 +04:00
# Building a file that *does* need dlmalloc *should* trigger cache generation, but only the first time
2012-01-20 02:02:53 +04:00
for filename , libname in [ ( ' hello_malloc.cpp ' , ' dlmalloc ' ) , ( ' hello_libcxx.cpp ' , ' libcxx ' ) ] :
2012-01-18 22:46:47 +04:00
for i in range ( 3 ) :
2012-02-01 07:09:32 +04:00
try_delete ( basebc_name ) # we might need to check this file later
try_delete ( dcebc_name ) # we might need to check this file later
2012-01-18 22:46:47 +04:00
output = self . do ( [ EMCC , path_from_root ( ' tests ' , filename ) ] )
assert INCLUDING_MESSAGE . replace ( ' X ' , libname ) in output
2012-01-20 02:02:53 +04:00
if libname == ' dlmalloc ' :
assert INCLUDING_MESSAGE . replace ( ' X ' , ' libcxx ' ) not in output # we don't need libcxx in this code
else :
assert INCLUDING_MESSAGE . replace ( ' X ' , ' dlmalloc ' ) in output # libcxx always forces inclusion of dlmalloc
2012-01-18 22:46:47 +04:00
assert ( BUILDING_MESSAGE . replace ( ' X ' , libname ) in output ) == ( i == 0 ) , ' Must only build the first time '
self . assertContained ( ' hello, world! ' , run_js ( ' a.out.js ' ) )
assert os . path . exists ( EMCC_CACHE )
assert os . path . exists ( os . path . join ( EMCC_CACHE , libname + ' .bc ' ) )
2012-01-19 01:59:49 +04:00
if libname == ' libcxx ' :
assert os . stat ( os . path . join ( EMCC_CACHE , libname + ' .bc ' ) ) . st_size > 4000000 , ' libc++ is big '
2012-02-01 07:09:32 +04:00
assert os . stat ( basebc_name ) . st_size > 4000000 , ' libc++ is indeed big '
assert os . stat ( dcebc_name ) . st_size < 2000000 , ' Dead code elimination must remove most of libc++ '
2012-01-18 06:10:40 +04:00
finally :
if emcc_debug :
os . environ [ ' EMCC_DEBUG ' ] = emcc_debug
2011-12-18 23:34:19 +04:00
else :
raise Exception ( ' Test runner is confused: ' + str ( sys . argv ) )
2011-06-17 03:19:58 +04:00
2010-08-26 08:01:10 +04:00
if __name__ == ' __main__ ' :
2010-12-30 08:33:28 +03:00
sys . argv = [ sys . argv [ 0 ] ] + [ ' -v ' ] + sys . argv [ 1 : ] # Verbose output by default
2011-12-05 08:44:29 +04:00
# Sanity checks
2011-12-18 23:34:19 +04:00
check_sanity ( force = True )
2011-12-05 23:05:37 +04:00
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. '
2011-12-05 08:44:29 +04:00
# Go
2010-10-10 03:54:23 +04:00
unittest . main ( )
2010-08-26 08:01:10 +04:00