diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/cases/gepoverflow.txt | 2 | ||||
-rw-r--r-- | tests/gl_subdata.cpp | 141 | ||||
-rw-r--r-- | tests/hello_libcxx_mod1.cpp | 9 | ||||
-rwxr-xr-x | tests/runner.py | 285 |
4 files changed, 417 insertions, 20 deletions
diff --git a/tests/cases/gepoverflow.txt b/tests/cases/gepoverflow.txt index 90772c33..bd3091fd 100644 --- a/tests/cases/gepoverflow.txt +++ b/tests/cases/gepoverflow.txt @@ -1,2 +1,2 @@ -*5246502,5247072* +*5246498,5247068* *-514,56* diff --git a/tests/gl_subdata.cpp b/tests/gl_subdata.cpp new file mode 100644 index 00000000..d159b2b2 --- /dev/null +++ b/tests/gl_subdata.cpp @@ -0,0 +1,141 @@ +#define GL_GLEXT_PROTOTYPES +#define EGL_EGLEXT_PROTOTYPES +#include <cmath> +#include <iostream> +#include <vector> +extern "C" { +#include <GL/gl.h> +#include <GL/glut.h> +} +static const char vertex_shader[] = + "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "attribute float indices;\n" + "uniform sampler2D nodeInfo;\n" + "varying vec4 color;" + "\n" + "void main(void)\n" + "{\n" + " float s = (indices + 0.5) / 512.; \n" + " vec4 v = texture2D(nodeInfo, vec2( s, 0.5));\n" + " gl_Position = vec4(v.x, v.y, 0.5, 1.);\n" + " gl_PointSize = v.z;\n" + " color = vec4(0.5 + v.w/2., 0.5 + 0.5 * v.w/2., 0.5, 1);\n" + "}\n"; +static const char fragment_shader[] = + "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "\n" + "varying vec4 color;\n" + "void main(void)\n" + "{\n" + " float dst = distance(vec2(0.5, 0.5), gl_PointCoord); \n" + " gl_FragColor = color;\n" + " if ( dst > 0.3) {" + " gl_FragColor = vec4(0., 0., 0.5, 0.2);\n" + "}\n" + "if ( dst > 0.5) discard;\n" + "}"; +struct NodeInfo { //structure that we want to transmit to our shaders + float x; + float y; + float s; + float c; +}; +GLuint nodeTexture; //texture id used to bind +GLuint nodeSamplerLocation; //shader sampler address +GLuint indicesAttributeLocation; //shader attribute address +GLuint indicesVBO; //Vertex Buffer Object Id; +const int nbNodes = 512; +NodeInfo data[nbNodes]; //our data that will be transmitted using float texture. +double alpha = 0; //use to make a simple funny effect; +static void updateFloatTexture() { + int count = 0; + for (float x=0; x < nbNodes; ++x ) { + data[count].x = 0.2*pow(cos(alpha), 3) + (sin(alpha)*3. + 3.5) * x/nbNodes * cos(alpha + x/nbNodes * 16. * M_PI); + data[count].y = 0.2*pow(sin(alpha), 3) + (sin(alpha)*3. + 3.5) * x/nbNodes * sin(alpha + x/nbNodes * 16. * M_PI); + data[count].s = (16. + 16. * cos(alpha + x/nbNodes * 32. * M_PI)) + 8.;// * fmod(x/nbNodes + alpha, 1.) + 5.; + data[count].c = 0.5 + 0.5 * sin(alpha + x/nbNodes * 32. * M_PI); + ++count; + } + glBindTexture(GL_TEXTURE_2D, nodeTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, nbNodes, 1, 0, GL_RGBA, GL_FLOAT, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, NULL); + alpha -= 0.001; +} +static void glut_draw_callback(void) { + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClearColor(1., 1., 1., 0.); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glActiveTexture(GL_TEXTURE0); + updateFloatTexture(); //we change the texture each time to create the effect (it is just for the test) + glBindTexture(GL_TEXTURE_2D, nodeTexture); + glUniform1i(nodeSamplerLocation, GL_TEXTURE0); + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, indicesVBO); + glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL); + glDrawArrays(GL_POINTS, 0, nbNodes); + glutSwapBuffers(); +} +GLuint createShader(const char source[], int type) { + char msg[512]; + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, (const GLchar**)(&source), NULL); + glCompileShader(shader); + glGetShaderInfoLog(shader, sizeof msg, NULL, msg); + std::cout << "Shader info: " << msg << std::endl; + return shader; +} +static void gl_init(void) { + GLuint program = glCreateProgram(); + glAttachShader(program, createShader(vertex_shader , GL_VERTEX_SHADER)); + glAttachShader(program, createShader(fragment_shader, GL_FRAGMENT_SHADER)); + glLinkProgram(program); + char msg[512]; + glGetProgramInfoLog(program, sizeof msg, NULL, msg); + std::cout << "info: " << msg << std::endl; + glUseProgram(program); + std::vector<float> elements(nbNodes); + int count = 0; + for (float x=0; x < nbNodes; ++x ) { + elements[count] = count; + ++count; + } + /*Create one texture to store all the needed information */ + glGenTextures(1, &nodeTexture); + /* Store the vertices in a vertex buffer object (VBO) */ + glGenBuffers(1, &indicesVBO); + glBindBuffer(GL_ARRAY_BUFFER, indicesVBO); + float zeroes[nbNodes]; + memset(zeroes, 0, sizeof(zeroes)); + glBufferData(GL_ARRAY_BUFFER, elements.size() * sizeof(float), zeroes, GL_STATIC_DRAW); + for (int x = 0; x < nbNodes; x++) { + glBufferSubData(GL_ARRAY_BUFFER, x * sizeof(float), elements.size() * sizeof(float), &elements[x]); + } + /* Get the locations of the uniforms so we can access them */ + nodeSamplerLocation = glGetUniformLocation(program, "nodeInfo"); + glBindAttribLocation(program, 0, "indices"); + //Enable glPoint size in shader, always enable in Open Gl ES 2. + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glEnable(GL_POINT_SPRITE); +} +int main(int argc, char *argv[]) { + glutInit(&argc, argv); + glutInitWindowSize(640, 480); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutCreateWindow("Simple FLOAT Texture Test"); + /* Set up glut callback functions */ + glutDisplayFunc(glut_draw_callback ); + gl_init(); + glutMainLoop(); + return 0; +} + + diff --git a/tests/hello_libcxx_mod1.cpp b/tests/hello_libcxx_mod1.cpp new file mode 100644 index 00000000..2389b1ef --- /dev/null +++ b/tests/hello_libcxx_mod1.cpp @@ -0,0 +1,9 @@ +#include <iostream> + +int main() +{ + std::cout << "hello, world!" << std::endl; + std::cout << "hello, world!" << std::endl; + return 0; +} + diff --git a/tests/runner.py b/tests/runner.py index b7e44c05..09fd7d49 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -970,7 +970,7 @@ m_divisor is 1091269979 Settings.PRECISE_I64_MATH = 0 self.do_run(src, 'unsigned') code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() - assert 'goog.math.Long' not in code and 'jsbn' not in code, 'i64 precise math should not have been included if not asked for' + assert 'goog.math.Long' not in code, 'i64 precise math should not have been included if not asked for' # Verify that even if we ask for precision, if it is not needed it is not included Settings.PRECISE_I64_MATH = 1 @@ -994,7 +994,28 @@ m_divisor is 1091269979 ''' self.do_run(src, '*4903566027370624, 153236438355333*') code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() - assert 'goog.math.Long' not in code and 'jsbn' not in code, 'i64 precise math should not have been included if not actually used' + assert 'goog.math.Long' not in code, 'i64 precise math should not have been included if not actually used' + + # But if we force it to be included, it is. First, a case where we don't need it + Settings.PRECISE_I64_MATH = 2 + self.do_run(open(path_from_root('tests', 'hello_world.c')).read(), 'hello') + code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() + assert 'goog.math.Long' in code, 'i64 precise math should be included if forced' + + # and now one where we do + self.do_run(r''' + #include <stdio.h> + + int main( int argc, char ** argv ) + { + unsigned long a = 0x60DD1695U; + unsigned long b = 0xCA8C4E7BU; + unsigned long long c = (unsigned long long)a * b; + printf( "c = %016llx\n", c ); + + return 0; + } + ''', 'c = 4ca38a6bd2973f97') def test_i64_zextneg(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') @@ -1347,6 +1368,7 @@ c5,de,15,8a def test_floatvars(self): src = ''' #include <stdio.h> + #include <math.h> int main() { float x = 1.234, y = 3.5, q = 0.00000001; @@ -1354,6 +1376,8 @@ c5,de,15,8a int z = x < y; printf("*%d,%d,%.1f,%d,%.4f,%.2f*\\n", z, int(y), y, (int)x, x, q); + printf("%.2f, %.2f, %.2f, %.2f\\n", fmin(0.5, 3.3), fmin(NAN, 3.3), fmax(0.5, 3.3), fmax(NAN, 3.3)); + /* // Rounding behavior float fs[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 }; @@ -1365,7 +1389,7 @@ c5,de,15,8a return 0; } ''' - self.do_run(src, '*1,10,10.5,1,1.2340,0.00*') + self.do_run(src, '*1,10,10.5,1,1.2340,0.00*\n0.50, 3.30, 3.30, 3.30\n') def test_globaldoubles(self): src = r''' @@ -1429,6 +1453,24 @@ c5,de,15,8a ''' 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*') + def test_erf(self): + src = ''' + #include <math.h> + #include <stdio.h> + int main() + { + printf("%1.6f, %1.6f, %1.6f, %1.6f, %1.6f, %1.6f\\n", + erf(1.0), + erf(3.0), + erf(-1.0), + erfc(1.0), + erfc(3.0), + erfc(-1.5)); + return 0; + } + ''' + self.do_run(src, '0.842701, 0.999978, -0.842701, 0.157299, 0.000022, 1.966105') + 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() @@ -1948,6 +1990,52 @@ c5,de,15,8a else: self.do_run(src, 'second\nmain: 0\n') + def test_longjmp2(self): + src = r''' + #include <setjmp.h> + #include <stdio.h> + + typedef struct { + jmp_buf* jmp; + } jmp_state; + + void stack_manipulate_func(jmp_state* s, int level) { + jmp_buf buf; + + printf("Entering stack_manipulate_func, level: %d\n", level); + + if (level == 0) { + s->jmp = &buf; + if (setjmp(*(s->jmp)) == 0) { + printf("Setjmp normal execution path, level: %d\n", level); + stack_manipulate_func(s, level + 1); + } else { + printf("Setjmp error execution path, level: %d\n", level); + } + } else { + printf("Perform longjmp at level %d\n", level); + longjmp(*(s->jmp), 1); + } + + printf("Exiting stack_manipulate_func, level: %d\n", level); + } + + int main(int argc, char *argv[]) { + jmp_state s; + s.jmp = NULL; + stack_manipulate_func(&s, 0); + + return 0; + } + ''' + self.do_run(src, '''Entering stack_manipulate_func, level: 0 +Setjmp normal execution path, level: 0 +Entering stack_manipulate_func, level: 1 +Perform longjmp at level 1 +Setjmp error execution path, level: 0 +Exiting stack_manipulate_func, level: 0 +''') + def test_exceptions(self): if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1") @@ -2738,6 +2826,7 @@ c5,de,15,8a // EMSCRIPTEN_COMMENT("hello from the source"); emscripten_run_script("Module.print('hello world' + '!')"); printf("*%d*\n", emscripten_run_script_int("5*20")); + printf("*%s*\n", emscripten_run_script_string("'five'+'six'")); emscripten_run_script("_save_me_aimee()"); return 0; } @@ -2749,19 +2838,26 @@ def process(filename): # TODO: restore this (see comment in emscripten.h) assert '// hello from the source' in src ''' - self.do_run(src, 'hello world!\n*100*\nmann\n', post_build=check) + self.do_run(src, 'hello world!\n*100*\n*fivesix*\nmann\n', post_build=check) def test_inlinejs(self): src = r''' #include <stdio.h> + double get() { + double ret = 0; + __asm __volatile__("12/3.3":"=a"(ret)); + return ret; + } + int main() { asm("Module.print('Inline JS is very cool')"); + printf("%.2f\n", get()); return 0; } ''' - self.do_run(src, 'Inline JS is very cool') + self.do_run(src, 'Inline JS is very cool\n3.64') def test_memorygrowth(self): if Settings.USE_TYPED_ARRAYS == 0: return self.skip('memory growth is only supported with typed arrays') @@ -4467,11 +4563,15 @@ Pass: 0.000012 0.000012''') int x = sscanf("one %n two", "%s %n", word, &l); printf("%d,%s,%d\n", x, word, l); - + { + int a, b, c, count; + count = sscanf("12345 6789", "%d %n%d", &a, &b, &c); + printf("%i %i %i %i\n", count, a, b, c); + } return 0; } ''' - self.do_run(src, '''[DEBUG] word 1: version, l: 7\n1,one,4''') + self.do_run(src, '''[DEBUG] word 1: version, l: 7\n1,one,4\n2 12345 6 6789\n''') def test_sscanf_whitespace(self): src = r''' @@ -4521,7 +4621,22 @@ Pass: 0.000012 0.000012''') self.do_run(src, '3\n123,1073741823,1125899906842620\n' + '3\n-123,-1073741823,-1125899906842620\n') - + + def test_sscanf_4(self): + src = r''' + #include <stdio.h> + + int main() + { + char pYear[16], pMonth[16], pDay[16], pDate[64]; + printf("%d\n", sscanf("Nov 19 2012", "%s%s%s", pMonth, pDay, pYear)); + printf("day %s, month %s, year %s \n", pDay, pMonth, pYear); + return(0); + } + ''' + + self.do_run(src, '3\nday 19, month Nov, year 2012'); + 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() @@ -6126,7 +6241,9 @@ def process(filename): finally: del os.environ['EMCC_DEBUG'] for debug in [1,2]: - self.assertIdentical(open('release.js').read().replace('\n\n', '\n').replace('\n\n', '\n'), open('debug%d.js' % debug).read().replace('\n\n', '\n').replace('\n\n', '\n')) # EMCC_DEBUG=1 mode must not generate different code! + def clean(text): + return text.replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n') + self.assertIdentical(clean(open('release.js').read()), clean(open('debug%d.js' % debug).read())) # EMCC_DEBUG=1 mode must not generate different code! print >> sys.stderr, 'debug check %d passed too' % debug try_delete(CANONICAL_TEMP_DIR) @@ -7654,6 +7771,22 @@ f.close() Popen(['python', EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate() self.assertContained('data: 67452301\ndata[0,1] 16bit: 2301\ndata[1,2] 16bit: 4523', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + def test_unaligned_memory_2(self): + open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r''' + #include <string> + #include <stdio.h> + + int main( int argc, char ** argv ) + { + std::string testString( "Hello, World!" ); + + printf( "testString = %s\n", testString.c_str() ); + return 0; + } + ''') + Popen(['python', EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate() + self.assertContained('testString = Hello, World!', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + def test_l_link(self): # Linking with -lLIBNAME and -L/DIRNAME should work @@ -8100,6 +8233,33 @@ f.close() output = Popen(['python', EMCC, os.path.join(self.get_dir(), 'main.cpp')], stderr=PIPE).communicate() self.assertNotContained('Unresolved symbol: _something\n', output[1]) + def test_toobig(self): + open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' + #include <stdio.h> + + #define BYTES 100*1024*1024 + + int main(int argc, char **argv) { + if (argc == 100) { + static char buf[BYTES]; + static char buf2[BYTES]; + for (int i = 0; i < BYTES; i++) { + buf[i] = i*i; + buf2[i] = i/3; + } + for (int i = 0; i < BYTES; i++) { + buf[i] = buf2[i/2]; + buf2[i] = buf[i/3]; + } + printf("%d\n", buf[10] + buf2[20]); + } + return 0; + } + ''') + output = Popen(['python', EMCC, os.path.join(self.get_dir(), 'main.cpp')], stderr=PIPE).communicate()[1] + assert 'Emscripten failed' in output, output + assert 'warning: very large fixed-size structural type' in output, output + def test_prepost(self): open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(''' #include <stdio.h> @@ -8203,7 +8363,7 @@ f.close() (path_from_root('tools', 'test-js-optimizer-t2.js'), open(path_from_root('tools', 'test-js-optimizer-t2-output.js')).read(), ['simplifyExpressionsPre', 'optimizeShiftsAggressive']), # Make sure that optimizeShifts handles functions with shift statements. - (path_from_root('tools', 'test-js-optimizer-t3.js'), open(path_from_root('tools', 'test-js-optimizer-t3.js')).read(), + (path_from_root('tools', 'test-js-optimizer-t3.js'), open(path_from_root('tools', 'test-js-optimizer-t3-output.js')).read(), ['optimizeShiftsAggressive']), (path_from_root('tools', 'test-js-optimizer-regs.js'), open(path_from_root('tools', 'test-js-optimizer-regs-output.js')).read(), ['registerize']), @@ -8222,6 +8382,17 @@ f.close() assert 'foo.o: ' in output, '-%s failed to produce the right output: %s' % (opt, output) assert 'error' not in err, 'Unexpected stderr: ' + err + def test_chunking(self): + if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode') + if multiprocessing.cpu_count() < 2: return self.skip('need multiple cores') + try: + os.environ['EMCC_DEBUG'] = '1' + output, err = Popen(['python', EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O1'], stdout=PIPE, stderr=PIPE).communicate() + assert 'phase 2 working on 3 chunks' in err, err + assert 'splitting up js optimization into 2 chunks' in err, err + finally: + del os.environ['EMCC_DEBUG'] + def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1 try_delete(os.path.join(self.get_dir(), 'test')) shutil.copytree(path_from_root('tests', 'scons'), os.path.join(self.get_dir(), 'test')) @@ -9477,6 +9648,9 @@ elif 'browser' in str(sys.argv): def test_float_tex(self): self.btest('float_tex.cpp', reference='float_tex.png') + def test_subdata(self): + self.btest('gl_subdata.cpp', reference='float_tex.png') + def test_runtimelink(self): main, supp = self.setup_runtimelink_test() @@ -9978,6 +10152,8 @@ elif 'sanity' in str(sys.argv): assert os.path.exists(CONFIG_FILE), 'To run these tests, we need a (working!) %s file to already exist' % EM_CONFIG + assert not os.environ.get('EMCC_DEBUG'), 'do not run sanity checks in debug mode!' + shutil.copyfile(CONFIG_FILE, CONFIG_FILE + '_backup') def restore(): shutil.copyfile(CONFIG_FILE + '_backup', CONFIG_FILE) @@ -10210,10 +10386,11 @@ fi self.assertContained(SANITY_MESSAGE, output) # but with EMCC_DEBUG=1 we should check - assert not os.environ.get('EMCC_DEBUG'), 'do not run sanity checks in debug mode!' - os.environ['EMCC_DEBUG'] = '1' - output = self.check_working(EMCC) - del os.environ['EMCC_DEBUG'] + try: + os.environ['EMCC_DEBUG'] = '1' + output = self.check_working(EMCC) + finally: + del os.environ['EMCC_DEBUG'] self.assertContained(SANITY_MESSAGE, output) output = self.check_working(EMCC) self.assertNotContained(SANITY_MESSAGE, output) @@ -10270,8 +10447,8 @@ fi assert not os.path.exists(EMCC_CACHE) try: - emcc_debug = os.environ.get('EMCC_DEBUG') os.environ['EMCC_DEBUG'] ='1' + self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp') # 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')]) @@ -10287,8 +10464,6 @@ fi ll_name1 = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-2-ll.ll') ll_name2 = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-3-ll.ll') - self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp') - # Building a file that *does* need dlmalloc *should* trigger cache generation, but only the first time for filename, libname in [('hello_malloc.cpp', 'dlmalloc'), ('hello_libcxx.cpp', 'libcxx')]: for i in range(3): @@ -10321,8 +10496,7 @@ fi print i, 'll metadata should be removed in -O1 and O2 by default', ll[-300:] assert False finally: - if emcc_debug: - os.environ['EMCC_DEBUG'] = emcc_debug + del os.environ['EMCC_DEBUG'] # Manual cache clearing assert os.path.exists(EMCC_CACHE) @@ -10350,6 +10524,79 @@ fi assert os.path.exists(RELOOPER) == (i >= 2), 'have relooper on O2: ' + output assert ('L2 : do {' in open('a.out.js').read()) == (i >= 2), 'reloop code on O2: ' + output + def test_jcache(self): + PRE_LOAD_MSG = 'loading pre from jcache' + PRE_SAVE_MSG = 'saving pre to jcache' + FUNC_CHUNKS_LOAD_MSG = ' funcchunks from jcache' + FUNC_CHUNKS_SAVE_MSG = ' funcchunks to jcache' + JSFUNC_CHUNKS_LOAD_MSG = 'jsfuncchunks from jcache' + JSFUNC_CHUNKS_SAVE_MSG = 'jsfuncchunks to jcache' + + restore() + Cache.erase() + + try: + os.environ['EMCC_DEBUG'] = '1' + self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp') + if not os.path.exists(self.working_dir): os.makedirs(self.working_dir) + + assert not os.path.exists(JCache.get_cachename('emscript_files')) + + srcs = {} + used_jcache = False + + for args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected in [ + ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []), + (['--jcache'], 'hello_world_loop.cpp', True, False, True, False, True, False, []), + (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []), + ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []), + # new + ([], 'hello_world.cpp', False, False, False, False, False, False, []), + (['--jcache'], 'hello_world.cpp', True, False, True, False, True, False, []), + (['--jcache'], 'hello_world.cpp', False, True, False, True, False, True, []), + ([], 'hello_world.cpp', False, False, False, False, False, False, []), + # go back to old file, experience caching + (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []), + # new, large file + ([], 'hello_malloc.cpp', False, False, False, False, False, False, []), + (['--jcache'], 'hello_malloc.cpp', True, False, True, False, True, False, []), + (['--jcache'], 'hello_malloc.cpp', False, True, False, True, False, True, []), + ([], 'hello_malloc.cpp', False, False, False, False, False, False, []), + # new, huge file + ([], 'hello_libcxx.cpp', False, False, False, False, False, False, ('2 chunks', '3 chunks')), + (['--jcache'], 'hello_libcxx.cpp', True, False, True, False, True, False, []), + (['--jcache'], 'hello_libcxx.cpp', False, True, False, True, False, True, []), + ([], 'hello_libcxx.cpp', False, False, False, False, False, False, []), + # finally, build a file close to the previous, to see that some chunks are found in the cache and some not + (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, True, True, True, False, []), # win on pre, mix on funcs, fail on jsfuncs + (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, False, True, False, True, []), + ]: + print >> sys.stderr, args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected + self.clear() + out, err = Popen(['python', EMCC, '-O2', '--closure', '0', path_from_root('tests', input_file)] + args, stdout=PIPE, stderr=PIPE).communicate() + errtail = err.split('emcc invocation')[-1] + self.assertContained('hello, world!', run_js('a.out.js'), errtail) + assert (PRE_SAVE_MSG in err) == expect_pre_save, errtail + assert (PRE_LOAD_MSG in err) == expect_pre_load, errtail + assert (FUNC_CHUNKS_SAVE_MSG in err) == expect_funcs_save, errtail + assert (FUNC_CHUNKS_LOAD_MSG in err) == expect_funcs_load, errtail + assert (JSFUNC_CHUNKS_SAVE_MSG in err) == expect_jsfuncs_save, errtail + assert (JSFUNC_CHUNKS_LOAD_MSG in err) == expect_jsfuncs_load, errtail + for expect in expected: assert expect in err, expect + ' ? ' + errtail + curr = open('a.out.js').read() + if input_file not in srcs: + srcs[input_file] = curr + else: + open('/home/alon/Dev/emscripten/a', 'w').write(srcs[input_file]) + open('/home/alon/Dev/emscripten/b', 'w').write(curr) + assert abs(len(curr)/float(len(srcs[input_file]))-1)<0.01, 'contents may shift in order, but must remain the same size %d vs %d' % (len(curr), len(srcs[input_file])) + '\n' + errtail + used_jcache = used_jcache or ('--jcache' in args) + assert used_jcache == os.path.exists(JCache.get_cachename('emscript_files')) + #print >> sys.stderr, errtail + + finally: + del os.environ['EMCC_DEBUG'] + else: raise Exception('Test runner is confused: ' + str(sys.argv)) |