diff options
Diffstat (limited to 'tests')
28 files changed, 1355 insertions, 275 deletions
diff --git a/tests/browser_main.cpp b/tests/browser_main.cpp new file mode 100644 index 00000000..efdce1be --- /dev/null +++ b/tests/browser_main.cpp @@ -0,0 +1,42 @@ +#include <assert.h> +#include <stdio.h> +#include <dlfcn.h> +#include <emscripten.h> + +typedef void (*voidfunc)(); +typedef int (*intfunc)(); + +void *lib_handle; +voidfunc onefunc; +intfunc twofunc; + +void next(const char *x) { + lib_handle = dlopen("themodule.js", RTLD_NOW); + assert(lib_handle != NULL); + + onefunc = (voidfunc)dlsym(lib_handle, "one"); + twofunc = (intfunc)dlsym(lib_handle, "two"); + assert(onefunc && twofunc); + + assert(twofunc() == 0); + onefunc(); + assert(twofunc() == 1); + onefunc(); + onefunc(); + assert(twofunc() == 3); + onefunc(); + onefunc(); + onefunc(); + onefunc(); + assert(twofunc() == 7); + onefunc(); + int result = twofunc(); + REPORT_RESULT(); +} + +int main() { + emscripten_async_wget("module.js", "themodule.js", next, NULL); + + return 0; +} + diff --git a/tests/browser_module.cpp b/tests/browser_module.cpp new file mode 100644 index 00000000..85d724b5 --- /dev/null +++ b/tests/browser_module.cpp @@ -0,0 +1,15 @@ + +int state = 0; + +extern "C" { + +void one() { + state++; +} + +int two() { + return state; +} + +} + diff --git a/tests/cmake/target_html/CMakeLists.txt b/tests/cmake/target_html/CMakeLists.txt index 9f891e71..8b0528eb 100644 --- a/tests/cmake/target_html/CMakeLists.txt +++ b/tests/cmake/target_html/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -project(hello_world_gles.html) +project(hello_world_gles) file(GLOB sourceFiles ../../hello_world_gles.c) @@ -10,5 +10,7 @@ else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimi SET(linkFlags "-O2") endif() -add_executable(hello_world_gles.html ${sourceFiles}) -set_target_properties(hello_world_gles.html PROPERTIES LINK_FLAGS "${linkFlags}") +SET(CMAKE_EXECUTABLE_SUFFIX ".html") + +add_executable(hello_world_gles ${sourceFiles}) +set_target_properties(hello_world_gles PROPERTIES LINK_FLAGS "${linkFlags}") diff --git a/tests/cmake/target_js/CMakeLists.txt b/tests/cmake/target_js/CMakeLists.txt index 860b70a9..cee5fc42 100644 --- a/tests/cmake/target_js/CMakeLists.txt +++ b/tests/cmake/target_js/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -project(hello_world.js) +project(hello_world) file(GLOB sourceFiles ../../hello_world.cpp) @@ -10,5 +10,23 @@ else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimi SET(linkFlags "-O2") endif() -add_executable(hello_world.js ${sourceFiles}) -set_target_properties(hello_world.js PROPERTIES LINK_FLAGS "${linkFlags}") +SET(CMAKE_EXECUTABLE_SUFFIX ".js") + +if (WIN32) + message(FATAL_ERROR "WIN32 should not be defined when cross-compiling!") +endif() + +if (APPLE) + message(FATAL_ERROR "APPLE should not be defined when cross-compiling!") +endif() + +if (NOT EMSCRIPTEN) + message(FATAL_ERROR "EMSCRIPTEN should be defined when cross-compiling!") +endif() + +if (NOT CMAKE_C_SIZEOF_DATA_PTR) + message(FATAL_ERROR "CMAKE_C_SIZEOF_DATA_PTR was not defined!") +endif() + +add_executable(hello_world ${sourceFiles}) +set_target_properties(hello_world PROPERTIES LINK_FLAGS "${linkFlags}") diff --git a/tests/dlmalloc_proxy.c b/tests/dlmalloc_proxy.c new file mode 100644 index 00000000..06137c42 --- /dev/null +++ b/tests/dlmalloc_proxy.c @@ -0,0 +1,85 @@ +// Emscripten tests + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <dlfcn.h> + +typedef void *(*mallocer)(int n); +typedef void (*freeer)(void *p); + +void *lib_handle; +int handles = 0; +mallocer mallocproxy = NULL; +freeer freeproxy = NULL; + +void get_lib() { + //printf("get lib\n"); + lib_handle = dlopen("liblib.so", RTLD_NOW); + assert(lib_handle != NULL); + handles++; + + mallocproxy = (mallocer)dlsym(lib_handle, "mallocproxy"); + assert(mallocproxy!= NULL); + freeproxy = (freeer)dlsym(lib_handle, "freeproxy"); + assert(freeproxy!= NULL); +} + +void unget_lib() { + //printf("unget lib\n"); + assert(lib_handle); + dlclose(lib_handle); + handles--; + if (handles == 0) lib_handle = NULL; +} + +int main() { + int n = 0, total = 0, l = 0; + void *allocs[50]; + allocs[10] = malloc(10); // pull in real malloc + for (int i = 0; i < 1000; i++) { + //printf("%d: total ever %d MB, current MB %d, total libs %d\n", i, total, n, l); + if (i % 5 == 0) { + if (handles < 10) { + get_lib(); + l++; + } + } + if (i % 7 == 0) { + if (handles > 0) unget_lib(); + } + if (i % 3 == 0) { + if (handles > 0) { + if (n < 10) { + if (i % 2 == 0) { + //printf("alloc\n"); + allocs[n++] = mallocproxy(1024*1024); + } else { + //printf("real alloc\n"); + allocs[n++] = malloc(1024*1024); + } + total++; + } else { + //printf("real free\n"); + free(allocs[--n]); // real free + } + } + } + if (i % 4 == 0) { + if (handles > 0 && n > 0) { + //printf("free\n"); + if (i % 2 == 0) { + //printf("free\n"); + freeproxy(allocs[--n]); + } else { + //printf("real free\n"); + free(allocs[--n]); + } + } + } + } + while (n > 0) free(allocs[--n]); // real free + while (handles > 0) unget_lib(); + printf("*%d,%d*\n", total, l); +} + diff --git a/tests/filesystem/src.js b/tests/filesystem/src.js index dbdd4bed..91337f5b 100644 --- a/tests/filesystem/src.js +++ b/tests/filesystem/src.js @@ -1,16 +1,18 @@ var dummy_device = FS.makedev(64, 0); FS.registerDevice(dummy_device, {}); -FS.createFolder('/', 'forbidden', false, false); -FS.createFolder('/forbidden', 'test', true, true); -FS.createPath('/', 'abc/123', true, true); -FS.createPath('/', 'abc/456', true, true); -FS.createPath('/', 'def/789', true, true); -FS.mkdev('/abc/deviceA', 0666, dummy_device); -FS.mkdev('/def/deviceB', 0666, dummy_device); -FS.createLink('/abc', 'localLink', '123', true, true); -FS.createLink('/abc', 'rootLink', '/', true, true); -FS.createLink('/abc', 'relativeLink', '../def', true, true); +FS.mkdir('/forbidden', 0000); +FS.mkdir('/forbidden/test'); +FS.mkdir('/abc'); +FS.mkdir('/abc/123'); +FS.mkdir('/abc/456'); +FS.mkdir('/def'); +FS.mkdir('/def/789'); +FS.mkdev('/abc/deviceA', dummy_device); +FS.mkdev('/def/deviceB', dummy_device); +FS.symlink('123', '/abc/localLink'); +FS.symlink('/', '/abc/rootLink'); +FS.symlink('../def', '/abc/relativeLink'); FS.ignorePermissions = false; function explore(path) { diff --git a/tests/gl_vertex_buffer.c b/tests/gl_vertex_buffer.c new file mode 100644 index 00000000..6b695462 --- /dev/null +++ b/tests/gl_vertex_buffer.c @@ -0,0 +1,195 @@ +/******************************************************************* + * * + * Using SDL With OpenGL * + * * + * Tutorial by Kyle Foley (sdw) * + * * + * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL * + * * + *******************************************************************/ + +/* + THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION + AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN. + + THE ORIGINAL AUTHOR IS KYLE FOLEY. + + THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY + OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF + MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, + ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE + RESULTING FROM THE USE, MODIFICATION, OR + REDISTRIBUTION OF THIS SOFTWARE. + */ + +#if !EMSCRIPTEN +#define USE_GLEW 0 +#endif + +#if USE_GLEW +#include "GL/glew.h" +#endif + +#include <SDL/SDL.h> + +#if !USE_GLEW +#include "SDL/SDL_opengl.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen; + + // Slightly different SDL initialization + if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) { + printf("Unable to initialize SDL: %s\n", SDL_GetError()); + return 1; + } + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new* + + screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed* + if ( !screen ) { + printf("Unable to set video mode: %s\n", SDL_GetError()); + return 1; + } + + // Set the OpenGL state after creating the context with SDL_SetVideoMode + + glClearColor( 0, 0, 0, 0 ); + +#if !EMSCRIPTEN + glEnable( GL_TEXTURE_2D ); // Need this to display a texture XXX unnecessary in OpenGL ES 2.0/WebGL +#endif + + glViewport( 0, 0, 640, 480 ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Clear the screen before drawing + glClear( GL_COLOR_BUFFER_BIT ); + + typedef struct Color { + GLubyte r; + GLubyte g; + GLubyte b; + GLubyte a; + } Color; + + typedef struct Vertex { + GLfloat x; + GLfloat y; + Color color; + } Vertex; + + Vertex vertices[18] = { + {-1.00, 0.0, {0xFF, 0x00, 0xFF, 0xFF}}, + {-1.00, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.75, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.75, 1.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + {-0.50, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.50, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.25, 0.0, {0xFF, 0x00, 0xFF, 0xFF}}, + {-0.25, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.00, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.00, 1.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + { 0.25, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 0.25, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + { 0.50, 0.0, {0xFF, 0x00, 0xFF, 0xFF}}, + { 0.50, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + { 0.75, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 0.75, 1.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + { 1.00, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 1.00, 1.0, {0xFF, 0xFF, 0x00, 0xFF}} + }; + + Vertex vertices2[18] = { + {-1.00, -1.0, {0xFF, 0x00, 0xFF, 0xFF}}, + {-1.00, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.75, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.75, 0.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + {-0.50, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.50, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.25, -1.0, {0xFF, 0x00, 0xFF, 0xFF}}, + {-0.25, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.00, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.00, 0.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + { 0.25, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 0.25, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + { 0.50, -1.0, {0xFF, 0x00, 0xFF, 0xFF}}, + { 0.50, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + { 0.75, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 0.75, 0.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + { 1.00, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 1.00, 0.0, {0xFF, 0xFF, 0x00, 0xFF}} + }; + + // make a vertex buffer for the second set of vertices + GLuint vbo = 0; + glGenBuffers(1, &vbo); + + + // bind to it + glBindBuffer(GL_ARRAY_BUFFER, vbo); + // send it to gl + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_STATIC_READ); // GL_STATIC_READ is not in WebGL! + + // unbind from it + glBindBuffer(GL_ARRAY_BUFFER, 0); + + + // DRAW + + // Clear the screen before drawing + glClear( GL_COLOR_BUFFER_BIT ); + + // This test ensures that we can use two separate arrays in memory for different + // attributes, and that they each can have different stride. + // The first test shows implicit striding (the zero indicates tightly packed) + // The second test shows explicit striding where the stride is passed in + // even though it also is tightly packed + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + // TEST 1 - clientside data + + glVertexPointer(2, GL_FLOAT, sizeof(Vertex), vertices); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), &vertices[0].color); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 6); + glDrawArrays(GL_TRIANGLE_STRIP, 10, 3); + + + + // TEST 2 - bind to array buffer, gl*Pointer calls are offsets into the buffer, which was previously uploaded to + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + + glVertexPointer(2, GL_FLOAT, sizeof(Vertex), 0); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (GLvoid*)((GLvoid*)&vertices2[0].color - (GLvoid*)&vertices2[0])); + +// gldrawarrays first with a low number of vertices, then with a high number + glDrawArrays(GL_TRIANGLE_STRIP, 0, 6); + glDrawArrays(GL_TRIANGLE_STRIP, 10, 3); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + SDL_GL_SwapBuffers(); + +#if !EMSCRIPTEN + // Wait for 3 seconds to give us a chance to see the image + SDL_Delay(3000); +#endif + + SDL_Quit(); + + return 0; +} diff --git a/tests/gl_vertex_buffer.png b/tests/gl_vertex_buffer.png Binary files differnew file mode 100644 index 00000000..3e1f2230 --- /dev/null +++ b/tests/gl_vertex_buffer.png diff --git a/tests/gl_vertex_buffer_pre.c b/tests/gl_vertex_buffer_pre.c new file mode 100644 index 00000000..84b76569 --- /dev/null +++ b/tests/gl_vertex_buffer_pre.c @@ -0,0 +1,177 @@ +/******************************************************************* + * * + * Using SDL With OpenGL * + * * + * Tutorial by Kyle Foley (sdw) * + * * + * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL * + * * + *******************************************************************/ + +/* + THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION + AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN. + + THE ORIGINAL AUTHOR IS KYLE FOLEY. + + THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY + OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF + MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, + ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE + RESULTING FROM THE USE, MODIFICATION, OR + REDISTRIBUTION OF THIS SOFTWARE. + */ + +#if !EMSCRIPTEN +#define USE_GLEW 0 +#endif + +#if USE_GLEW +#include "GL/glew.h" +#endif + +#include <SDL/SDL.h> + +#if !USE_GLEW +#include "SDL/SDL_opengl.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen; + + // Slightly different SDL initialization + if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) { + printf("Unable to initialize SDL: %s\n", SDL_GetError()); + return 1; + } + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new* + + screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed* + if ( !screen ) { + printf("Unable to set video mode: %s\n", SDL_GetError()); + return 1; + } + + // Set the OpenGL state after creating the context with SDL_SetVideoMode + + glClearColor( 0, 0, 0, 0 ); + +#if !EMSCRIPTEN + glEnable( GL_TEXTURE_2D ); // Need this to display a texture XXX unnecessary in OpenGL ES 2.0/WebGL +#endif + + glViewport( 0, 0, 640, 480 ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Clear the screen before drawing + glClear( GL_COLOR_BUFFER_BIT ); + + typedef struct Color { + GLubyte r; + GLubyte g; + GLubyte b; + GLubyte a; + } Color; + + typedef struct Vertex { + GLfloat x; + GLfloat y; + Color color; + } Vertex; + + Vertex vertices[18] = { + {-1.00, 0.0, {0xFF, 0x00, 0xFF, 0xFF}}, + {-1.00, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.75, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.75, 1.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + {-0.50, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.50, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.25, 0.0, {0xFF, 0x00, 0xFF, 0xFF}}, + {-0.25, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.00, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.00, 1.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + { 0.25, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 0.25, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + { 0.50, 0.0, {0xFF, 0x00, 0xFF, 0xFF}}, + { 0.50, 1.0, {0xFF, 0xFF, 0x00, 0xFF}}, + { 0.75, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 0.75, 1.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + { 1.00, 0.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 1.00, 1.0, {0xFF, 0xFF, 0x00, 0xFF}} + }; + + Vertex vertices2[18] = { + {-1.00, -1.0, {0xFF, 0x00, 0xFF, 0xFF}}, + {-1.00, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.75, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.75, 0.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + {-0.50, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.50, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.25, -1.0, {0xFF, 0x00, 0xFF, 0xFF}}, + {-0.25, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + {-0.00, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + {-0.00, 0.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + { 0.25, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 0.25, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + { 0.50, -1.0, {0xFF, 0x00, 0xFF, 0xFF}}, + { 0.50, 0.0, {0xFF, 0xFF, 0x00, 0xFF}}, + { 0.75, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 0.75, 0.0, {0xFF, 0xFF, 0xFF, 0xFF}}, + { 1.00, -1.0, {0xFF, 0x00, 0x00, 0xFF}}, + { 1.00, 0.0, {0xFF, 0xFF, 0x00, 0xFF}} + }; + + // make a vertex buffer for the second set of vertices + GLuint vbo = 0; + glGenBuffers(1, &vbo); + + + // bind to it + glBindBuffer(GL_ARRAY_BUFFER, vbo); + // send it to gl + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_STATIC_DRAW); + + // unbind from it + glBindBuffer(GL_ARRAY_BUFFER, 0); + + + // DRAW + + // Clear the screen before drawing + glClear( GL_COLOR_BUFFER_BIT ); + + // This test ensures that we can use two separate arrays in memory for different + // attributes, and that they each can have different stride. + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + glVertexPointer(2, GL_FLOAT, sizeof(Vertex), vertices); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), &vertices[0].color); + glDrawArrays(GL_TRIANGLE_STRIP, 10, 3); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 6); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + SDL_GL_SwapBuffers(); + +#if !EMSCRIPTEN + // Wait for 3 seconds to give us a chance to see the image + SDL_Delay(3000); +#endif + + SDL_Quit(); + + return 0; +} diff --git a/tests/gl_vertex_buffer_pre.png b/tests/gl_vertex_buffer_pre.png Binary files differnew file mode 100644 index 00000000..5677a868 --- /dev/null +++ b/tests/gl_vertex_buffer_pre.png diff --git a/tests/runner.py b/tests/runner.py index f0e61c4e..ddc97ea4 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -254,7 +254,7 @@ process(sys.argv[1]) os.chdir(cwd) out = open(stdout, 'r').read() err = open(stderr, 'r').read() - if engine == SPIDERMONKEY_ENGINE and Settings.ASM_JS: + if engine == SPIDERMONKEY_ENGINE and Settings.ASM_JS == 1: err = self.validate_asmjs(err) if output_nicerizer: ret = output_nicerizer(out, err) @@ -646,7 +646,7 @@ class BrowserCore(RunnerCore): }); ''' % basename) - def btest(self, filename, expected=None, reference=None, force_c=False, reference_slack=0, + def btest(self, filename, expected=None, reference=None, force_c=False, reference_slack=0, manual_reference=False, post_build=None, args=[], outfile='test.html', message='.'): # TODO: use in all other tests # if we are provided the source and not a path, use that filename_is_src = '\n' in filename @@ -663,9 +663,11 @@ class BrowserCore(RunnerCore): expected = [str(i) for i in range(0, reference_slack+1)] shutil.copyfile(filepath, temp_filepath) self.reftest(path_from_root('tests', reference)) - args = args + ['--pre-js', 'reftest.js', '-s', 'GL_TESTING=1'] + if not manual_reference: + args = args + ['--pre-js', 'reftest.js', '-s', 'GL_TESTING=1'] Popen([PYTHON, EMCC, temp_filepath, '-o', outfile] + args).communicate() assert os.path.exists(outfile) + if post_build: post_build() if type(expected) is str: expected = [expected] self.run_browser(outfile, message, ['/report_result?' + e for e in expected]) diff --git a/tests/sdl_canvas_proxy.c b/tests/sdl_canvas_proxy.c new file mode 100644 index 00000000..27ef3bb4 --- /dev/null +++ b/tests/sdl_canvas_proxy.c @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <stdlib.h> +#include <SDL/SDL.h> +#include <assert.h> +#include <emscripten.h> + +int main(int argc, char **argv) { + FILE *f = fopen("data.txt", "rb"); + assert(f); + assert(fgetc(f) == 'd'); + assert(fgetc(f) == 'a'); + assert(fgetc(f) == 't'); + assert(fgetc(f) == 'u'); + assert(fgetc(f) == 'm'); + fclose(f); + + SDL_Init(SDL_INIT_VIDEO); + SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE); + + SDL_LockSurface(screen); + unsigned int *pixels = (unsigned int *)screen->pixels; + for (int x = 0; x < screen->w; x++) { + for (int y = 0; y < screen->h; y++) { + pixels[x + y*screen->h] = x < 300 ? (y < 200 ? 0x3377AA88 : 0xAA3377CC) : (y < 200 ? 0x0066AA77 : 0xAA006699); + } + } + SDL_UnlockSurface(screen); + + SDL_Quit(); + + EM_ASM(window.close()); + return 0; +} + diff --git a/tests/sdl_canvas_proxy.png b/tests/sdl_canvas_proxy.png Binary files differnew file mode 100644 index 00000000..cc96acfd --- /dev/null +++ b/tests/sdl_canvas_proxy.png diff --git a/tests/sdl_key_proxy.c b/tests/sdl_key_proxy.c new file mode 100644 index 00000000..bc233f29 --- /dev/null +++ b/tests/sdl_key_proxy.c @@ -0,0 +1,63 @@ +#include <stdio.h> +#include <SDL/SDL.h> +#include <SDL/SDL_ttf.h> +#include <emscripten.h> + +int result = 1; + +void one() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + printf("got event %d\n", event.type); + switch(event.type) { + case SDL_KEYDOWN: + break; + case SDL_KEYUP: + // don't handle the modifier key events + if (event.key.keysym.sym == SDLK_LCTRL || + event.key.keysym.sym == SDLK_LSHIFT || + event.key.keysym.sym == SDLK_LALT) { + return; + } + if ((event.key.keysym.mod & KMOD_LCTRL) || (event.key.keysym.mod & KMOD_RCTRL)) { + result *= 2; + } + if ((event.key.keysym.mod & KMOD_LSHIFT) || (event.key.keysym.mod & KMOD_RSHIFT)) { + result *= 3; + } + if ((event.key.keysym.mod & KMOD_LALT) || (event.key.keysym.mod & KMOD_RALT)) { + result *= 5; + } + switch (event.key.keysym.sym) { + case SDLK_RIGHT: printf("right\n"); result *= 7; break; + case SDLK_LEFT: printf("left\n"); result *= 11; break; + case SDLK_DOWN: printf("down\n"); result *= 13; break; + case SDLK_UP: printf("up\n"); result *= 17; break; + case SDLK_a: printf("a\n"); result *= 19; break; + default: { + if (event.key.keysym.scancode == SDL_SCANCODE_B) { + printf("b scancode\n"); result *= 23; break; + } + printf("unknown key: sym %d scancode %d\n", event.key.keysym.sym, event.key.keysym.scancode); + REPORT_RESULT(); + emscripten_run_script("throw 'done'"); // comment this out to leave event handling active. Use the following to log DOM keys: + // addEventListener('keyup', function(event) { console.log(event.keyCode) }, true) + } + } + break; + default: /* Report an unhandled event */ + printf("I don't know what this event is!\n"); + } + } +} + +int main(int argc, char **argv) { + printf("main\n"); + SDL_Init(SDL_INIT_VIDEO); + SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE); + + if (argc == 1337) one(); // keep it alive + + return 0; +} + diff --git a/tests/test_browser.py b/tests/test_browser.py index a0c4dceb..e6fd6544 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -627,6 +627,28 @@ If manually bisecting: Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate() self.run_browser('page.html', '', '/report_result?1') + def test_sdl_canvas_proxy(self): + def post(): + html = open('test.html').read() + html = html.replace('</body>', ''' +<script> +function assert(x, y) { if (!x) throw 'assertion failed ' + y } + +%s + +var windowClose = window.close; +window.close = function() { + doReftest(); + setTimeout(windowClose, 1000); +}; +</script> +</body>''' % open('reftest.js').read()) + open('test.html', 'w').write(html) + + open('data.txt', 'w').write('datum') + + self.btest('sdl_canvas_proxy.c', reference='sdl_canvas_proxy.png', args=['--proxy-to-worker', '--preload-file', 'data.txt'], manual_reference=True, post_build=post) + def test_sdl_key(self): open(os.path.join(self.get_dir(), 'pre.js'), 'w').write(''' Module.postRun = function() { @@ -658,6 +680,52 @@ If manually bisecting: Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_key.c'), '-o', 'page.html', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''']).communicate() self.run_browser('page.html', '', '/report_result?223092870') + def test_sdl_key_proxy(self): + open(os.path.join(self.get_dir(), 'pre.js'), 'w').write(''' + var Module = {}; + Module.postRun = function() { + function doOne() { + Module._one(); + setTimeout(doOne, 1000/60); + } + setTimeout(doOne, 1000/60); + } + ''') + + def post(): + html = open('test.html').read() + html = html.replace('</body>', ''' +<script> +function keydown(c) { + var event = document.createEvent("KeyboardEvent"); + event.initKeyEvent("keydown", true, true, window, + 0, 0, 0, 0, + c, c); + document.dispatchEvent(event); +} + +function keyup(c) { + var event = document.createEvent("KeyboardEvent"); + event.initKeyEvent("keyup", true, true, window, + 0, 0, 0, 0, + c, c); + document.dispatchEvent(event); +} + +keydown(1250);keydown(38);keyup(38);keyup(1250); // alt, up +keydown(1248);keydown(1249);keydown(40);keyup(40);keyup(1249);keyup(1248); // ctrl, shift, down +keydown(37);keyup(37); // left +keydown(39);keyup(39); // right +keydown(65);keyup(65); // a +keydown(66);keyup(66); // b +keydown(100);keyup(100); // trigger the end + +</script> +</body>''') + open('test.html', 'w').write(html) + + self.btest('sdl_key_proxy.c', '223092870', args=['--proxy-to-worker', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']'''], manual_reference=True, post_build=post) + def test_sdl_text(self): open(os.path.join(self.get_dir(), 'pre.js'), 'w').write(''' Module.postRun = function() { @@ -1207,6 +1275,12 @@ If manually bisecting: def test_gl_stride(self): self.btest('gl_stride.c', reference='gl_stride.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1']) + def test_gl_vertex_buffer_pre(self): + self.btest('gl_vertex_buffer_pre.c', reference='gl_vertex_buffer_pre.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1']) + + def test_gl_vertex_buffer(self): + self.btest('gl_vertex_buffer.c', reference='gl_vertex_buffer.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1'], reference_slack=1) + def test_matrix_identity(self): self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840'], args=['-s', 'LEGACY_GL_EMULATION=1']) @@ -1404,3 +1478,8 @@ If manually bisecting: def test_emscripten_async_wget2(self): self.btest('http.cpp', expected='0', args=['-I' + path_from_root('tests')]) + + def test_module(self): + Popen([PYTHON, EMCC, path_from_root('tests', 'browser_module.cpp'), '-o', 'module.js', '-O2', '-s', 'SIDE_MODULE=1', '-s', 'DLOPEN_SUPPORT=1', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two"]']).communicate() + self.btest('browser_main.cpp', args=['-O2', '-s', 'MAIN_MODULE=1', '-s', 'DLOPEN_SUPPORT=1'], expected='8') + diff --git a/tests/test_core.py b/tests/test_core.py index 16bf9a00..5d4f35e8 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -3742,7 +3742,8 @@ def process(filename): self.do_run(open(path_from_root('tests', 'emscripten_get_now.cpp')).read(), 'Timer resolution is good.') def test_inlinejs(self): - if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm') + if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code + if not self.is_le32(): return self.skip('le32 needed for inline js') src = r''' #include <stdio.h> @@ -3762,7 +3763,8 @@ def process(filename): self.do_run(src, 'Inline JS is very cool\n3.64\n') def test_inlinejs2(self): - if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm') + if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code + if not self.is_le32(): return self.skip('le32 needed for inline js') src = r''' #include <stdio.h> @@ -3773,8 +3775,8 @@ def process(filename): } void mult() { - asm("var $_$1 = Math.abs(-100); $_$1 *= 2;"); // multiline - asm __volatile__("Module.print($_$1); Module.print('\n')"); + asm("var $_$1 = Math.abs(-100); $_$1 *= 2; Module.print($_$1)"); // multiline + asm __volatile__("Module.print('done')"); } int main(int argc, char **argv) { @@ -3784,7 +3786,7 @@ def process(filename): } ''' - self.do_run(src, '4\n200\n') + self.do_run(src, '4\n200\ndone\n') def test_inlinejs3(self): if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm') @@ -5580,11 +5582,53 @@ The current type of b is: 9 Settings.RUNTIME_LINKED_LIBS = ['liblib.so']; self.do_run(main, 'supp: 54,2\nmain: 56\nsupp see: 543\nmain see: 76\nok.') - def test_dlfcn_basic(self): - if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') + def can_dlfcn(self): + if self.emcc_args and '--memory-init-file' in self.emcc_args: + for i in range(len(self.emcc_args)): + if self.emcc_args[i] == '--memory-init-file': + self.emcc_args = self.emcc_args[:i] + self.emcc_args[i+2:] + break - Settings.NAMED_GLOBALS = 1 + if Settings.ASM_JS: + Settings.DLOPEN_SUPPORT = 1 + else: + Settings.NAMED_GLOBALS = 1 + + if not self.is_le32(): + self.skip('need le32 for dlfcn support') + return False + else: + return True + + def prep_dlfcn_lib(self): + if Settings.ASM_JS: + Settings.MAIN_MODULE = 0 + Settings.SIDE_MODULE = 1 + else: + Settings.BUILD_AS_SHARED_LIB = 1 + Settings.INCLUDE_FULL_LIBRARY = 0 + + def prep_dlfcn_main(self): + if Settings.ASM_JS: + Settings.MAIN_MODULE = 1 + Settings.SIDE_MODULE = 0 + else: + Settings.BUILD_AS_SHARED_LIB = 0 + Settings.INCLUDE_FULL_LIBRARY = 1 + + dlfcn_post_build = ''' +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) +''' + + def test_dlfcn_basic(self): + if not self.can_dlfcn(): return + self.prep_dlfcn_lib() lib_src = ''' #include <cstdio> @@ -5599,10 +5643,10 @@ The current type of b is: 9 ''' dirname = self.get_dir() filename = os.path.join(dirname, 'liblib.cpp') - Settings.BUILD_AS_SHARED_LIB = 1 self.build(lib_src, dirname, filename) shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + self.prep_dlfcn_main() src = ''' #include <cstdio> #include <dlfcn.h> @@ -5621,28 +5665,17 @@ The current type of b is: 9 return 0; } ''' - Settings.BUILD_AS_SHARED_LIB = 0 - 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) -''' self.do_run(src, 'Constructing main object.\nConstructing lib object.\n', - post_build=add_pre_run_and_checks) + post_build=self.dlfcn_post_build) def test_dlfcn_qsort(self): - if self.emcc_args is None: return self.skip('requires emcc') - if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') - - Settings.LINKABLE = 1 - Settings.NAMED_GLOBALS = 1 + if not self.can_dlfcn(): return if Settings.USE_TYPED_ARRAYS == 2: Settings.CORRECT_SIGNS = 1 # Needed for unsafe optimizations + self.prep_dlfcn_lib() + Settings.EXPORTED_FUNCTIONS = ['_get_cmp'] lib_src = ''' int lib_cmp(const void* left, const void* right) { const int* a = (const int*) left; @@ -5660,11 +5693,11 @@ def process(filename): ''' dirname = self.get_dir() filename = os.path.join(dirname, 'liblib.cpp') - Settings.BUILD_AS_SHARED_LIB = 1 - Settings.EXPORTED_FUNCTIONS = ['_get_cmp'] self.build(lib_src, dirname, filename) shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + self.prep_dlfcn_main() + Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc'] src = ''' #include <stdio.h> #include <stdlib.h> @@ -5686,6 +5719,13 @@ def process(filename): CMP_TYPE lib_cmp_ptr; int arr[5] = {4, 2, 5, 1, 3}; + 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"); + lib_handle = dlopen("liblib.so", RTLD_NOW); if (lib_handle == NULL) { printf("Could not load lib.\\n"); @@ -5697,14 +5737,6 @@ def process(filename): return 1; } lib_cmp_ptr = getter_ptr(); - - 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"); - qsort((void*)arr, 5, sizeof(int), lib_cmp_ptr); printf("Sort with lib comparison: "); for (int i = 0; i < 5; i++) { @@ -5715,27 +5747,22 @@ def process(filename): return 0; } ''' - Settings.BUILD_AS_SHARED_LIB = 0 - Settings.EXPORTED_FUNCTIONS = ['_main'] - 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) -''' self.do_run(src, 'Sort with main comparison: 5 4 3 2 1 *Sort with lib comparison: 1 2 3 4 5 *', output_nicerizer=lambda x, err: x.replace('\n', '*'), - post_build=add_pre_run_and_checks) + post_build=self.dlfcn_post_build) + + if Settings.ASM_JS and os.path.exists(SPIDERMONKEY_ENGINE[0]): + out = run_js('liblib.so', engine=SPIDERMONKEY_ENGINE, full_output=True, stderr=STDOUT) + if 'asm' in out: + self.validate_asmjs(out) def test_dlfcn_data_and_fptr(self): - if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') - if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func') + if Settings.ASM_JS: return self.skip('this is not a valid case - libraries should not be able to access their parents globals willy nilly') + if not self.can_dlfcn(): return - Settings.LINKABLE = 1 - Settings.NAMED_GLOBALS = 1 + if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func') + self.prep_dlfcn_lib() lib_src = ''' #include <stdio.h> @@ -5760,21 +5787,23 @@ def process(filename): ''' dirname = self.get_dir() filename = os.path.join(dirname, 'liblib.cpp') - Settings.BUILD_AS_SHARED_LIB = 1 Settings.EXPORTED_FUNCTIONS = ['_func'] Settings.EXPORTED_GLOBALS = ['_global'] self.build(lib_src, dirname, filename) shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + self.prep_dlfcn_main() + Settings.LINKABLE = 1 src = ''' #include <stdio.h> #include <dlfcn.h> + #include <emscripten.h> typedef void (*FUNCTYPE(int, void(*)()))(); FUNCTYPE func; - void parent_func() { + void EMSCRIPTEN_KEEPALIVE parent_func() { printf("parent_func called from child\\n"); } @@ -5818,23 +5847,14 @@ def process(filename): return 0; } ''' - Settings.BUILD_AS_SHARED_LIB = 0 Settings.EXPORTED_FUNCTIONS = ['_main'] Settings.EXPORTED_GLOBALS = [] - 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) -''' 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*', output_nicerizer=lambda x, err: x.replace('\n', '*'), - post_build=add_pre_run_and_checks) + post_build=self.dlfcn_post_build) def test_dlfcn_alias(self): - if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') + if Settings.ASM_JS: return self.skip('this is not a valid case - libraries should not be able to access their parents globals willy nilly') Settings.LINKABLE = 1 Settings.NAMED_GLOBALS = 1 @@ -5876,29 +5896,23 @@ def process(filename): Settings.BUILD_AS_SHARED_LIB = 0 Settings.INCLUDE_FULL_LIBRARY = 1 Settings.EXPORTED_FUNCTIONS = ['_main'] - 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) -''' self.do_run(src, 'Parent global: 123.*Parent global: 456.*', output_nicerizer=lambda x, err: x.replace('\n', '*'), - post_build=add_pre_run_and_checks, + post_build=self.dlfcn_post_build, extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/time.h,libc/langinfo.h']) Settings.INCLUDE_FULL_LIBRARY = 0 def test_dlfcn_varargs(self): - if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') + if Settings.ASM_JS: return self.skip('this is not a valid case - libraries should not be able to access their parents globals willy nilly') + + if not self.can_dlfcn(): return Settings.LINKABLE = 1 - Settings.NAMED_GLOBALS = 1 if Building.LLVM_OPTS == 2: return self.skip('LLVM LTO will optimize things that prevent shared objects from working') if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this') + self.prep_dlfcn_lib() lib_src = r''' void print_ints(int n, ...); extern "C" void func() { @@ -5907,15 +5921,16 @@ def process(filename): ''' dirname = self.get_dir() filename = os.path.join(dirname, 'liblib.cpp') - Settings.BUILD_AS_SHARED_LIB = 1 Settings.EXPORTED_FUNCTIONS = ['_func'] self.build(lib_src, dirname, filename) shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + self.prep_dlfcn_main() src = r''' #include <stdarg.h> #include <stdio.h> #include <dlfcn.h> + #include <assert.h> void print_ints(int n, ...) { va_list args; @@ -5933,24 +5948,16 @@ def process(filename): print_ints(2, 100, 200); lib_handle = dlopen("liblib.so", RTLD_NOW); + assert(lib_handle); fptr = (void (*)())dlsym(lib_handle, "func"); fptr(); return 0; } ''' - Settings.BUILD_AS_SHARED_LIB = 0 Settings.EXPORTED_FUNCTIONS = ['_main'] - 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) -''' self.do_run(src, '100\n200\n13\n42\n', - post_build=add_pre_run_and_checks) + post_build=self.dlfcn_post_build) def test_dlfcn_self(self): if Settings.USE_TYPED_ARRAYS == 1: return self.skip('Does not work with USE_TYPED_ARRAYS=1') @@ -5959,14 +5966,15 @@ def process(filename): src = r''' #include <stdio.h> #include <dlfcn.h> +#include <emscripten.h> -int global = 123; +int EMSCRIPTEN_KEEPALIVE global = 123; -extern "C" __attribute__((noinline)) void foo(int x) { +extern "C" EMSCRIPTEN_KEEPALIVE void foo(int x) { printf("%d\n", x); } -extern "C" __attribute__((noinline)) void repeatable() { +extern "C" EMSCRIPTEN_KEEPALIVE void repeatable() { void* self = dlopen(NULL, RTLD_LAZY); int* global_ptr = (int*)dlsym(self, "global"); void (*foo_ptr)(int) = (void (*)(int))dlsym(self, "foo"); @@ -5987,15 +5995,372 @@ return 0; break else: raise Exception('Could not find symbol table!') - import json - table = json.loads(table[table.find('{'):table.rfind('}')+1]) - actual = list(sorted(table.keys())) + table = table[table.find('{'):table.rfind('}')+1] # ensure there aren't too many globals; we don't want unnamed_addr - assert actual == ['_foo', '_global', '_main', '_repeatable'], \ - "Symbol table does not match: %s" % actual - + assert table.count(',') <= 4 self.do_run(src, '123\n123', post_build=(None, post)) + + def test_dlfcn_unique_sig(self): + if not self.can_dlfcn(): return + + self.prep_dlfcn_lib() + lib_src = ''' + #include <stdio.h> + + int myfunc(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m) { + return 13; + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_myfunc'] + dirname = self.get_dir() + filename = os.path.join(dirname, 'liblib.c') + self.build(lib_src, dirname, filename) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + + self.prep_dlfcn_main() + src = ''' + #include <assert.h> + #include <stdio.h> + #include <dlfcn.h> + + typedef int (*FUNCTYPE)(int, int, int, int, int, int, int, int, int, int, int, int, int); + + int main() { + void *lib_handle; + FUNCTYPE func_ptr; + + lib_handle = dlopen("liblib.so", RTLD_NOW); + assert(lib_handle != NULL); + + func_ptr = (FUNCTYPE)dlsym(lib_handle, "myfunc"); + assert(func_ptr != NULL); + assert(func_ptr(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == 13); + + puts("success"); + + return 0; + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc'] + self.do_run(src, 'success', force_c=True, post_build=self.dlfcn_post_build) + + def test_dlfcn_stacks(self): + if not self.can_dlfcn(): return + + self.prep_dlfcn_lib() + lib_src = ''' + #include <assert.h> + #include <stdio.h> + #include <string.h> + + int myfunc(const char *input) { + char bigstack[1024] = { 0 }; + + // make sure we didn't just trample the stack! + assert(!strcmp(input, "foobar")); + + snprintf(bigstack, sizeof(bigstack), input); + return strlen(bigstack); + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_myfunc'] + dirname = self.get_dir() + filename = os.path.join(dirname, 'liblib.c') + self.build(lib_src, dirname, filename) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + + self.prep_dlfcn_main() + src = ''' + #include <assert.h> + #include <stdio.h> + #include <dlfcn.h> + + typedef int (*FUNCTYPE)(const char *); + + int main() { + void *lib_handle; + FUNCTYPE func_ptr; + char str[128]; + + snprintf(str, sizeof(str), "foobar"); + + lib_handle = dlopen("liblib.so", RTLD_NOW); + assert(lib_handle != NULL); + + func_ptr = (FUNCTYPE)dlsym(lib_handle, "myfunc"); + assert(func_ptr != NULL); + assert(func_ptr(str) == 6); + + puts("success"); + + return 0; + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc'] + self.do_run(src, 'success', force_c=True, post_build=self.dlfcn_post_build) + + def test_dlfcn_funcs(self): + if not self.can_dlfcn(): return + + self.prep_dlfcn_lib() + lib_src = r''' + #include <assert.h> + #include <stdio.h> + #include <string.h> + + typedef void (*voidfunc)(); + typedef void (*intfunc)(int); + + void callvoid(voidfunc f) { f(); } + void callint(voidfunc f, int x) { f(x); } + + void void_0() { printf("void 0\n"); } + void void_1() { printf("void 1\n"); } + voidfunc getvoid(int i) { + switch(i) { + case 0: return void_0; + case 1: return void_1; + default: return NULL; + } + } + + void int_0(int x) { printf("int 0 %d\n", x); } + void int_1(int x) { printf("int 1 %d\n", x); } + intfunc getint(int i) { + switch(i) { + case 0: return int_0; + case 1: return int_1; + default: return NULL; + } + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_callvoid', '_callint', '_getvoid', '_getint'] + dirname = self.get_dir() + filename = os.path.join(dirname, 'liblib.c') + self.build(lib_src, dirname, filename) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + + self.prep_dlfcn_main() + src = r''' + #include <assert.h> + #include <stdio.h> + #include <dlfcn.h> + + typedef void (*voidfunc)(); + typedef void (*intfunc)(int); + + typedef void (*voidcaller)(voidfunc); + typedef void (*intcaller)(intfunc, int); + + typedef voidfunc (*voidgetter)(int); + typedef intfunc (*intgetter)(int); + + void void_main() { printf("main.\n"); } + void int_main(int x) { printf("main %d\n", x); } + + int main() { + printf("go\n"); + void *lib_handle; + lib_handle = dlopen("liblib.so", RTLD_NOW); + assert(lib_handle != NULL); + + voidcaller callvoid = (voidcaller)dlsym(lib_handle, "callvoid"); + assert(callvoid != NULL); + callvoid(void_main); + + intcaller callint = (intcaller)dlsym(lib_handle, "callint"); + assert(callint != NULL); + callint(int_main, 201); + + voidgetter getvoid = (voidgetter)dlsym(lib_handle, "getvoid"); + assert(getvoid != NULL); + callvoid(getvoid(0)); + callvoid(getvoid(1)); + + intgetter getint = (intgetter)dlsym(lib_handle, "getint"); + assert(getint != NULL); + callint(getint(0), 54); + callint(getint(1), 9000); + + assert(getint(1000) == NULL); + + puts("ok"); + return 0; + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc'] + self.do_run(src, '''go +main. +main 201 +void 0 +void 1 +int 0 54 +int 1 9000 +ok +''', force_c=True, post_build=self.dlfcn_post_build) + + def test_dlfcn_mallocs(self): + if not Settings.ASM_JS: return self.skip('needs asm') + + if not self.can_dlfcn(): return + + Settings.TOTAL_MEMORY = 64*1024*1024 # will be exhausted without functional malloc/free + + self.prep_dlfcn_lib() + lib_src = r''' + #include <assert.h> + #include <stdio.h> + #include <string.h> + #include <stdlib.h> + + void *mallocproxy(int n) { return malloc(n); } + void freeproxy(void *p) { free(p); } + ''' + Settings.EXPORTED_FUNCTIONS = ['_mallocproxy', '_freeproxy'] + dirname = self.get_dir() + filename = os.path.join(dirname, 'liblib.c') + self.build(lib_src, dirname, filename) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + + self.prep_dlfcn_main() + src = open(path_from_root('tests', 'dlmalloc_proxy.c')).read() + Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc', '_free'] + self.do_run(src, '''*294,153*''', force_c=True, post_build=self.dlfcn_post_build) + + def test_dlfcn_longjmp(self): + if not self.can_dlfcn(): return + + self.prep_dlfcn_lib() + lib_src = r''' + #include <setjmp.h> + + void jumpy(jmp_buf buf) { + static int i = 0; + i++; + if (i == 10) longjmp(buf, i); + printf("pre %d\n", i); + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_jumpy'] + dirname = self.get_dir() + filename = os.path.join(dirname, 'liblib.c') + self.build(lib_src, dirname, filename) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + + self.prep_dlfcn_main() + src = r''' + #include <assert.h> + #include <stdio.h> + #include <dlfcn.h> + #include <setjmp.h> + + typedef void (*jumpfunc)(jmp_buf); + + int main() { + printf("go!\n"); + + void *lib_handle; + lib_handle = dlopen("liblib.so", RTLD_NOW); + assert(lib_handle != NULL); + + jumpfunc jumpy = (jumpfunc)dlsym(lib_handle, "jumpy"); + assert(jumpy); + + jmp_buf buf; + int jmpval = setjmp(buf); + if (jmpval == 0) { + while (1) jumpy(buf); + } else { + printf("out!\n"); + } + + return 0; + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc', '_free'] + self.do_run(src, '''go! +pre 1 +pre 2 +pre 3 +pre 4 +pre 5 +pre 6 +pre 7 +pre 8 +pre 9 +out! +''', post_build=self.dlfcn_post_build, force_c=True) + + def zzztest_dlfcn_exceptions(self): # TODO: make this work. need to forward tempRet0 across modules + if not self.can_dlfcn(): return + + Settings.DISABLE_EXCEPTION_CATCHING = 0 + + self.prep_dlfcn_lib() + lib_src = r''' + extern "C" { + int ok() { + return 65; + } + int fail() { + throw 123; + } + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_ok', '_fail'] + dirname = self.get_dir() + filename = os.path.join(dirname, 'liblib.cpp') + self.build(lib_src, dirname, filename) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + + self.prep_dlfcn_main() + src = r''' + #include <assert.h> + #include <stdio.h> + #include <dlfcn.h> + + typedef int (*intfunc)(); + + int main() { + printf("go!\n"); + + void *lib_handle; + lib_handle = dlopen("liblib.so", RTLD_NOW); + assert(lib_handle != NULL); + + intfunc okk = (intfunc)dlsym(lib_handle, "ok"); + intfunc faill = (intfunc)dlsym(lib_handle, "fail"); + assert(okk && faill); + + try { + printf("ok: %d\n", okk()); + } catch(...) { + printf("wha\n"); + } + + try { + printf("fail: %d\n", faill()); + } catch(int x) { + printf("int %d\n", x); + } + + try { + printf("fail: %d\n", faill()); + } catch(double x) { + printf("caught %f\n", x); + } + + return 0; + } + ''' + Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc', '_free'] + self.do_run(src, '''go! +ok: 65 +int 123 +ok +''', post_build=self.dlfcn_post_build) + def test_rand(self): return self.skip('rand() is now random') # FIXME @@ -6992,7 +7357,7 @@ def process(filename): FS.registerDevice(dummy_device, {}); FS.createDataFile('/', 'file', 'abcdef', true, true); - FS.mkdev('/device', 0666, dummy_device); + FS.mkdev('/device', dummy_device); \'\'\' ) open(filename, 'w').write(src) @@ -7250,32 +7615,18 @@ def process(filename): Settings.INCLUDE_FULL_LIBRARY = 0 def test_unistd_access(self): - add_pre_run = ''' -def process(filename): - import tools.shared as shared - src = open(filename, 'r').read().replace( - '// {{PRE_RUN_ADDITIONS}}', - open(shared.path_from_root('tests', 'unistd', 'access.js'), 'r').read() - ) - open(filename, 'w').write(src) -''' + if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code + if not self.is_le32(): return self.skip('le32 needed for inline js') src = open(path_from_root('tests', 'unistd', 'access.c'), 'r').read() expected = open(path_from_root('tests', 'unistd', 'access.out'), 'r').read() - self.do_run(src, expected, post_build=add_pre_run) + self.do_run(src, expected) def test_unistd_curdir(self): - add_pre_run = ''' -def process(filename): - import tools.shared as shared - src = open(filename, 'r').read().replace( - '// {{PRE_RUN_ADDITIONS}}', - open(shared.path_from_root('tests', 'unistd', 'curdir.js'), 'r').read() - ) - open(filename, 'w').write(src) -''' + if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code + if not self.is_le32(): return self.skip('le32 needed for inline js') src = open(path_from_root('tests', 'unistd', 'curdir.c'), 'r').read() expected = open(path_from_root('tests', 'unistd', 'curdir.out'), 'r').read() - self.do_run(src, expected, post_build=add_pre_run) + self.do_run(src, expected) def test_unistd_close(self): src = open(path_from_root('tests', 'unistd', 'close.c'), 'r').read() @@ -7302,18 +7653,11 @@ def process(filename): self.do_run(src, expected) def test_unistd_truncate(self): - add_pre_run = ''' -def process(filename): - import tools.shared as shared - src = open(filename, 'r').read().replace( - '// {{PRE_RUN_ADDITIONS}}', - open(shared.path_from_root('tests', 'unistd', 'truncate.js'), 'r').read() - ) - open(filename, 'w').write(src) -''' + if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code + if not self.is_le32(): return self.skip('le32 needed for inline js') src = open(path_from_root('tests', 'unistd', 'truncate.c'), 'r').read() expected = open(path_from_root('tests', 'unistd', 'truncate.out'), 'r').read() - self.do_run(src, expected, post_build=add_pre_run) + self.do_run(src, expected) def test_unistd_swab(self): src = open(path_from_root('tests', 'unistd', 'swab.c'), 'r').read() @@ -7339,18 +7683,11 @@ def process(filename): self.do_run(src, 'success', force_c=True) def test_unistd_links(self): - add_pre_run = ''' -def process(filename): - import tools.shared as shared - src = open(filename, 'r').read().replace( - '// {{PRE_RUN_ADDITIONS}}', - open(shared.path_from_root('tests', 'unistd', 'links.js'), 'r').read() - ) - open(filename, 'w').write(src) -''' + if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code + if not self.is_le32(): return self.skip('le32 needed for inline js') src = open(path_from_root('tests', 'unistd', 'links.c'), 'r').read() expected = open(path_from_root('tests', 'unistd', 'links.out'), 'r').read() - self.do_run(src, expected, post_build=add_pre_run) + self.do_run(src, expected) def test_unistd_sleep(self): src = open(path_from_root('tests', 'unistd', 'sleep.c'), 'r').read() @@ -7358,18 +7695,12 @@ def process(filename): self.do_run(src, expected) def test_unistd_io(self): - add_pre_run = ''' -def process(filename): - import tools.shared as shared - src = open(filename, 'r').read().replace( - '// {{PRE_RUN_ADDITIONS}}', - open(shared.path_from_root('tests', 'unistd', 'io.js'), 'r').read() - ) - open(filename, 'w').write(src) -''' + if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code + if not self.is_le32(): return self.skip('le32 needed for inline js') + if self.run_name == 'o2': return self.skip('non-asm optimized builds can fail with inline js') src = open(path_from_root('tests', 'unistd', 'io.c'), 'r').read() expected = open(path_from_root('tests', 'unistd', 'io.out'), 'r').read() - self.do_run(src, expected, post_build=add_pre_run) + self.do_run(src, expected) def test_unistd_misc(self): src = open(path_from_root('tests', 'unistd', 'misc.c'), 'r').read() diff --git a/tests/test_other.py b/tests/test_other.py index fd1a6245..627995e9 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -281,54 +281,65 @@ f.close() if os.name == 'nt': make_command = 'mingw32-make' - emscriptencmaketoolchain = path_from_root('cmake', 'Platform', 'Emscripten.cmake') + generator = 'MinGW Makefiles' + emconfigure = path_from_root('emconfigure.bat') else: make_command = 'make' - emscriptencmaketoolchain = path_from_root('cmake', 'Platform', 'Emscripten_unix.cmake') + generator = 'Unix Makefiles' + emconfigure = path_from_root('emconfigure') cmake_cases = ['target_js', 'target_html'] cmake_outputs = ['hello_world.js', 'hello_world_gles.html'] - for i in range(0, 2): + for i in range(0, 2): # Test both JS and HTML build outputs from CMake. for configuration in ['Debug', 'Release']: - - # Create a temp workspace folder - cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i]) - tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR) - try: - os.chdir(tempdirname) - - # Run Cmake - cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+emscriptencmaketoolchain, - '-DCMAKE_BUILD_TYPE=' + configuration, - '-DCMAKE_MODULE_PATH=' + path_from_root('cmake').replace('\\', '/'), - '-G' 'Unix Makefiles', cmakelistsdir] - ret = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() - if ret[1] != None and len(ret[1].strip()) > 0: - print >> sys.stderr, ret[1] # If there were any errors, print them directly to console for diagnostics. - if 'error' in ret[1].lower(): - print >> sys.stderr, 'Failed command: ' + ' '.join(cmd) - print >> sys.stderr, 'Result:\n' + ret[1] - raise Exception('cmake call failed!') - assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!' - - # Build - cmd = [make_command] - ret = Popen(cmd, stdout=PIPE).communicate() - if ret[1] != None and len(ret[1].strip()) > 0: - print >> sys.stderr, ret[1] # If there were any errors, print them directly to console for diagnostics. - if 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower(): - print >> sys.stderr, 'Failed command: ' + ' '.join(cmd) - print >> sys.stderr, 'Result:\n' + ret[0] - raise Exception('make failed!') - assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i] - - # Run through node, if CMake produced a .js file. - if cmake_outputs[i].endswith('.js'): - ret = Popen(listify(NODE_JS) + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0] - assert 'hello, world!' in ret, 'Running cmake-based .js application failed!' - finally: - os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove. - shutil.rmtree(tempdirname) + # CMake can be invoked in two ways, using 'emconfigure cmake', or by directly running 'cmake'. + # Test both methods. + for invoke_method in ['cmake', 'emconfigure']: + + # Create a temp workspace folder + cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i]) + tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR) + try: + os.chdir(tempdirname) + + verbose_level = int(os.getenv('EM_BUILD_VERBOSE')) if os.getenv('EM_BUILD_VERBOSE') != None else 0 + + # Run Cmake + if invoke_method == 'cmake': + # Test invoking cmake directly. + cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Platform', 'Emscripten.cmake'), + '-DCMAKE_BUILD_TYPE=' + configuration, '-G', generator, cmakelistsdir] + else: + # Test invoking via 'emconfigure cmake' + cmd = [emconfigure, 'cmake', '-DCMAKE_BUILD_TYPE=' + configuration, '-G', generator, cmakelistsdir] + + ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE, stderr=None if verbose_level >= 1 else PIPE).communicate() + if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0: + logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics. + if len(ret) > 1 and ret[1] != None and 'error' in ret[1].lower(): + logging.error('Failed command: ' + ' '.join(cmd)) + logging.error('Result:\n' + ret[1]) + raise Exception('cmake call failed!') + assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!' + + # Build + cmd = [make_command] + (['VERBOSE=1'] if verbose_level >= 3 else []) + ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE).communicate() + if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0: + logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics. + if len(ret) > 0 and ret[0] != None and 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower(): + logging.error('Failed command: ' + ' '.join(cmd)) + logging.error('Result:\n' + ret[0]) + raise Exception('make failed!') + assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i] + + # Run through node, if CMake produced a .js file. + if cmake_outputs[i].endswith('.js'): + ret = Popen(listify(NODE_JS) + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0] + assert 'hello, world!' in ret, 'Running cmake-based .js application failed!' + finally: + os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove. + shutil.rmtree(tempdirname) def test_failure_error_code(self): for compiler in [EMCC, EMXX]: @@ -1884,3 +1895,12 @@ you should see two lines of text in different colors and a blue rectangle SDL_Quit called (and ignored) done. ''' in output, output + + def test_preprocess(self): + self.clear() + + out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-E'], stdout=PIPE).communicate() + assert not os.path.exists('a.out.js') + assert '''tests/hello_world.c"''' in out + assert '''printf("hello, world!''' in out + diff --git a/tests/unistd/access.c b/tests/unistd/access.c index 89428610..4d5ba08e 100644 --- a/tests/unistd/access.c +++ b/tests/unistd/access.c @@ -1,8 +1,16 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> +#include <emscripten.h> int main() { + EM_ASM( + FS.writeFile('/forbidden', ''); FS.chmod('/forbidden', 0000); + FS.writeFile('/readable', ''); FS.chmod('/readable', 0444); + FS.writeFile('/writeable', ''); FS.chmod('/writeable', 0222); + FS.writeFile('/allaccess', ''); FS.chmod('/allaccess', 0777); + ); + char* files[] = {"/readable", "/writeable", "/allaccess", "/forbidden", "/nonexistent"}; for (int i = 0; i < sizeof files / sizeof files[0]; i++) { diff --git a/tests/unistd/access.js b/tests/unistd/access.js deleted file mode 100644 index ea9e6359..00000000 --- a/tests/unistd/access.js +++ /dev/null @@ -1,4 +0,0 @@ -FS.createDataFile('/', 'forbidden', '', false, false); -FS.createDataFile('/', 'readable', '', true, false); -FS.createDataFile('/', 'writeable', '', false, true); -FS.createDataFile('/', 'allaccess', '', true, true); diff --git a/tests/unistd/access.out b/tests/unistd/access.out index dffe0b9e..d462e5a5 100644 --- a/tests/unistd/access.out +++ b/tests/unistd/access.out @@ -2,8 +2,8 @@ F_OK(/readable): 0 errno: 0 R_OK(/readable): 0 errno: 0 -X_OK(/readable): 0 -errno: 0 +X_OK(/readable): -1 +errno: 13 W_OK(/readable): -1 errno: 13 diff --git a/tests/unistd/curdir.c b/tests/unistd/curdir.c index 63b9c7fe..b9f22dd7 100644 --- a/tests/unistd/curdir.c +++ b/tests/unistd/curdir.c @@ -2,8 +2,19 @@ #include <errno.h> #include <unistd.h> #include <fcntl.h> +#include <emscripten.h> int main() { + EM_ASM( + var dummy_device = FS.makedev(64, 0); + FS.registerDevice(dummy_device, {}); + FS.mkdev('/device', dummy_device); + + FS.mkdir('/folder'); + FS.symlink('/folder', '/link'); + FS.writeFile('/file', '', { mode: 0777 }); + ); + char buffer[256]; printf("getwd: %s\n", getwd(buffer)); printf("errno: %d\n", errno); diff --git a/tests/unistd/curdir.js b/tests/unistd/curdir.js deleted file mode 100644 index 75a1d2ce..00000000 --- a/tests/unistd/curdir.js +++ /dev/null @@ -1,7 +0,0 @@ -var dummy_device = FS.makedev(64, 0); -FS.registerDevice(dummy_device, {}); - -FS.createDataFile('/', 'file', '', true, true); -FS.createFolder('/', 'folder', true, true); -FS.mkdev('/device', 0666, dummy_device); -FS.createLink('/', 'link', 'folder', true, true); diff --git a/tests/unistd/io.c b/tests/unistd/io.c index a96290ef..0ff5f4fb 100644 --- a/tests/unistd/io.c +++ b/tests/unistd/io.c @@ -3,8 +3,58 @@ #include <unistd.h> #include <fcntl.h> #include <string.h> +#include <emscripten.h> int main() { + EM_ASM( + var major = 80; + + var device = FS.makedev(major++, 0); + FS.registerDevice(device, { + open: function(stream) { + stream.payload = [65, 66, 67, 68]; + }, + read: function(stream, buffer, offset, length, pos) { + var bytesRead = 0; + for (var i = 0; i < length; i++) { + if (stream.payload.length) { + bytesRead++; + buffer[offset+i] = stream.payload.shift(); + } else { + break; + } + } + return bytesRead; + }, + write: function(stream, buffer, offset, length, pos) { + for (var i = 0; i < length; i++) { + Module.print('TO DEVICE: ' + buffer[offset+i]); + } + return i; + } + }); + FS.mkdev('/device', device); + + var broken_device = FS.makedev(major++, 0); + FS.registerDevice(broken_device, { + read: function(stream, buffer, offset, length, pos) { + throw new FS.ErrnoError(ERRNO_CODES.EIO); + }, + write: function(stream, buffer, offset, length, pos) { + throw new FS.ErrnoError(ERRNO_CODES.EIO); + } + }); + FS.mkdev('/broken-device', broken_device); + + // NB: These are meant to test FS.createDevice specifically, + // and as such do not use registerDevice/mkdev + FS.createDevice('/', 'createDevice-read-only', function() {}); + FS.createDevice('/', 'createDevice-write-only', null, function() {}); + + FS.mkdir('/folder', 0777); + FS.writeFile('/file', '1234567890'); + ); + char readBuffer[256] = {0}; char writeBuffer[] = "writeme"; diff --git a/tests/unistd/io.js b/tests/unistd/io.js deleted file mode 100644 index 11c0da79..00000000 --- a/tests/unistd/io.js +++ /dev/null @@ -1,52 +0,0 @@ -(function() { - var major = 80; - - var device = FS.makedev(major++, 0); - var device_ops = { - open: function(stream) { - stream.payload = [65, 66, 67, 68]; - }, - read: function(stream, buffer, offset, length, pos) { - var bytesRead = 0; - for (var i = 0; i < length; i++) { - if (stream.payload.length) { - bytesRead++; - buffer[offset+i] = stream.payload.shift(); - } else { - break; - } - } - return bytesRead; - }, - write: function(stream, buffer, offset, length, pos) { - for (var i = 0; i < length; i++) { - Module.print("TO DEVICE: " + buffer[offset+i]); - } - return i; - } - }; - FS.registerDevice(device, device_ops); - - FS.mkdev('/device', 0666, device); - - var broken_device = FS.makedev(major++, 0); - var broken_device_ops = { - read: function(stream, buffer, offset, length, pos) { - throw new FS.ErrnoError(ERRNO_CODES.EIO); - }, - write: function(stream, buffer, offset, length, pos) { - throw new FS.ErrnoError(ERRNO_CODES.EIO); - } - }; - FS.registerDevice(broken_device, broken_device_ops); - - FS.mkdev('/broken-device', 0666, broken_device); - - // NB: These are meant to test FS.createDevice specifically, - // and as such do not use registerDevice/mkdev - FS.createDevice('/', 'createDevice-read-only', function() {}); - FS.createDevice('/', 'createDevice-write-only', null, function() {}); - - FS.createDataFile('/', 'file', '1234567890', true, true); - FS.createFolder('/', 'folder', true, true); -})(); diff --git a/tests/unistd/links.c b/tests/unistd/links.c index c6da83b9..5b403c1f 100644 --- a/tests/unistd/links.c +++ b/tests/unistd/links.c @@ -1,8 +1,15 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> +#include <emscripten.h> int main() { + EM_ASM( + FS.symlink('../test/../there!', '/link'); + FS.writeFile('/file', 'test'); + FS.mkdir('/folder'); + ); + char* files[] = {"/link", "/file", "/folder"}; char buffer[256] = {0}; diff --git a/tests/unistd/links.js b/tests/unistd/links.js deleted file mode 100644 index 5e58a729..00000000 --- a/tests/unistd/links.js +++ /dev/null @@ -1,3 +0,0 @@ -FS.createLink('/', 'link', '../test/../there!', true, true); -FS.createDataFile('/', 'file', 'test', true, true); -FS.createFolder('/', 'folder', true, true); diff --git a/tests/unistd/truncate.c b/tests/unistd/truncate.c index 18920976..b1d9fc96 100644 --- a/tests/unistd/truncate.c +++ b/tests/unistd/truncate.c @@ -4,8 +4,15 @@ #include <fcntl.h> #include <sys/stat.h> #include <string.h> +#include <emscripten.h> int main() { + EM_ASM( + FS.writeFile('/towrite', 'abcdef'); + FS.writeFile('/toread', 'abcdef'); + FS.chmod('/toread', 0444); + ); + struct stat s; int f = open("/towrite", O_WRONLY); int f2 = open("/toread", O_RDONLY); diff --git a/tests/unistd/truncate.js b/tests/unistd/truncate.js deleted file mode 100644 index 6a4c6868..00000000 --- a/tests/unistd/truncate.js +++ /dev/null @@ -1,2 +0,0 @@ -FS.createDataFile('/', 'towrite', 'abcdef', true, true); -FS.createDataFile('/', 'toread', 'abcdef', true, false); |