Ver código fonte

ES6module cyclic imports fix and test enhancements

	1) ES6module: cyclic imports (Issue#2800)

(Reference: Issue2681/2702)

For ES6 module support, module import and resolution depends on a counter ("numPendingChildModule") to increment when a child module is identified and decrement when the child module "notifies" its parent module.

This breaks down when there imports forms a cycle, e.g. `mod0 > mod1 > mod2 > mod0` (">" represents left-side module imports right-side module). In this case, the counter stays at one indefinitely and none of these modules involved is instantiated.

Proposed fix is to break the cycle by checking the "wasParsed" flag of the child module, changed from false to true right after the parser has done processing the module code successfully. Once the "wasParsed" flag is set to "true", the child module will either resolve all its dependencies and be ready for instantiation, or find itself/dependencies in error state. Both cases will cause its parent module to be notified and decrement the counter, except when loading fails in the host.

The "readyAsChildModule" flag that indicates parent notification is renamed to "parentsNotified" and retained for assertion purpose.

	2) Unit test framework improvement for module

Cyclic imports were nominally covered in unit tests but did not catch Issue#2800. This is because module-related unit tests use WScript.LoadModule() that failed silently when modules fail to instantiate. We need an update on unit test framework to collect and tally results from tests that are launched asynchronously.

Proposed changes to the unit test framework augments testRunner APIs by 1) adding tracking of asynchronously launched code in runTest(); 2) adding testRunner.LoadModule() as a promise-friendly wrapper for Wscript.LoadModule(). Module tests therefore go through the extra step of checking asynchronously launched code, which have to complete with no error in order for the tests to pass.

	3) ModuleNamespace initialization triggers singleton instance assertion (Issue #2840)

Instances of ModuleNamespace share the same type object moduleNamespaceType in JavascriptLibrary. Need to mark the same as shared to avoid singleton instance logic in type handler classes.

	4) Tracing for module

This changeset also includes tracing and assertions for module.
Suwei Chen 9 anos atrás
pai
commit
e08cf3226f

+ 1 - 0
lib/Common/ConfigFlagsList.h

@@ -5,6 +5,7 @@
 #ifdef PHASE
 PHASE(All)
     PHASE(BGJit)
+    PHASE(Module)
     PHASE(LibInit)
         PHASE(JsLibInit)
     PHASE(Parse)

+ 31 - 4
lib/Runtime/Language/SourceTextModuleRecord.cpp

@@ -36,7 +36,9 @@ namespace Js
         resolvedExportMap(nullptr),
         wasParsed(false),
         wasDeclarationInitialized(false),
-        readyAsChildModule(false),
+#if DBG
+        parentsNotified(false),
+#endif
         isRootModule(false),
         hadNotifyHostReady(false),
         localExportSlots(nullptr),
@@ -86,6 +88,7 @@ namespace Js
 
     HRESULT SourceTextModuleRecord::ParseSource(__in_bcount(sourceLength) byte* sourceText, uint32 sourceLength, SRCINFO * srcInfo, Var* exceptionVar, bool isUtf8)
     {
+        OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("ParseSource(%s)\n"), this->GetSpecifierSz());
         Assert(!wasParsed);
         Assert(parser == nullptr);
         HRESULT hr = NOERROR;
@@ -170,6 +173,8 @@ namespace Js
             {
                 this->errorObject = *exceptionVar;
             }
+
+            OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("\t>NotifyParentAsNeeded\n"));
             NotifyParentsAsNeeded();
         }
         return hr;
@@ -185,6 +190,9 @@ namespace Js
                 parentModule->OnChildModuleReady(this, this->errorObject);
             });
         }
+#if DBG
+        SetParentsNotified();
+#endif
     }
 
     void SourceTextModuleRecord::ImportModuleListsFromParser()
@@ -214,12 +222,13 @@ namespace Js
 
     HRESULT SourceTextModuleRecord::PrepareForModuleDeclarationInitialization()
     {
+        OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("PrepareForModuleDeclarationInitialization(%s)\n"), this->GetSpecifierSz());
         HRESULT hr = NO_ERROR;
 
         if (numPendingChildrenModule == 0)
         {
+            OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("\t>NotifyParentsAsNeeded\n"));
             NotifyParentsAsNeeded();
-            SetReadyAsChildModule();
 
             if (!WasDeclarationInitialized() && isRootModule)
             {
@@ -236,11 +245,18 @@ namespace Js
                 }
             }
         }
+#if DBG
+        else
+        {
+            OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("\tnumPendingChildrenModule=(%d)\n"), numPendingChildrenModule);
+        }
+#endif
         return hr;
     }
 
     HRESULT SourceTextModuleRecord::OnChildModuleReady(SourceTextModuleRecord* childModule, Var childException)
     {
+        OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("OnChildModuleReady(%s)\n"), this->GetSpecifierSz(), childModule->GetSpecifierSz());
         HRESULT hr = NOERROR;
         if (childException != nullptr)
         {
@@ -249,6 +265,8 @@ namespace Js
             {
                 this->errorObject = childException;
             }
+
+            OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("\t>NotifyParentAsNeeded (childException)\n"), this->GetSpecifierSz());
             NotifyParentsAsNeeded();
             if (isRootModule && !hadNotifyHostReady)
             {
@@ -573,7 +591,7 @@ namespace Js
         {
             parentRecord->childrenModuleSet->AddNew(moduleName, this);
 
-            if (!this->ReadyAsChildModule())
+            if (!this->WasParsed())
             {
                 if (this->parentModuleList == nullptr)
                 {
@@ -593,6 +611,8 @@ namespace Js
 
     HRESULT SourceTextModuleRecord::ResolveExternalModuleDependencies()
     {
+        OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("ResolveExternalModuleDependencies(%s)\n"), this->GetSpecifierSz());
+
         ScriptContext* scriptContext = GetScriptContext();
 
         HRESULT hr = NOERROR;
@@ -616,6 +636,7 @@ namespace Js
                         return true;
                     }
                     moduleRecord = SourceTextModuleRecord::FromHost(moduleRecordBase);
+                    OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("\t>SetParent in (%s)\n"), moduleRecord->GetSpecifierSz());
                     moduleRecord->SetParent(this, moduleName);
                 }
                 return false;
@@ -625,6 +646,7 @@ namespace Js
                 JavascriptError *error = scriptContext->GetLibrary()->CreateError();
                 JavascriptError::SetErrorMessageProperties(error, hr, _u("fetch import module failed"), scriptContext);
                 this->errorObject = error;
+                OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("\tfetch import module failed\n"));
                 NotifyParentsAsNeeded();
             }
         }
@@ -643,6 +665,7 @@ namespace Js
 
     void SourceTextModuleRecord::ModuleDeclarationInstantiation()
     {
+        OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("ModuleDeclarationInstantiation(%s)\n"), this->GetSpecifierSz());
         ScriptContext* scriptContext = GetScriptContext();
 
         if (this->WasDeclarationInitialized())
@@ -666,6 +689,7 @@ namespace Js
 
         if (this->errorObject != nullptr)
         {
+            OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("\t>NotifyParentsAsNeeded (errorObject)\n"));
             NotifyParentsAsNeeded();
             return;
         }
@@ -688,6 +712,7 @@ namespace Js
         if (rootFunction == nullptr)
         {
             this->errorObject = JavascriptError::CreateFromCompileScriptException(scriptContext, &se);
+            OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("\t>NotifyParentAsNeeded rootFunction == nullptr\n"));
             NotifyParentsAsNeeded();
         }
         else
@@ -698,6 +723,8 @@ namespace Js
 
     Var SourceTextModuleRecord::ModuleEvaluation()
     {
+        OUTPUT_TRACE_DEBUGONLY(Js::ModulePhase, _u("ModuleEvaluation(%s)\n"), this->GetSpecifierSz());
+
 #if DBG
         if (childrenModuleSet != nullptr)
         {
@@ -720,7 +747,7 @@ namespace Js
         Assert(!WasEvaluated());
         SetWasEvaluated();
         // we shouldn't evaluate if there are existing failure. This is defense in depth as the host shouldn't
-        // call into evaluation if there was previous fialure on the module.
+        // call into evaluation if there was previous failure on the module.
         if (this->errorObject)
         {
             return this->errorObject;

+ 8 - 3
lib/Runtime/Language/SourceTextModuleRecord.h

@@ -47,6 +47,7 @@ namespace Js
 
         void SetSpecifier(Var specifier) { this->normalizedSpecifier = specifier; }
         Var GetSpecifier() const { return normalizedSpecifier; }
+        const char16 *GetSpecifierSz() const { return JavascriptString::FromVar(this->normalizedSpecifier)->GetSz(); }
 
         Var GetErrorObject() const { return errorObject; }
 
@@ -54,8 +55,10 @@ namespace Js
         void SetWasParsed() { wasParsed = true; }
         bool WasDeclarationInitialized() const { return wasDeclarationInitialized; }
         void SetWasDeclarationInitialized() { wasDeclarationInitialized = true; }
-        bool ReadyAsChildModule() const { return readyAsChildModule; }
-        void SetReadyAsChildModule() { readyAsChildModule = true; }
+#if DBG
+        bool ParentsNotified() const { return parentsNotified; }
+        void SetParentsNotified() { parentsNotified = true; }
+#endif
         void SetIsRootModule() { isRootModule = true; }
 
         void SetImportRecordList(ModuleImportOrExportEntryList* importList) { importRecordList = importList; }
@@ -109,7 +112,9 @@ namespace Js
         // This is the parsed tree resulted from compilation. 
         Field(bool) wasParsed;
         Field(bool) wasDeclarationInitialized;
-        Field(bool) readyAsChildModule;
+#if DBG
+        Field(bool) parentsNotified;
+#endif
         Field(bool) isRootModule;
         Field(bool) hadNotifyHostReady;
         Field(ParseNodePtr) parseTree;

+ 1 - 0
lib/Runtime/Library/JavascriptLibrary.cpp

@@ -517,6 +517,7 @@ namespace Js
         if (config->IsES6ModuleEnabled())
         {
             moduleNamespaceType = DynamicType::New(scriptContext, TypeIds_ModuleNamespace, nullValue, nullptr, &SharedNamespaceSymbolTypeHandler);
+            moduleNamespaceType->ShareType();
         }
 
         // Initialize Date types

+ 140 - 12
test/UnitTestFramework/UnitTestFramework.js

@@ -13,17 +13,24 @@
 //   How to define and run tests:
 //     var tests = [ { name: "test name 1", body: function () {} }, ...];
 //     testRunner.run(tests);
+//
 //   How to output "pass" only if run passes so that we can skip baseline:
 //     testRunner.run(tests, {verbose: false});
 //     Or do this only when "summary" is given on command line:
 //          jshost   -args summary -endargs
 //          testRunner.run(tests, { verbose: WScript.Arguments[0] != "summary" });
+//
+//   How to launch module code
+//     testRunner.LoadModule(source, context, shouldFail)
+//     example: testRunner.LoadModule(source, 'samethread', false);
+//
 //   How to use assert:
 //     assert.areEqual(expected, actual, "those two should be equal");
 //     assert.areNotEqual(expected, actual, "those two should NOT be equal");
 //     assert.fail("error");
 //     assert.throws(function, SyntaxError);
 //     assert.doesNotThrow(function, "this function should not throw anything");
+//
 //   Some useful helpers:
 //     helpers.writeln("works in both", "console", "and", "browser);
 //     helpers.printObject(WScript);
@@ -105,14 +112,50 @@ var testRunner = function testRunner() {
     var passedTestCount = 0;
     var objectType = "object";
     var _verbose = true; // If false, try to output "pass" only for passed run so we can skip baseline.
+    var _asyncMode = false;  // If true, run tests in asynchronous mode
+    var _hasAsyncTestPromise = false;
+
+    var asyncTest = {
+        "promise" : [],
+        "resolve" : []
+    };
+
+    var testRunner = {
+        isAsyncTest: function isAsyncTest() {
+            return _asyncMode;
+        },
+
+        getAsyncTestIndex: function getAsyncTestIndex() {
+            return asyncTest.testIndex;
+        },
+
+        asyncTestErr: function asyncTestErr(testIndex, str) {
+            asyncTest.error[testIndex] += str + "\n";
+        },
+
+        asyncTestHasNoErr: function asyncTestHasNoErr(testIndex) {
+            return asyncTest.error[testIndex] == "";
+        },
+
+        asyncTestCompleted: function asyncTestCompleted(testIndex) {
+            for (var i in asyncTest.resolve[testIndex]) {
+                if (asyncTest.resolve[testIndex][i] != 0) {
+                    return false;
+                }
+            }
+            return true;
+        },
 
-    return {
         runTests: function runTests(testsToRun, options) {
             ///<summary>Runs provided tests.<br/>
             /// The 'testsToRun' is an object that has enumerable properties,<br/>
             /// each property is an object that has 'name' and 'body' properties.
+            /// Also collects and tallies error output of asynchronously executed code.
             ///</summary>
 
+            asyncTest.count = new Array(testsToRun.length).fill(0);
+            asyncTest.error = new Array(testsToRun.length).fill("");
+
             if (options && options.hasOwnProperty("verbose")) {
                 _verbose = options.verbose;
             }
@@ -124,11 +167,53 @@ var testRunner = function testRunner() {
                 }
             }
 
-            if (_verbose || executedTestCount != passedTestCount) {
-                helpers.writeln("Summary of tests: total executed: ", executedTestCount,
-                  "; passed: ", passedTestCount, "; failed: ", executedTestCount - passedTestCount);
+            if (!_hasAsyncTestPromise) {
+                if (_verbose || executedTestCount != passedTestCount) {
+                    helpers.writeln(`Summary of tests: total executed: ${executedTestCount}; passed: ${passedTestCount}; failed: ${executedTestCount - passedTestCount}`);
+                } else {
+                    helpers.writeln("pass");
+                }
             } else {
-                helpers.writeln("pass");
+                var promiseResolved = false;
+                var asyncTestSummary = function asyncTestSummary(executedTestCount) {
+                    var passedTestCount = 0;
+                    for (var i in testsToRun) {
+                        var completed = testRunner.asyncTestCompleted(i);
+                        var passed = completed && testRunner.asyncTestHasNoErr(i);
+                        if (!passed) {
+                            helpers.writeln(`*** Async result of test #${Number(i)+1} (${i}): ${testsToRun[i].name}`);
+                            helpers.writeln(asyncTest.error[i]);
+                            if (!completed) {
+                                helpers.writeln("NOT COMPLETED");
+                            }
+                            helpers.writeln(passed ? "PASSED" : "FAILED");
+                        } else {
+                            passedTestCount++;
+                        }
+                    }
+
+                    if (_verbose || executedTestCount != passedTestCount) {
+                        helpers.writeln(`Summary of tests: total executed: ${executedTestCount}; passed: ${passedTestCount}; failed: ${executedTestCount - passedTestCount}`);
+                    } else {
+                        helpers.writeln("pass");
+                    }
+
+                };
+
+                Promise.all(asyncTest.promise.map(Promise.all, Promise)).then( function() {
+                    asyncTestSummary(executedTestCount);
+                    promiseResolved = true;
+                    WScript.ClearTimeout(scheduledPromiseCheck);
+                });
+
+                var promiseCheck = function promiseCheck(time, keepWaiting) {
+                    if (keepWaiting && !promiseResolved) {
+                        WScript.SetTimeout(()=>promiseCheck(time, true), time);
+                    } else if (!promiseResolved) {
+                        asyncTestSummary(executedTestCount);
+                    }
+                };
+                var scheduledPromiseCheck = WScript.SetTimeout(promiseCheck, 5000);
             }
         },
 
@@ -142,12 +227,16 @@ var testRunner = function testRunner() {
             ///</summary>
             function logTestNameIf(b) {
                 if (b) {
-                    helpers.writeln("*** Running test #", executedTestCount + 1, " (", testIndex, "): ", testName);
+                    helpers.writeln(`*** Running test #${executedTestCount + 1} (${testIndex}): ${testName}`);
                 }
             }
 
             logTestNameIf(_verbose);
 
+            asyncTest.testIndex = testIndex;
+            asyncTest.promise[testIndex] = [];
+            asyncTest.resolve[testIndex] = [];
+
             var isSuccess = true;
             try {
                 testBody();
@@ -165,10 +254,40 @@ var testRunner = function testRunner() {
             } else {
                 helpers.writeln("FAILED");
             }
-
             ++executedTestCount;
+        },
+
+        asyncTestBegin: function asyncTestBegin(testIndex, testCount) {
+            _asyncMode = true;
+            asyncTest.testIndex = testIndex;
+        },
+
+        asyncTestEnd: function asyncTestEnd(testIndex, testCount) {
+            _asyncMode = false;
+            asyncTest.resolve[testIndex][testCount]();
+            asyncTest.resolve[testIndex][testCount] = 0;
+        },
+
+        prepareAsyncCode: function prepareAsyncCode(source, shouldFail) {
+            var testIndex = asyncTest.testIndex;
+            if (typeof shouldFail == "undefined" || shouldFail == false) {
+                _hasAsyncTestPromise = true;
+                var testCount = asyncTest.count[testIndex]++;
+                var promise = new Promise((resolve, reject) => {
+                    asyncTest.resolve[testIndex].push(resolve);
+                });
+                asyncTest.promise[testIndex].push(promise);
+                return `testRunner.asyncTestBegin(${testIndex}, ${testCount}); ${source};\ntestRunner.asyncTestEnd(${testIndex}, ${testCount});`;
+            } else {
+                return source;
+            }
+        },
+
+        LoadModule : function LoadModule(source, context, shouldFail) {
+            return WScript.LoadModule(testRunner.prepareAsyncCode(source, shouldFail), context);
         }
-    }
+    };
+    return testRunner;
 }(); // testRunner.
 
 var assert = function assert() {
@@ -181,6 +300,15 @@ var assert = function assert() {
         return x !== x;
     };
 
+    var throwMessage = function throwMessage(ex) {
+        if (!testRunner.isAsyncTest()) {
+            throw ex;
+        } else {
+            var message = ex.stack || ex.message || ex;
+            testRunner.asyncTestErr(testRunner.getAsyncTestIndex(), "Test threw exception: " + message);
+        }
+    }
+
     // returns true on success, and error message on failure
     var compare = function compare(expected, actual) {
         if (expected === actual) {
@@ -238,7 +366,7 @@ var assert = function assert() {
         if (result !== true) {
             var exMessage = addMessage("assert." + assertType + " failed: " + result);
             exMessage = addMessage(exMessage, message);
-            throw exMessage;
+            throwMessage(exMessage);
         }
     }
 
@@ -334,7 +462,7 @@ var assert = function assert() {
                     expectedString += " " + expectedErrorMessage;
                 }
                 var actual = exception !== noException ? exception : "<no exception>";
-                throw addMessage("assert.throws failed: expected: " + expectedString + ", actual: " + actual, message);
+                throwMessage(addMessage("assert.throws failed: expected: " + expectedString + ", actual: " + actual, message));
             }
         },
 
@@ -351,12 +479,12 @@ var assert = function assert() {
                 return;
             }
 
-            throw addMessage("assert.doesNotThrow failed: expected: <no exception>, actual: " + exception, message);
+            throwMessage(addMessage("assert.doesNotThrow failed: expected: <no exception>, actual: " + exception, message));
         },
 
         fail: function fail(message) {
             ///<summary>Can be used to fail the test.</summary>
-            throw message;
+            throwMessage(message);
         }
     }
 }(); // assert.

+ 33 - 33
test/es6/module-functionality.js

@@ -7,8 +7,8 @@
 
 WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
 
-function testModuleScript(source, message, shouldFail) {
-    let testfunc = () => WScript.LoadModule(source, 'samethread');
+function testModuleScript(source, message, shouldFail = false) {
+    let testfunc = () => testRunner.LoadModule(source, 'samethread', shouldFail);
 
     if (shouldFail) {
         let caught = false;
@@ -34,7 +34,7 @@ var tests = [
     {
         name: "Validate a simple module export",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { ModuleSimpleExport_foo } from 'ModuleSimpleExport.js';
                 assert.areEqual('ModuleSimpleExport', ModuleSimpleExport_foo(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');`;
             testModuleScript(functionBody, "Test importing a simple exported function", false);
@@ -43,7 +43,7 @@ var tests = [
     {
         name: "Validate importing from multiple modules",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { ModuleSimpleExport_foo } from 'ModuleSimpleExport.js';
                 assert.areEqual('ModuleSimpleExport', ModuleSimpleExport_foo(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');
                 import { foo2 } from 'ModuleComplexExports.js';
@@ -54,7 +54,7 @@ var tests = [
     {
         name: "Validate a variety of more complex exports",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { foo, foo2 } from 'ModuleComplexExports.js';
                 assert.areEqual('foo', foo(), 'Failed to import foo from ModuleComplexExports.js');
                 assert.areEqual('foo', foo2(), 'Failed to import foo2 from ModuleComplexExports.js');
@@ -94,7 +94,7 @@ var tests = [
     {
         name: "Import an export as a different binding identifier",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { ModuleSimpleExport_foo as foo3 } from 'ModuleSimpleExport.js';
                 assert.areEqual('ModuleSimpleExport', foo3(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');
                 import { foo2 as foo4 } from 'ModuleComplexExports.js';
@@ -105,7 +105,7 @@ var tests = [
     {
         name: "Import the same export under multiple local binding identifiers",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { ModuleSimpleExport_foo as foo3, ModuleSimpleExport_foo as foo4 } from 'ModuleSimpleExport.js';
                 assert.areEqual('ModuleSimpleExport', foo3(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');
                 assert.areEqual('ModuleSimpleExport', foo4(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');
@@ -116,7 +116,7 @@ var tests = [
     {
         name: "Exporting module changes exported value",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { target, changeTarget } from 'ModuleComplexExports.js';
                 assert.areEqual('before', target(), 'Failed to import target from ModuleComplexExports.js');
                 assert.areEqual('ok', changeTarget(), 'Failed to import changeTarget from ModuleComplexExports.js');
@@ -127,7 +127,7 @@ var tests = [
     {
         name: "Simple re-export forwards import to correct slot",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { ModuleSimpleExport_foo } from 'ModuleSimpleReexport.js';
                 assert.areEqual('ModuleSimpleExport', ModuleSimpleExport_foo(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleReexport.js');`;
             testModuleScript(functionBody, "Simple re-export from one module to another", false);
@@ -136,7 +136,7 @@ var tests = [
     {
         name: "Import of renamed re-export forwards import to correct slot",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { ModuleSimpleExport_foo as ModuleSimpleExport_baz } from 'ModuleSimpleReexport.js';
                 assert.areEqual('ModuleSimpleExport', ModuleSimpleExport_baz(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleReexport.js');`;
             testModuleScript(functionBody, "Rename simple re-export", false);
@@ -145,7 +145,7 @@ var tests = [
     {
         name: "Renamed re-export and renamed import",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { ModuleComplexReexports_foo as ModuleComplexReexports_baz } from 'ModuleComplexReexports.js';
                 assert.areEqual('bar', ModuleComplexReexports_baz(), 'Failed to import ModuleComplexReexports_foo from ModuleComplexReexports.js');`;
             testModuleScript(functionBody, "Rename already renamed re-export", false);
@@ -154,7 +154,7 @@ var tests = [
     {
         name: "Explicit export/import to default binding",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { default as baz } from 'ModuleDefaultExport1.js';
                 assert.areEqual('ModuleDefaultExport1', baz(), 'Failed to import default from ModuleDefaultExport1.js');`;
             testModuleScript(functionBody, "Explicitly export and import a local name to the default binding", false);
@@ -163,7 +163,7 @@ var tests = [
     {
         name: "Explicit import of default binding",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { default as baz } from 'ModuleDefaultExport2.js';
                 assert.areEqual('ModuleDefaultExport2', baz(), 'Failed to import default from ModuleDefaultExport2.js');`;
             testModuleScript(functionBody, "Explicitly import the default export binding", false);
@@ -172,7 +172,7 @@ var tests = [
     {
         name: "Implicitly re-export default export",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import baz from 'ModuleDefaultReexport.js';
                 assert.areEqual('ModuleDefaultExport1', baz(), 'Failed to import default from ModuleDefaultReexport.js');`;
             testModuleScript(functionBody, "Implicitly re-export the default export binding", false);
@@ -181,7 +181,7 @@ var tests = [
     {
         name: "Implicitly re-export default export and rename the imported binding",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { default as baz } from 'ModuleDefaultReexport.js';
                 assert.areEqual('ModuleDefaultExport1', baz(), 'Failed to import default from ModuleDefaultReexport.js');
                 import { not_default as bat } from 'ModuleDefaultReexport.js';
@@ -192,7 +192,7 @@ var tests = [
     {
         name: "Exporting module changes value of default export",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import ModuleDefaultExport3_default from 'ModuleDefaultExport3.js';
                 assert.areEqual(2, ModuleDefaultExport3_default, 'Failed to import default from ModuleDefaultExport3.js');
                 import ModuleDefaultExport4_default from 'ModuleDefaultExport4.js';
@@ -203,7 +203,7 @@ var tests = [
     {
         name: "Import bindings used in a nested function",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `function test() {
                     assert.areEqual('ModuleDefaultExport2', foo(), 'Failed to import default from ModuleDefaultExport2.js');
                 }
@@ -216,7 +216,7 @@ var tests = [
     {
         name: "Exported name may be any keyword",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { export as baz } from 'ModuleComplexExports.js';
                 assert.areEqual('ModuleComplexExports', baz, 'Failed to import export from ModuleDefaultExport2.js');
                 import { function as bat } from 'ModuleComplexExports.js';
@@ -238,7 +238,7 @@ var tests = [
     {
         name: "Exported name may be any keyword testing re-exports",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { switch as baz } from 'ModuleComplexReexports.js';
                 assert.areEqual('ModuleComplexExports', baz, 'Failed to import switch from ModuleComplexReexports.js');`;
             testModuleScript(functionBody, "Exported name may be a keyword including re-epxort chains", false);
@@ -247,7 +247,7 @@ var tests = [
     {
         name: "Odd case of 'export { as as as }; import { as as as };'",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { as as as } from 'ModuleComplexExports.js';
                 assert.areEqual('as', as(), 'String "as" is not reserved word');`;
             testModuleScript(functionBody, "Test 'import { as as as}'", false);
@@ -256,29 +256,29 @@ var tests = [
     {
         name: "Typeof a module export",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import _default from 'ModuleDefaultExport2.js';
                 assert.areEqual('function', typeof _default, 'typeof default export from ModuleDefaultExport2.js is function');`;
-                
-            WScript.LoadModule(functionBody, 'samethread');
+
+            testRunner.LoadModule(functionBody, 'samethread');
         }
     },
     {
         name: "Circular module dependency",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { circular_foo } from 'ModuleCircularFoo.js';
                 assert.areEqual(2, circular_foo(), 'This function calls between both modules in the circular dependency incrementing a counter in each');
                 import { circular_bar } from 'ModuleCircularBar.js';
                 assert.areEqual(4, circular_bar(), 'Second call originates in the other module but still increments the counter twice');`;
-                
-            WScript.LoadModule(functionBody, 'samethread');
+
+            testRunner.LoadModule(functionBody, 'samethread');
         }
     },
     {
         name: "Implicitly re-exporting an import binding (import { foo } from ''; export { foo };)",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import { foo, baz, localfoo, bar, localfoo2, bar2, bar2 as bar3 } from 'ModuleComplexReexports.js';
                 assert.areEqual('foo', foo(), 'Simple implicit re-export');
                 assert.areEqual('foo', baz(), 'Renamed export imported and renamed during implicit re-export');
@@ -287,19 +287,19 @@ var tests = [
                 assert.areEqual('foo', localfoo2(), 'Renamed export renamed as import and implicitly re-exported');
                 assert.areEqual('foo', bar2(), 'Renamed export renamed as import and renamed again during implicit re-export');
                 assert.areEqual('foo', bar3(), 'Renamed export renamed as import renamed during implicit re-export and renamed in final import');`;
-                
-            WScript.LoadModule(functionBody, 'samethread');
+
+            testRunner.LoadModule(functionBody, 'samethread');
         }
     },
     {
         name: "Nested function in module function body which captures exported symbol doesn't create empty frame object",
-        body: function() { 
-            let functionBody = 
+        body: function() {
+            let functionBody =
                 `function foo() { };
                 export { foo };
                 function bar() { foo(); };`;
-                
-            WScript.LoadModule(functionBody, 'samethread');
+
+            testRunner.LoadModule(functionBody, 'samethread');
         }
     },
 ];

+ 0 - 383
test/es6/module-namespace.baseline

@@ -1,383 +0,0 @@
-*** Running test #1 (0): Basic import namespace
-PASSED
-*** Running test #2 (1): import namespace with verification
-PASSED
-*** Running test #3 (2): reexport only
-PASSED
-*** Running test #4 (3): complex reexport
-PASSED
-*** Running test #5 (4): namespace as prototype
-PASSED
-*** Running test #6 (5): namespace internal operations
-PASSED
-Summary of tests: total executed: 6; passed: 6; failed: 0
-default=default
-var7=undefined
-var6=undefined
-var5=undefined
-var4=undefined
-var3=5
-var2=undefined
-var1=string
-foo4=function foo() { }
-bar2=class bar { }
-foobar=function foobar() { }
-foo3=function foo() { }
-baz2=function* baz() { }
-foo2=function foo() { }
-baz=function* baz() { }
-bar=class bar { }
-foo=function foo() { }
-const6=
-const5=[object Object]
-const4=4
-const3=3
-const2=str
-let7=
-let6=[object Object]
-let5=undefined
-let4=undefined
-let3=undefined
-let2=2
-let1=undefined
-cl2=class cl2 { }
-cl1=class cl1 { }
-gn2=function* gn2() { }
-gn1=function* gn1() { }
-fn2=function fn2() { }
-fn1=function fn1() { }
-default=default
-var7=undefined
-var6=undefined
-var5=undefined
-var4=undefined
-var3=5
-var2=undefined
-var1=string
-foo4=function foo() { }
-bar2=class bar { }
-foobar=function foobar() { }
-foo3=function foo() { }
-baz2=function* baz() { }
-foo2=function foo() { }
-baz=function* baz() { }
-bar=class bar { }
-foo=function foo() { }
-const6=
-const5=[object Object]
-const4=4
-const3=3
-const2=str
-let7=
-let6=[object Object]
-let5=undefined
-let4=undefined
-let3=undefined
-let2=2
-let1=undefined
-cl2=class cl2 { }
-cl1=class cl1 { }
-gn2=function* gn2() { }
-gn1=function* gn1() { }
-fn2=function fn2() { }
-fn1=function fn1() { }
-in iterator
-bar
-bar2
-baz
-baz2
-cl1
-cl2
-const2
-const3
-const4
-const5
-const6
-default
-fn1
-fn2
-foo
-foo2
-foo3
-foo4
-foobar
-gn1
-gn2
-let1
-let2
-let3
-let4
-let5
-let6
-let7
-var1
-var2
-var3
-var4
-var5
-var6
-var7
-done with iterator
-verifyNamespace=function verifyNamespace(ns)

-{

-    var unused = 1;

-    for (var i in ns) helpers.writeln(i + " = " + ns[i]);

-    assert.areEqual(ns.var7, var7, "var7 is the same");

-    assert.areEqual(ns.var6, var6, "var6 is the same");

-    assert.areEqual(ns.var5, var5, "var5 is the same");

-    assert.areEqual(ns.var4, var4, "var4 is the same");

-    assert.areEqual(ns.var3, var3, "var3 is the same");

-    assert.areEqual(ns.var2, var2, "var2 is the same");

-    assert.areEqual(ns.var1, var1, "var1 is the same");

-    assert.areEqual(ns.foobar, foobar, "foobar is the same");

-    assert.areEqual(ns.foo4, foo, "foo4 is the same");

-    assert.areEqual(ns.baz2, baz, "baz2 is the same");

-    assert.areEqual(ns.foo3, foo, "foo3 is the same");

-    assert.areEqual(ns.bar2, bar, "bar2 is the same");

-    assert.areEqual(ns.baz, baz, "baz is the same");

-    assert.areEqual(ns.foo2, foo, "foo2 is the same");

-    assert.areEqual(ns.foo, foo, "foo is the same");

-    assert.areEqual(ns.bar, bar, "bar is the same");

-    assert.areEqual(ns.const6, const6, "const6 is the same");

-    assert.areEqual(ns.const5, const5, "const5 is the same");

-    assert.areEqual(ns.const4, const4, "const4 is the same");

-    assert.areEqual(ns.const3, const3, "const3 is the same");

-    assert.areEqual(ns.const2, const2, "const2 is the same");

-    assert.areEqual(ns.let7, let7, "let7 is the same");

-    assert.areEqual(ns.let6, let6, "let6 is the same");

-    assert.areEqual(ns.let5, let5, "let5 is the same");

-    assert.areEqual(ns.let4, let4, "let4 is the same");

-    assert.areEqual(ns.let3, let3, "let3 is the same");

-    assert.areEqual(ns.let2, let2, "let2 is the same");

-    assert.areEqual(ns.let1, let1, "let1 is the same");

-    assert.areEqual(ns.cl2, cl2, "cl2 is the same");

-    assert.areEqual(ns.cl1, cl1, "cl1 is the same");

-    assert.areEqual(ns.gn2, gn2, "gn2 is the same");

-    assert.areEqual(ns.gn1, gn1, "gn1 is the same");

-    assert.areEqual(ns.fn2, fn2, "fn2 is the same");

-    assert.areEqual(ns.fn1, fn1, "fn1 is the same");

-}
-changeContext=function changeContext()

-{

-    foo = 20;

-    var1 = 'new string';

-    var2 = 'changed';

-    var tmp = fn1;

-    fn1 = fn2;

-    fn2 = fn1;

-}
-default=default
-var7=undefined
-var6=undefined
-var5=undefined
-var4=undefined
-var3=5
-var2=undefined
-var1=string
-foo4=function foo() { }
-bar2=class bar { }
-foobar=function foobar() { }
-foo3=function foo() { }
-baz2=function* baz() { }
-foo2=function foo() { }
-baz=function* baz() { }
-bar=class bar { }
-foo=function foo() { }
-const6=
-const5=[object Object]
-const4=4
-const3=3
-const2=str
-let7=
-let6=[object Object]
-let5=undefined
-let4=undefined
-let3=undefined
-let2=2
-let1=undefined
-cl2=class cl2 { }
-cl1=class cl1 { }
-gn2=function* gn2() { }
-gn1=function* gn1() { }
-fn2=function fn2() { }
-fn1=function fn1() { }
-verifyNamespace = function verifyNamespace(ns)

-{

-    var unused = 1;

-    for (var i in ns) helpers.writeln(i + " = " + ns[i]);

-    assert.areEqual(ns.var7, var7, "var7 is the same");

-    assert.areEqual(ns.var6, var6, "var6 is the same");

-    assert.areEqual(ns.var5, var5, "var5 is the same");

-    assert.areEqual(ns.var4, var4, "var4 is the same");

-    assert.areEqual(ns.var3, var3, "var3 is the same");

-    assert.areEqual(ns.var2, var2, "var2 is the same");

-    assert.areEqual(ns.var1, var1, "var1 is the same");

-    assert.areEqual(ns.foobar, foobar, "foobar is the same");

-    assert.areEqual(ns.foo4, foo, "foo4 is the same");

-    assert.areEqual(ns.baz2, baz, "baz2 is the same");

-    assert.areEqual(ns.foo3, foo, "foo3 is the same");

-    assert.areEqual(ns.bar2, bar, "bar2 is the same");

-    assert.areEqual(ns.baz, baz, "baz is the same");

-    assert.areEqual(ns.foo2, foo, "foo2 is the same");

-    assert.areEqual(ns.foo, foo, "foo is the same");

-    assert.areEqual(ns.bar, bar, "bar is the same");

-    assert.areEqual(ns.const6, const6, "const6 is the same");

-    assert.areEqual(ns.const5, const5, "const5 is the same");

-    assert.areEqual(ns.const4, const4, "const4 is the same");

-    assert.areEqual(ns.const3, const3, "const3 is the same");

-    assert.areEqual(ns.const2, const2, "const2 is the same");

-    assert.areEqual(ns.let7, let7, "let7 is the same");

-    assert.areEqual(ns.let6, let6, "let6 is the same");

-    assert.areEqual(ns.let5, let5, "let5 is the same");

-    assert.areEqual(ns.let4, let4, "let4 is the same");

-    assert.areEqual(ns.let3, let3, "let3 is the same");

-    assert.areEqual(ns.let2, let2, "let2 is the same");

-    assert.areEqual(ns.let1, let1, "let1 is the same");

-    assert.areEqual(ns.cl2, cl2, "cl2 is the same");

-    assert.areEqual(ns.cl1, cl1, "cl1 is the same");

-    assert.areEqual(ns.gn2, gn2, "gn2 is the same");

-    assert.areEqual(ns.gn1, gn1, "gn1 is the same");

-    assert.areEqual(ns.fn2, fn2, "fn2 is the same");

-    assert.areEqual(ns.fn1, fn1, "fn1 is the same");

-}
-changeContext = function changeContext()

-{

-    foo = 20;

-    var1 = 'new string';

-    var2 = 'changed';

-    var tmp = fn1;

-    fn1 = fn2;

-    fn2 = fn1;

-}
-default = default
-var7 = undefined
-var6 = undefined
-var5 = undefined
-var4 = undefined
-var3 = 5
-var2 = undefined
-var1 = string
-foo4 = function foo() { }
-bar2 = class bar { }
-foobar = function foobar() { }
-foo3 = function foo() { }
-baz2 = function* baz() { }
-foo2 = function foo() { }
-baz = function* baz() { }
-bar = class bar { }
-foo = function foo() { }
-const6 = 
-const5 = [object Object]
-const4 = 4
-const3 = 3
-const2 = str
-let7 = 
-let6 = [object Object]
-let5 = undefined
-let4 = undefined
-let3 = undefined
-let2 = 2
-let1 = undefined
-cl2 = class cl2 { }
-cl1 = class cl1 { }
-gn2 = function* gn2() { }
-gn1 = function* gn1() { }
-fn2 = function fn2() { }
-fn1 = function fn1() { }
-verifyNamespace = function verifyNamespace(ns)

-{

-    var unused = 1;

-    for (var i in ns) helpers.writeln(i + " = " + ns[i]);

-    assert.areEqual(ns.var7, var7, "var7 is the same");

-    assert.areEqual(ns.var6, var6, "var6 is the same");

-    assert.areEqual(ns.var5, var5, "var5 is the same");

-    assert.areEqual(ns.var4, var4, "var4 is the same");

-    assert.areEqual(ns.var3, var3, "var3 is the same");

-    assert.areEqual(ns.var2, var2, "var2 is the same");

-    assert.areEqual(ns.var1, var1, "var1 is the same");

-    assert.areEqual(ns.foobar, foobar, "foobar is the same");

-    assert.areEqual(ns.foo4, foo, "foo4 is the same");

-    assert.areEqual(ns.baz2, baz, "baz2 is the same");

-    assert.areEqual(ns.foo3, foo, "foo3 is the same");

-    assert.areEqual(ns.bar2, bar, "bar2 is the same");

-    assert.areEqual(ns.baz, baz, "baz is the same");

-    assert.areEqual(ns.foo2, foo, "foo2 is the same");

-    assert.areEqual(ns.foo, foo, "foo is the same");

-    assert.areEqual(ns.bar, bar, "bar is the same");

-    assert.areEqual(ns.const6, const6, "const6 is the same");

-    assert.areEqual(ns.const5, const5, "const5 is the same");

-    assert.areEqual(ns.const4, const4, "const4 is the same");

-    assert.areEqual(ns.const3, const3, "const3 is the same");

-    assert.areEqual(ns.const2, const2, "const2 is the same");

-    assert.areEqual(ns.let7, let7, "let7 is the same");

-    assert.areEqual(ns.let6, let6, "let6 is the same");

-    assert.areEqual(ns.let5, let5, "let5 is the same");

-    assert.areEqual(ns.let4, let4, "let4 is the same");

-    assert.areEqual(ns.let3, let3, "let3 is the same");

-    assert.areEqual(ns.let2, let2, "let2 is the same");

-    assert.areEqual(ns.let1, let1, "let1 is the same");

-    assert.areEqual(ns.cl2, cl2, "cl2 is the same");

-    assert.areEqual(ns.cl1, cl1, "cl1 is the same");

-    assert.areEqual(ns.gn2, gn2, "gn2 is the same");

-    assert.areEqual(ns.gn1, gn1, "gn1 is the same");

-    assert.areEqual(ns.fn2, fn2, "fn2 is the same");

-    assert.areEqual(ns.fn1, fn1, "fn1 is the same");

-}
-changeContext = function changeContext()

-{

-    foo = 20;

-    var1 = 'new string';

-    var2 = 'changed';

-    var tmp = fn1;

-    fn1 = fn2;

-    fn2 = fn1;

-}
-default = default
-var7 = undefined
-var6 = undefined
-var5 = undefined
-var4 = undefined
-var3 = 5
-var2 = changed
-var1 = new string
-foo4 = 20
-bar2 = class bar { }
-foobar = function foobar() { }
-foo3 = 20
-baz2 = function* baz() { }
-foo2 = 20
-baz = function* baz() { }
-bar = class bar { }
-foo = 20
-const6 = 
-const5 = [object Object]
-const4 = 4
-const3 = 3
-const2 = str
-let7 = 
-let6 = [object Object]
-let5 = undefined
-let4 = undefined
-let3 = undefined
-let2 = 2
-let1 = undefined
-cl2 = class cl2 { }
-cl1 = class cl1 { }
-gn2 = function* gn2() { }
-gn1 = function* gn1() { }
-fn2 = function fn2() { }
-fn1 = function fn2() { }
-foo=function foo() { }
-bar=class bar { }
-baz=function* baz() { }
-foo2=function foo() { }
-bar2=class bar { }
-foo3=function foo() { }
-ModuleComplexReexports_foo=function bar() { return 'bar'; }
-switch=undefined
-bar2=function foo() { return 'foo'; }
-localfoo2=function foo() { return 'foo'; }
-bar=function foo() { return 'foo'; }
-localfoo=function foo() { return 'foo'; }
-baz=function foo() { return 'foo'; }
-foo=function foo() { return 'foo'; }

+ 142 - 14
test/es6/module-namespace.js

@@ -7,8 +7,8 @@
 
 WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
 
-function testModuleScript(source, message, shouldFail) {
-    let testfunc = () => WScript.LoadModule(source);
+function testModuleScript(source, message, shouldFail = false) {
+    let testfunc = () => testRunner.LoadModule(source, undefined, shouldFail);
 
     if (shouldFail) {
         let caught = false;
@@ -34,39 +34,169 @@ var tests = [
     {
         name: "Basic import namespace",
         body: function () {
-           testModuleScript('import * as foo from "ValidExportStatements.js"; for (var i in foo) helpers.writeln(i + "=" + foo[i]);', '', false);
-       }
+			testModuleScript(`
+			import * as foo from "ValidExportStatements.js";
+			assert.areEqual("default", foo.default, "default");
+			assert.areEqual(undefined, foo.var7, "var7");
+			assert.areEqual(undefined, foo.var6, "var6");
+			assert.areEqual(undefined, foo.var5, "var5");
+			assert.areEqual(undefined, foo.var4, "var4");
+			assert.areEqual(5, foo.var3, "var3");
+			assert.areEqual(undefined, foo.var2, "var2");
+			assert.areEqual("string", foo.var1, "var1");
+			assert.areEqual("function foo() { }", foo.foo4.toString(), "foo4");
+			assert.areEqual("class bar { }", foo.bar2.toString(), "bar2");
+			assert.areEqual("function foobar() { }", foo.foobar.toString(), "foobar");
+			assert.areEqual("function foo() { }", foo.foo3.toString(), "foo3");
+			assert.areEqual("function* baz() { }", foo.baz2.toString(), "baz2");
+			assert.areEqual("function foo() { }", foo.foo2.toString(), "foo2");
+			assert.areEqual("function* baz() { }", foo.baz.toString(), "baz");
+			assert.areEqual("class bar { }", foo.bar.toString(), "bar");
+			assert.areEqual("function foo() { }", foo.foo.toString(), "foo");
+			assert.areEqual([], foo.const6, "const6");
+			assert.areEqual({}, foo.const5, "const5");
+			assert.areEqual(4, foo.const4, "const4");
+			assert.areEqual(3, foo.const3, "const3");
+			assert.areEqual("str", foo.const2, "const2");
+			assert.areEqual([], foo.let7, "let7");
+			assert.areEqual({}, foo.let6, "let6");
+			assert.areEqual(undefined, foo.let5, "let5");
+			assert.areEqual(undefined, foo.let4, "let4");
+			assert.areEqual(undefined, foo.let3, "let3");
+			assert.areEqual(2, foo.let2, "let2");
+			assert.areEqual(undefined, foo.let1, "let1");
+			assert.areEqual("class cl2 { }", foo.cl2.toString(), "cl2");
+			assert.areEqual("class cl1 { }", foo.cl1.toString(), "cl1");
+			assert.areEqual("function* gn2() { }", foo.gn2.toString(), "gn2");
+			assert.areEqual("function* gn1() { }", foo.gn1.toString(), "gn1");
+			assert.areEqual("function fn2() { }", foo.fn2.toString(), "fn2");
+			assert.areEqual("function fn1() { }", foo.fn1.toString(), "fn1");
+		    `, '', false);
+        }
     },
     {
         name: "import namespace with verification",
         body: function () {
-           testModuleScript('import * as foo from "moduleExport1.js"; for (var i in foo) WScript.Echo(i + "=" + foo[i]);', '', false);
-           testModuleScript('import * as foo from "moduleExport1.js"; foo.verifyNamespace(foo);', '', false);
-           testModuleScript('import * as foo from "moduleExport1.js"; foo.changeContext(); foo.verifyNamespace(foo);', '', false);
+			testModuleScript(`
+			import * as foo from "moduleExport1.js";
+			assert.areEqual("default", foo.default, "default");
+			assert.areEqual(undefined, foo.var7, "var7");
+			assert.areEqual(undefined, foo.var6, "var6");
+			assert.areEqual(undefined, foo.var5, "var5");
+			assert.areEqual(undefined, foo.var4, "var4");
+			assert.areEqual(5, foo.var3, "var3");
+			assert.areEqual(undefined, foo.var2, "var2");
+			assert.areEqual("string", foo.var1, "var1");
+			assert.areEqual("function foo() { }", foo.foo4.toString(), "foo4");
+			assert.areEqual("class bar { }", foo.bar2.toString(), "bar2");
+			assert.areEqual("function foobar() { }", foo.foobar.toString(), "foobar");
+			assert.areEqual("function foo() { }", foo.foo3.toString(), "foo3");
+			assert.areEqual("function* baz() { }", foo.baz2.toString(), "baz2");
+			assert.areEqual("function foo() { }", foo.foo2.toString(), "foo2");
+			assert.areEqual("function* baz() { }", foo.baz.toString(), "baz");
+			assert.areEqual("class bar { }", foo.bar.toString(), "bar");
+			assert.areEqual("function foo() { }", foo.foo.toString(), "foo");
+			assert.areEqual([], foo.const6, "const6");
+			assert.areEqual({}, foo.const5, "const5");
+			assert.areEqual(4, foo.const4, "const4");
+			assert.areEqual(3, foo.const3, "const3");
+			assert.areEqual("str", foo.const2, "const2");
+			assert.areEqual([], foo.let7, "let7");
+			assert.areEqual({}, foo.let6, "let6");
+			assert.areEqual(undefined, foo.let5, "let5");
+			assert.areEqual(undefined, foo.let4, "let4");
+			assert.areEqual(undefined, foo.let3, "let3");
+			assert.areEqual(2, foo.let2, "let2");
+			assert.areEqual(undefined, foo.let1, "let1");
+			assert.areEqual("class cl2 { }", foo.cl2.toString(), "cl2");
+			assert.areEqual("class cl1 { }", foo.cl1.toString(), "cl1");
+			assert.areEqual("function* gn2() { }", foo.gn2.toString(), "gn2");
+			assert.areEqual("function* gn1() { }", foo.gn1.toString(), "gn1");
+			assert.areEqual("function fn2() { }", foo.fn2.toString(), "fn2");
+			assert.areEqual("function fn1() { }", foo.fn1.toString(), "fn1");
+			foo.verifyNamespace(foo);
+			foo.changeContext();
+			foo.verifyNamespace(foo);
+			`, '', false);
         }
     },
     {
         name: "reexport only",
         body: function () {
-            testModuleScript('import * as foo from "ValidReExportStatements.js"; for (var i in foo) helpers.writeln(i + "=" + foo[i]);', '', false);
+            //testModuleScript('import * as foo from "ValidReExportStatements.js"; for (var i in foo) helpers.writeln(i + "=" + foo[i]);', '', false);
+            testModuleScript(`
+			import * as foo from "ValidReExportStatements.js";
+			assert.areEqual("function foo() { }", foo.foo.toString(), "foo");
+			assert.areEqual("class bar { }", foo.bar.toString(), "bar");
+			assert.areEqual("function* baz() { }", foo.baz.toString(), "baz");
+			assert.areEqual("function foo() { }", foo.foo2.toString(), "foo2");
+			assert.areEqual("class bar { }", foo.bar2.toString(), "bar2");
+			assert.areEqual("function foo() { }", foo.foo3.toString(), "foo3");
+			`, '', false);
         }
     },
     {
         name: "complex reexport",
         body: function () {
-           testModuleScript('import * as fooComplex from "ModuleComplexReexports.js"; for (var i in fooComplex) WScript.Echo(i + "=" + fooComplex[i]);', '', false);
+            testModuleScript(`import * as fooComplex from "ModuleComplexReexports.js";
+			assert.areEqual("function bar() { return 'bar'; }", fooComplex.ModuleComplexReexports_foo.toString(), "ModuleComplexReexports_foo");
+			assert.areEqual(undefined, fooComplex.switch, "switch");
+			assert.areEqual("function foo() { return 'foo'; }", fooComplex.bar2.toString(), "bar2");
+			assert.areEqual("function foo() { return 'foo'; }", fooComplex.localfoo2.toString(), "localfoo2");
+			assert.areEqual("function foo() { return 'foo'; }", fooComplex.bar.toString(), "bar");
+			assert.areEqual("function foo() { return 'foo'; }", fooComplex.localfoo.toString(), "localfoo");
+			assert.areEqual("function foo() { return 'foo'; }", fooComplex.baz.toString(), "baz");
+			assert.areEqual("function foo() { return 'foo'; }", fooComplex.foo.toString(), "foo");
+		    `, '', false);
         }
     },
     {
         name: "namespace as prototype",
         body: function () {
-           testModuleScript('import * as foo from "ValidExportStatements.js"; var childObj = Object.create(foo); for (var i in childObj) helpers.writeln(i + "=" + childObj[i]);', '', false);
+            testModuleScript(`import * as foo from "ValidExportStatements.js";
+			var childObj = Object.create(foo);
+			assert.areEqual("default", childObj.default, "default");
+			assert.areEqual(undefined, childObj.var7, "var7");
+			assert.areEqual(undefined, childObj.var6, "var6");
+			assert.areEqual(undefined, childObj.var5, "var5");
+			assert.areEqual(undefined, childObj.var4, "var4");
+			assert.areEqual(5, childObj.var3, "var3");
+			assert.areEqual(undefined, childObj.var2, "var2");
+			assert.areEqual("string", childObj.var1, "var1");
+			assert.areEqual("function foo() { }", childObj.foo4.toString(), "foo4");
+			assert.areEqual("class bar { }", childObj.bar2.toString(), "bar2");
+			assert.areEqual("function foobar() { }", childObj.foobar.toString(), "foobar");
+			assert.areEqual("function foo() { }", childObj.foo3.toString(), "foo3");
+			assert.areEqual("function* baz() { }", childObj.baz2.toString(), "baz2");
+			assert.areEqual("function foo() { }", childObj.foo2.toString(), "foo2");
+			assert.areEqual("function* baz() { }", childObj.baz.toString(), "baz");
+			assert.areEqual("class bar { }", childObj.bar.toString(), "bar");
+			assert.areEqual("function foo() { }", childObj.foo.toString(), "foo");
+			assert.areEqual([], childObj.const6, "const6");
+			assert.areEqual({}, childObj.const5, "const5");
+			assert.areEqual(4, childObj.const4, "const4");
+			assert.areEqual(3, childObj.const3, "const3");
+			assert.areEqual("str", childObj.const2, "const2");
+			assert.areEqual([], childObj.let7, "let7");
+			assert.areEqual({}, childObj.let6, "let6");
+			assert.areEqual(undefined, childObj.let5, "let5");
+			assert.areEqual(undefined, childObj.let4, "let4");
+			assert.areEqual(undefined, childObj.let3, "let3");
+			assert.areEqual(2, childObj.let2, "let2");
+			assert.areEqual(undefined, childObj.let1, "let1");
+			assert.areEqual("class cl2 { }", childObj.cl2.toString(), "cl2");
+			assert.areEqual("class cl1 { }", childObj.cl1.toString(), "cl1");
+			assert.areEqual("function* gn2() { }", childObj.gn2.toString(), "gn2");
+			assert.areEqual("function* gn1() { }", childObj.gn1.toString(), "gn1");
+			assert.areEqual("function fn2() { }", childObj.fn2.toString(), "fn2");
+			assert.areEqual("function fn1() { }", childObj.fn1.toString(), "fn1");
+			`, '', false);
        }
     },
     {
         name: "namespace internal operations",
         body: function () {
-            let functionBody = 
+            let functionBody =
                 `import * as foo from "ValidExportStatements.js";
                 assert.areEqual(null, Object.getPrototypeOf(foo), 'namespace prototype is null');
                 assert.areEqual(false, Object.isExtensible(foo), 'namespace is not extensible');
@@ -81,8 +211,6 @@ var tests = [
                 assert.areEqual(undefined, foo[Symbol.species], 'namespace is not contructor');
                 assert.areEqual("Module", foo[Symbol.toStringTag], 'namespace toStringTag');
                 assert.areEqual("[object Module]", Object.prototype.toString.call(foo), 'Object.prototype.toString uses the module namespace @@toStringTag value');
-                helpers.writeln("in iterator"); for (var i of foo) helpers.writeln(i);
-                helpers.writeln("done with iterator")
                 var symbols = Object.getOwnPropertySymbols(foo);
                 assert.areEqual(2, symbols.length, "two symbols");
                 assert.areEqual(symbols[0], Symbol.toStringTag, "first symbol is toStringTag");
@@ -92,7 +220,7 @@ var tests = [
             testModuleScript(functionBody, "Test importing as different binding identifiers", false);
        }
     },
-   
+
 ];
 
 testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

+ 2 - 2
test/es6/module-syntax.js

@@ -7,8 +7,8 @@
 
 WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
 
-function testModuleScript(source, message, shouldFail) {
-    let testfunc = () => WScript.LoadModule(source, 'samethread');
+function testModuleScript(source, message, shouldFail = false) {
+    let testfunc = () => testRunner.LoadModule(source, 'samethread', shouldFail);
 
     if (shouldFail) {
         let caught = false;

+ 0 - 23
test/es6/module-syntax1.js

@@ -7,29 +7,6 @@
 
 WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
 
-function testModuleScript(source, message, shouldFail) {
-    let testfunc = () => WScript.LoadModule(source, 'samethread');
-    
-    if (shouldFail) {
-        let caught = false;
-        
-        // We can't use assert.throws here because the SyntaxError used to construct the thrown error
-        // is from a different context so it won't be strictly equal to our SyntaxError.
-        try {
-            testfunc();
-        } catch(e) {
-            caught = true;
-            
-            // Compare toString output of SyntaxError and other context SyntaxError constructor.
-            assert.areEqual(e.constructor.toString(), SyntaxError.toString(), message);
-        }
-        
-        assert.isTrue(caught, `Expected error not thrown: ${message}`);
-    } else {
-        assert.doesNotThrow(testfunc, message);
-    }
-}
-
 var tests = [
     {
         name: "All valid import statements",

+ 0 - 2
test/es6/moduleExport1.js

@@ -2,7 +2,6 @@
 // Copyright (C) Microsoft. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
-WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
 
 function foo() { }
 class bar { }
@@ -62,7 +61,6 @@ export function changeContext()
 export function verifyNamespace(ns)
 {
     var unused = 1;
-    for (var i in ns) helpers.writeln(i + " = " + ns[i]);
     assert.areEqual(ns.var7, var7, "var7 is the same");
     assert.areEqual(ns.var6, var6, "var6 is the same");
     assert.areEqual(ns.var5, var5, "var5 is the same");

+ 1 - 2
test/es6/rlexe.xml

@@ -1378,8 +1378,7 @@
 <test>
     <default>
         <files>module-namespace.js</files>
-        <compile-flags>-ES6Module -Es6ToStringTag</compile-flags>
-        <baseline>module-namespace.baseline</baseline>
+        <compile-flags>-ES6Module -Es6ToStringTag -args summary -endargs</compile-flags>
         <tags>exclude_sanitize_address</tags>
     </default>
 </test>