aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJez Ng <me@jezng.com>2013-06-07 15:37:47 -0700
committerJez Ng <me@jezng.com>2013-06-19 01:22:01 -0700
commit2f16717540cbeaa8e2e6b653bc31849111ccd9f2 (patch)
treea67c388de9926a2f290cbef3228e0e0ab6f4943d
parent165befaa29b7226b28caecd2f30bae91dc20f26f (diff)
Add test for source maps.
Tweak behavior of post_build; the `post2` hook now expects a function.
-rwxr-xr-xemcc4
-rwxr-xr-xtests/runner.py235
-rw-r--r--tools/sourcemap2json.js15
-rwxr-xr-xtools/sourcemapper.js10
4 files changed, 157 insertions, 107 deletions
diff --git a/emcc b/emcc
index 7eb9effa..8dc7652a 100755
--- a/emcc
+++ b/emcc
@@ -1585,9 +1585,9 @@ try:
else:
logging.debug('did not see memory initialization')
- def generate_source_maps(filename, mapFileBaseName):
+ def generate_source_maps(filename, map_file_base_name):
jsrun.run_js(shared.path_from_root('tools', 'sourcemapper.js'),
- shared.NODE_JS, [filename, os.getcwd(), mapFileBaseName])
+ shared.NODE_JS, [filename, os.getcwd(), map_file_base_name])
# If we were asked to also generate HTML, do that
if final_suffix == 'html':
diff --git a/tests/runner.py b/tests/runner.py
index 610a39f6..f90911d5 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -170,16 +170,13 @@ class RunnerCore(unittest.TestCase):
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')
-
if self.emcc_args is None:
Building.emscripten(filename, append_ext=True, extra_args=extra_emscripten_args)
- run_post(post1)
- run_post(post2)
+ if post1:
+ exec post1 in locals()
+ shutil.copyfile(filename + '.o.js', filename + '.o.js.prepost.js')
+ process(filename + '.o.js')
+ if post2: post2(filename + '.o.js')
else:
transform_args = []
if post1:
@@ -196,7 +193,7 @@ process(sys.argv[1])
transform.close()
transform_args = ['--js-transform', "%s %s" % (PYTHON, transform_filename)]
Building.emcc(filename + '.o.ll', Settings.serialize() + self.emcc_args + transform_args + Building.COMPILER_TEST_OPTS, filename + '.o.js')
- run_post(post2)
+ if post2: post2(filename + '.o.js')
# Build JavaScript code from source code
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):
@@ -9215,97 +9212,92 @@ def process(filename):
src.close()
'''
- post3 = '''
-def process(filename):
- script_src_2 = \'\'\'
- var sme = new Module.Parent(42);
- sme.mulVal(2);
- Module.print('*')
- Module.print(sme.getVal());
-
- Module.print('c1');
-
- var c1 = new Module.Child1();
- Module.print(c1.getVal());
- c1.mulVal(2);
- Module.print(c1.getVal());
- Module.print(c1.getValSqr());
- Module.print(c1.getValSqr(3));
- Module.print(c1.getValTimes()); // default argument should be 1
- Module.print(c1.getValTimes(2));
-
- Module.print('c1 v2');
-
- c1 = new Module.Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2
- Module.print(c1.getVal());
- c1.mulVal(2);
- Module.print(c1.getVal());
- Module.print(c1.getValSqr());
- Module.print(c1.getValSqr(3));
-
- Module.print('c2')
-
- var c2 = new Module.Child2();
- Module.print(c2.getVal());
- c2.mulVal(2);
- Module.print(c2.getVal());
- Module.print(c2.getValCube());
- var succeeded;
- try {
- succeeded = 0;
- Module.print(c2.doSomethingSecret()); // should fail since private
- succeeded = 1;
- } catch(e) {}
- Module.print(succeeded);
- try {
- succeeded = 0;
- Module.print(c2.getValSqr()); // function from the other class
- succeeded = 1;
- } catch(e) {}
- Module.print(succeeded);
- try {
- succeeded = 0;
- c2.getValCube(); // sanity
- succeeded = 1;
- } catch(e) {}
- Module.print(succeeded);
-
- Module.Child2.prototype.printStatic(); // static calls go through the prototype
-
- // virtual function
- c2.virtualFunc();
- Module.Child2.prototype.runVirtualFunc(c2);
- c2.virtualFunc2();
-
-''' + ('''
- // extend the class from JS
- var c3 = new Module.Child2;
- Module.customizeVTable(c3, [{
- original: Module.Child2.prototype.virtualFunc,
- replacement: function() {
- Module.print('*js virtualf replacement*');
- }
- }, {
- original: Module.Child2.prototype.virtualFunc2,
- replacement: function() {
- Module.print('*js virtualf2 replacement*');
- }
- }]);
- c3.virtualFunc();
- Module.Child2.prototype.runVirtualFunc(c3);
- c3.virtualFunc2();
-
- c2.virtualFunc(); // original should remain the same
- Module.Child2.prototype.runVirtualFunc(c2);
- c2.virtualFunc2();
-''') + '''
-
- Module.print('*ok*');
- \'\'\'
- src = open(filename, 'a')
- src.write(script_src_2 + '\\n')
- src.close()
-'''
+ def post3(filename):
+ script_src_2 = '''
+ var sme = new Module.Parent(42);
+ sme.mulVal(2);
+ Module.print('*')
+ Module.print(sme.getVal());
+
+ Module.print('c1');
+
+ var c1 = new Module.Child1();
+ Module.print(c1.getVal());
+ c1.mulVal(2);
+ Module.print(c1.getVal());
+ Module.print(c1.getValSqr());
+ Module.print(c1.getValSqr(3));
+ Module.print(c1.getValTimes()); // default argument should be 1
+ Module.print(c1.getValTimes(2));
+
+ Module.print('c1 v2');
+
+ c1 = new Module.Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2
+ Module.print(c1.getVal());
+ c1.mulVal(2);
+ Module.print(c1.getVal());
+ Module.print(c1.getValSqr());
+ Module.print(c1.getValSqr(3));
+
+ Module.print('c2')
+
+ var c2 = new Module.Child2();
+ Module.print(c2.getVal());
+ c2.mulVal(2);
+ Module.print(c2.getVal());
+ Module.print(c2.getValCube());
+ var succeeded;
+ try {
+ succeeded = 0;
+ Module.print(c2.doSomethingSecret()); // should fail since private
+ succeeded = 1;
+ } catch(e) {}
+ Module.print(succeeded);
+ try {
+ succeeded = 0;
+ Module.print(c2.getValSqr()); // function from the other class
+ succeeded = 1;
+ } catch(e) {}
+ Module.print(succeeded);
+ try {
+ succeeded = 0;
+ c2.getValCube(); // sanity
+ succeeded = 1;
+ } catch(e) {}
+ Module.print(succeeded);
+
+ Module.Child2.prototype.printStatic(); // static calls go through the prototype
+
+ // virtual function
+ c2.virtualFunc();
+ Module.Child2.prototype.runVirtualFunc(c2);
+ c2.virtualFunc2();
+
+ // extend the class from JS
+ var c3 = new Module.Child2;
+ Module.customizeVTable(c3, [{
+ original: Module.Child2.prototype.virtualFunc,
+ replacement: function() {
+ Module.print('*js virtualf replacement*');
+ }
+ }, {
+ original: Module.Child2.prototype.virtualFunc2,
+ replacement: function() {
+ Module.print('*js virtualf2 replacement*');
+ }
+ }]);
+ c3.virtualFunc();
+ Module.Child2.prototype.runVirtualFunc(c3);
+ c3.virtualFunc2();
+
+ c2.virtualFunc(); // original should remain the same
+ Module.Child2.prototype.runVirtualFunc(c2);
+ c2.virtualFunc2();
+ Module.print('*ok*');
+ '''
+ src = open(filename, 'a')
+ src.write(script_src_2 + '\n')
+ src.close()
Settings.RESERVED_FUNCTION_POINTERS = 20
@@ -9349,7 +9341,7 @@ Child2:9
*virtualf*
*virtualf2*''') + '''
*ok*
-''', post_build=[post2, post3])
+''', post_build=(post2, post3))
def test_scriptaclass_2(self):
if self.emcc_args is None: return self.skip('requires emcc')
@@ -9592,6 +9584,47 @@ def process(filename):
# This test *should* fail
assert 'Assertion failed' in str(e), str(e)
+ def test_source_map(self):
+ if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
+ if self.emcc_args is not None:
+ if '-O1' in self.emcc_args or '-O2' in self.emcc_args: return self.skip('optimizations remove LLVM debug info')
+
+ src = '''
+ #include <stdio.h>
+ #include <assert.h>
+
+ int foo() {
+ return 1; // line 6
+ }
+
+ int main() {
+ int i = foo(); // line 10
+ return 0; // line 11
+ }
+ '''
+
+ dirname = self.get_dir()
+ src_filename = os.path.join(dirname, 'src.cpp')
+
+ def post(filename):
+ import json
+ map_filename = filename + '.map'
+ data = json.load(open(map_filename, 'r'))
+ self.assertIdentical(filename, data['file'])
+ self.assertIdentical(src_filename, data['sources'][0])
+ self.assertIdentical(src, data['sourcesContent'][0])
+ mappings = json.loads(jsrun.run_js(
+ path_from_root('tools', 'sourcemap2json.js'),
+ tools.shared.NODE_JS, [map_filename]))
+ seen_lines = set()
+ for m in mappings:
+ self.assertIdentical(src_filename, m['source'])
+ seen_lines.add(m['originalLine'])
+ # ensure that all the 'meaningful' lines in the original code get mapped
+ assert seen_lines.issuperset([6, 10, 11])
+
+ self.build(src, dirname, src_filename, post_build=(None,post))
+
def test_linespecific(self):
if Settings.ASM_JS: return self.skip('asm always has corrections on')
diff --git a/tools/sourcemap2json.js b/tools/sourcemap2json.js
new file mode 100644
index 00000000..5dd162b2
--- /dev/null
+++ b/tools/sourcemap2json.js
@@ -0,0 +1,15 @@
+/*
+ * Quick utility script for the Python test script to call. Could be replaced if
+ * a good Python source map library is found.
+ */
+var SourceMapConsumer = require('source-map').SourceMapConsumer;
+var fs = require('fs');
+
+var consumer = new SourceMapConsumer(fs.readFileSync(process.argv[2], 'utf-8'));
+var mappings = [];
+
+consumer.eachMapping(function(mapping) {
+ mappings.push(mapping);
+});
+
+console.log(JSON.stringify(mappings));
diff --git a/tools/sourcemapper.js b/tools/sourcemapper.js
index 3d8dbe99..fce9251f 100755
--- a/tools/sourcemapper.js
+++ b/tools/sourcemapper.js
@@ -68,7 +68,7 @@ function generateMap(fileName, sourceRoot, mapFileBaseName) {
var path = require('path');
var SourceMapGenerator = require('source-map').SourceMapGenerator;
- var generator = new SourceMapGenerator({ file: fileName });
+ var generator = new SourceMapGenerator({ file: mapFileBaseName });
var generatedSource = fs.readFileSync(fileName, 'utf-8');
var seenFiles = Object.create(null);
@@ -80,11 +80,13 @@ function generateMap(fileName, sourceRoot, mapFileBaseName) {
if (!(originalFileName in seenFiles)) {
seenFiles[originalFileName] = true;
+ var rootedPath = originalFileName[0] === path.sep ?
+ originalFileName : path.join(sourceRoot, originalFileName);
try {
- generator.setSourceContent(originalFileName,
- fs.readFileSync(sourceRoot + "/" + originalFileName));
+ generator.setSourceContent(originalFileName, fs.readFileSync(rootedPath, 'utf-8'));
} catch (e) {
- console.warn("Unable to find original file for " + originalFileName);
+ console.warn("Unable to find original file for " + originalFileName +
+ " at " + rootedPath);
}
}