From 4b42402712227dec78ca364ab37df5c200f112bf Mon Sep 17 00:00:00 2001 From: Hiroaki Kamei Date: Sat, 1 Jun 2013 11:36:48 +0900 Subject: [PATCH 01/18] Update loadFile - support coffee-script file --- lib/util.js | 43 +++++++++++++++++-- package.json | 6 ++- test/fixtures/other.coffee | 4 ++ test/fixtures/other.litcoffee | 4 ++ test/fixtures/some.coffee | 6 +++ test/fixtures/some.litcoffee | 7 ++++ test/util.spec.coffee | 78 +++++++++++++++++++++++++++++++++++ 7 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/other.coffee create mode 100644 test/fixtures/other.litcoffee create mode 100644 test/fixtures/some.coffee create mode 100644 test/fixtures/some.litcoffee diff --git a/lib/util.js b/lib/util.js index ab24a68..5ac14b6 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,6 +1,7 @@ var vm = require('vm'); var fs = require('fs'); var path = require('path'); +CoffeeScript = require('coffee-script') var nextTickQueue = []; var nextTickRegistered = false; @@ -81,9 +82,17 @@ var loadFile = function(filePath, mocks, globals, mockNested) { globals = globals || {}; filePath = path.normalize(filePath); - - if (filePath.substr(-3) !== '.js') { - filePath += '.js'; + var extname = path.extname(filePath); + + switch (extname) { + case '.js': + break; + case '.coffee': + break; + case '.litcoffee': + break; + default: + filePath += '.js'; } var exports = {}; @@ -128,7 +137,19 @@ var loadFile = function(filePath, mocks, globals, mockNested) { }); try { - vm.runInNewContext(fs.readFileSync(filePath), context, filePath); + switch (extname) { + case '.coffee': + var jsSource = compileCoffeeScript(filePath); + vm.runInNewContext(jsSource, context); + break; + case '.litcoffee': + var jsSource = compileCoffeeScript(filePath); + vm.runInNewContext(jsSource, context); + break; + default: + vm.runInNewContext(fs.readFileSync(filePath), context, filePath); + break; + } } catch (e) { e.stack = e.name + ': ' + e.message + '\n' + '\tat ' + filePath; @@ -139,6 +160,20 @@ var loadFile = function(filePath, mocks, globals, mockNested) { return context; }; +/** + * compile coffeescript + * + * @param {string} filePath Absolute path to module (file to load) + * @return {string} javascript source + */ +function compileCoffeeScript(filePath) { + var coffeeSource = fs.readFileSync(filePath, {encoding: 'utf8'}); + var options = {encoding: 'utf8', bare: true, literate: false}; + if (filePath.substr(-10) === '.litcoffee') { + options.literate = true; + } + return CoffeeScript.compile(coffeeSource, options); +} // PUBLIC stuff exports.loadFile = loadFile; diff --git a/package.json b/package.json index 31bbd30..c9a9cd8 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "Damien Duportal ", "Taichi " ], - "dependencies": {}, + "dependencies": { + "coffee-script": ">=1.5.0" + }, "devDependencies": { "coffee-script": "1.1.2", "jasmine-node": "1.0.11", @@ -38,4 +40,4 @@ "node": ">= 0.6.5" }, "version": "0.0.11" -} \ No newline at end of file +} diff --git a/test/fixtures/other.coffee b/test/fixtures/other.coffee new file mode 100644 index 0000000..3b3183e --- /dev/null +++ b/test/fixtures/other.coffee @@ -0,0 +1,4 @@ +#A fake module for testing util.loadFile() + +exports.id = 'LOCAL_MODULE' +exports.fs = require 'fs' diff --git a/test/fixtures/other.litcoffee b/test/fixtures/other.litcoffee new file mode 100644 index 0000000..3f3f780 --- /dev/null +++ b/test/fixtures/other.litcoffee @@ -0,0 +1,4 @@ +A fake module for testing util.loadFile() + + exports.id = 'LOCAL_MODULE' + exports.fs = require 'fs' diff --git a/test/fixtures/some.coffee b/test/fixtures/some.coffee new file mode 100644 index 0000000..5494816 --- /dev/null +++ b/test/fixtures/some.coffee @@ -0,0 +1,6 @@ +# A fake module for testing util.loadFile() + +privateNumber = 100 +privateFs = require 'fs' +privateLocalModule = require './other.coffee' +privateConsole = console diff --git a/test/fixtures/some.litcoffee b/test/fixtures/some.litcoffee new file mode 100644 index 0000000..dc6558e --- /dev/null +++ b/test/fixtures/some.litcoffee @@ -0,0 +1,7 @@ +A fake module for testing util.loadFile() + + privateNumber = 100 + privateFs = require 'fs' + privateLocalModule = require './other.litcoffee' + privateConsole = console + diff --git a/test/util.spec.coffee b/test/util.spec.coffee index 501df27..30db922 100644 --- a/test/util.spec.coffee +++ b/test/util.spec.coffee @@ -180,3 +180,81 @@ describe 'mock-util', -> expect(module.privateLocalModule.fs).toBe fsMock + + #============================================================================ + # util.loadFile() CoffeeScript + #============================================================================ + describe 'loadFile', -> + loadFile = util.loadFile + fixturePath = __dirname + '/fixtures/some.coffee' + + it 'should load file with access to private state', -> + module = loadFile fixturePath + expect(module.privateNumber).toBe 100 + + + it 'should inject mocks', -> + fsMock = {} + module = loadFile fixturePath, {fs: fsMock} + expect(module.privateFs).toBe fsMock + + + it 'should load local modules', -> + module = loadFile fixturePath + expect(module.privateLocalModule).toBeDefined() + expect(module.privateLocalModule.id).toBe 'LOCAL_MODULE' + + + it 'should inject globals', -> + fakeConsole = {} + module = loadFile fixturePath, {}, {console: fakeConsole} + expect(module.privateConsole).toBe fakeConsole + + + it 'should inject mocks into nested modules', -> + fsMock = {} + + # /fixtures/some.coffee requires /fixtures/other.coffee + # /fixtures/other.coffee requires fs + module = loadFile fixturePath, {fs: fsMock}, {}, true + + expect(module.privateLocalModule.fs).toBe fsMock + + #============================================================================ + # util.loadFile() literate style CoffeeScript + #============================================================================ + describe 'loadFile', -> + loadFile = util.loadFile + fixturePath = __dirname + '/fixtures/some.litcoffee' + + it 'should load file with access to private state', -> + module = loadFile fixturePath + expect(module.privateNumber).toBe 100 + + + it 'should inject mocks', -> + fsMock = {} + module = loadFile fixturePath, {fs: fsMock} + expect(module.privateFs).toBe fsMock + + + it 'should load local modules', -> + module = loadFile fixturePath + expect(module.privateLocalModule).toBeDefined() + expect(module.privateLocalModule.id).toBe 'LOCAL_MODULE' + + + it 'should inject globals', -> + fakeConsole = {} + module = loadFile fixturePath, {}, {console: fakeConsole} + expect(module.privateConsole).toBe fakeConsole + + + it 'should inject mocks into nested modules', -> + fsMock = {} + + # /fixtures/some.litcoffee requires /fixtures/other.litcoffee + # /fixtures/other.litcoffee requires fs + module = loadFile fixturePath, {fs: fsMock}, {}, true + + expect(module.privateLocalModule.fs).toBe fsMock From ce17efd1231ac61f851da4845cf440ac75051e62 Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Wed, 3 Jul 2013 22:52:24 -0700 Subject: [PATCH 02/18] Add license Closes #5 --- LICENSE | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..58d61e7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License + +Copyright (C) 2012-2013 Vojta Jína. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From c5fb35977a0e71b887694f2f730c71f469d56acd Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Mon, 22 Jul 2013 19:50:14 -0700 Subject: [PATCH 03/18] feat(http): emit "end" event --- lib/http.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/http.js b/lib/http.js index 548ee80..91b20d5 100644 --- a/lib/http.js +++ b/lib/http.js @@ -8,6 +8,7 @@ var ServerResponse = function() { this._headers = {}; this._body = null; + this._status = null; this._isFinished = function() { return headSent && bodySent; @@ -39,6 +40,8 @@ var ServerResponse = function() { bodySent = true; this._body = body.toString(); + + this.emit('end'); }; }; From 5607795b0368b1f304069f7f59ce376fbff3d8ab Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Mon, 22 Jul 2013 19:51:17 -0700 Subject: [PATCH 04/18] Bump version to v0.0.12 --- CHANGELOG.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 719e5a6..21b7d7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### v0.0.12 +* http.ServerResponse emit "end" event + ### v0.0.11 * Added exists/existsSync to fs mocks diff --git a/package.json b/package.json index 31bbd30..d31616f 100644 --- a/package.json +++ b/package.json @@ -37,5 +37,5 @@ "engines": { "node": ">= 0.6.5" }, - "version": "0.0.11" + "version": "0.0.12" } \ No newline at end of file From 3a68ed3ae3385178eb22db28e3367b3642afdc1c Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Tue, 23 Jul 2013 10:01:01 -0700 Subject: [PATCH 05/18] Add http.ServerRequest.headers --- lib/http.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/http.js b/lib/http.js index 91b20d5..5f0b145 100644 --- a/lib/http.js +++ b/lib/http.js @@ -49,6 +49,7 @@ util.inherits(ServerResponse, EventEmitter); var ServerRequest = function(url) { this.url = url; + this.headers = {}; }; util.inherits(ServerRequest, EventEmitter); From 3afc37b3df0b5ec8d8de68c9ba6d359bd9ba8601 Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Tue, 23 Jul 2013 10:01:09 -0700 Subject: [PATCH 06/18] Bump version to v0.0.13 --- CHANGELOG.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21b7d7e..341e5dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### v0.0.13 +* Add http.ServerRequest.headers + ### v0.0.12 * http.ServerResponse emit "end" event diff --git a/package.json b/package.json index d31616f..cd8e155 100644 --- a/package.json +++ b/package.json @@ -37,5 +37,5 @@ "engines": { "node": ">= 0.6.5" }, - "version": "0.0.12" + "version": "0.0.13" } \ No newline at end of file From 80decc5173059568d581e6b4b49ca00b4999b6d0 Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Tue, 23 Jul 2013 15:11:14 -0700 Subject: [PATCH 07/18] http.ServerResponse: publish headerSent, getHeader, write http.ServerRequest: add getHeader --- lib/http.js | 39 ++++++++++++++++++++++++++++----------- test/http.spec.coffee | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/lib/http.js b/lib/http.js index 5f0b145..c6ceb4f 100644 --- a/lib/http.js +++ b/lib/http.js @@ -3,7 +3,6 @@ var EventEmitter = require('events').EventEmitter; var ServerResponse = function() { - var headSent = false; var bodySent = false; this._headers = {}; @@ -11,45 +10,63 @@ var ServerResponse = function() { this._status = null; this._isFinished = function() { - return headSent && bodySent; + return this.headerSent && bodySent; }; + this.headerSent = false; + this.setHeader = function(name, value) { - if (headSent) { + if (this.headerSent) { throw new Error("Can't set headers after they are sent."); } this._headers[name] = value; }; + this.getHeader = function(name) { + return this._headers[name]; + }; + this.removeHeader = function(name) { delete this._headers[name]; }; this.writeHead = function(status) { - if (headSent) { + if (this.headerSent) { throw new Error("Can't render headers after they are sent to the client."); } - headSent = true; + this.headerSent = true; this._status = status; }; - this.end = function(body) { - if (bodySent) return; + this.write = function(content) { + if (bodySent) { + throw new Error("Can't write to already finished response."); + } - bodySent = true; - this._body = body.toString(); + this._body = this._body ? this._body + content.toString() : content.toString(); + }; + this.end = function(content) { + if (content) { + this.write(content ); + } + + bodySent = true; this.emit('end'); }; }; util.inherits(ServerResponse, EventEmitter); -var ServerRequest = function(url) { +var ServerRequest = function(url, headers) { this.url = url; - this.headers = {}; + this.headers = headers || {}; + + this.getHeader = function(key) { + return this.headers[key]; + }; }; util.inherits(ServerRequest, EventEmitter); diff --git a/test/http.spec.coffee b/test/http.spec.coffee index 532f6bc..853e1fe 100644 --- a/test/http.spec.coffee +++ b/test/http.spec.coffee @@ -28,9 +28,11 @@ describe 'http', -> expect(response._status).toBe 201 - it 'should ignore end() when already sent', -> + it 'should throw when trygin to end() already finished reponse', -> response.end 'First Body' - response.end 'Another Body' + + expect(-> response.end 'Another Body') + .toThrow "Can't write to already finished response." expect(response._body).toBe 'First Body' @@ -43,6 +45,11 @@ describe 'http', -> expect(response._headers).toEqual {'Content-Type': 'text/plain'} + it 'should getHeader()', -> + response.setHeader 'Content-Type', 'json' + expect(response.getHeader 'Content-Type').toBe 'json' + + it 'should throw when trying to send headers twice', -> response.writeHead 200 @@ -57,6 +64,21 @@ describe 'http', -> .toThrow "Can't set headers after they are sent." + it 'should write body', -> + response.write 'a' + response.end 'b' + + expect(response._body).toBe 'ab' + + + it 'should throw when trying to write after end', -> + response.write 'one' + response.end 'two' + + expect(-> response.write 'more') + .toThrow "Can't write to already finished response." + + it 'isFinished() should assert whether headers and body has been sent', -> expect(response._isFinished()).toBe false @@ -68,3 +90,13 @@ describe 'http', -> response.end 'Some body' expect(response._isFinished()).toBe true + + + #============================================================================== + # http.ServerRequest + #============================================================================== + describe 'ServerRequest', -> + + it 'should return headers', -> + request = new httpMock.ServerRequest '/some', {'Content-Type': 'json'} + expect(request.getHeader 'Content-Type').toBe 'json' From 60d85adebc21d5ca1fcec6cb6b56483af5ae8bbd Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Tue, 23 Jul 2013 15:11:29 -0700 Subject: [PATCH 08/18] Bump version to v0.0.14 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 341e5dc..bf90c71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### v0.0.14 +* http.ServerResponse: publish headerSent, getHeader, write +* http.ServerRequest: add getHeader + ### v0.0.13 * Add http.ServerRequest.headers diff --git a/package.json b/package.json index cd8e155..9613c06 100644 --- a/package.json +++ b/package.json @@ -37,5 +37,5 @@ "engines": { "node": ">= 0.6.5" }, - "version": "0.0.13" + "version": "0.0.14" } \ No newline at end of file From 2f59e726ec874ecfe27155f52ea05ea7b9f2176b Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Sun, 28 Jul 2013 20:06:27 -0700 Subject: [PATCH 09/18] fix(util.loadFile): do not override the exceptions Closes #6 --- lib/util.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/util.js b/lib/util.js index ab24a68..cb79496 100644 --- a/lib/util.js +++ b/lib/util.js @@ -127,14 +127,7 @@ var loadFile = function(filePath, mocks, globals, mockNested) { context[name] = globals[name]; }); - try { - vm.runInNewContext(fs.readFileSync(filePath), context, filePath); - } catch (e) { - e.stack = e.name + ': ' + e.message + '\n' + - '\tat ' + filePath; - - throw e; - } + vm.runInNewContext(fs.readFileSync(filePath), context, filePath); return context; }; From a18cd70b40f6447dfd4b8b87a14ec7cd42354e96 Mon Sep 17 00:00:00 2001 From: Hiroaki Kamei Date: Mon, 29 Jul 2013 21:29:06 +0900 Subject: [PATCH 10/18] refine code along a review accorging to a review --- lib/util.js | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/lib/util.js b/lib/util.js index 5ac14b6..a5d4a9a 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,7 +1,7 @@ var vm = require('vm'); var fs = require('fs'); var path = require('path'); -CoffeeScript = require('coffee-script') +var coffee = require('coffee-script') var nextTickQueue = []; var nextTickRegistered = false; @@ -84,15 +84,8 @@ var loadFile = function(filePath, mocks, globals, mockNested) { filePath = path.normalize(filePath); var extname = path.extname(filePath); - switch (extname) { - case '.js': - break; - case '.coffee': - break; - case '.litcoffee': - break; - default: - filePath += '.js'; + if (extname !== '.js' && extname !== '.coffee' && extname !== '.litcoffee'){ + filePath += '.js'; } var exports = {}; @@ -137,19 +130,12 @@ var loadFile = function(filePath, mocks, globals, mockNested) { }); try { - switch (extname) { - case '.coffee': - var jsSource = compileCoffeeScript(filePath); - vm.runInNewContext(jsSource, context); - break; - case '.litcoffee': - var jsSource = compileCoffeeScript(filePath); - vm.runInNewContext(jsSource, context); - break; - default: - vm.runInNewContext(fs.readFileSync(filePath), context, filePath); - break; + if (extname === '.coffee' || extname === '.litcoffee') { + jsSource = compileCoffeeScript(filePath); + } else { + jsSource = fs.readFileSync(filePath); } + vm.runInNewContext(jsSource, context); } catch (e) { e.stack = e.name + ': ' + e.message + '\n' + '\tat ' + filePath; @@ -172,7 +158,7 @@ function compileCoffeeScript(filePath) { if (filePath.substr(-10) === '.litcoffee') { options.literate = true; } - return CoffeeScript.compile(coffeeSource, options); + return coffee.compile(coffeeSource, options); } // PUBLIC stuff From 61fde4385b3bdbf9a646d2815836673e12db3dc1 Mon Sep 17 00:00:00 2001 From: Hiroaki Kamei Date: Sat, 1 Jun 2013 11:36:48 +0900 Subject: [PATCH 11/18] Update loadFile - support coffee-script file --- lib/util.js | 50 ++++++++++++++++++++-- package.json | 6 ++- test/fixtures/other.coffee | 4 ++ test/fixtures/other.litcoffee | 4 ++ test/fixtures/some.coffee | 6 +++ test/fixtures/some.litcoffee | 7 ++++ test/util.spec.coffee | 78 +++++++++++++++++++++++++++++++++++ 7 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/other.coffee create mode 100644 test/fixtures/other.litcoffee create mode 100644 test/fixtures/some.coffee create mode 100644 test/fixtures/some.litcoffee diff --git a/lib/util.js b/lib/util.js index cb79496..5ac14b6 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,6 +1,7 @@ var vm = require('vm'); var fs = require('fs'); var path = require('path'); +CoffeeScript = require('coffee-script') var nextTickQueue = []; var nextTickRegistered = false; @@ -81,9 +82,17 @@ var loadFile = function(filePath, mocks, globals, mockNested) { globals = globals || {}; filePath = path.normalize(filePath); - - if (filePath.substr(-3) !== '.js') { - filePath += '.js'; + var extname = path.extname(filePath); + + switch (extname) { + case '.js': + break; + case '.coffee': + break; + case '.litcoffee': + break; + default: + filePath += '.js'; } var exports = {}; @@ -127,11 +136,44 @@ var loadFile = function(filePath, mocks, globals, mockNested) { context[name] = globals[name]; }); - vm.runInNewContext(fs.readFileSync(filePath), context, filePath); + try { + switch (extname) { + case '.coffee': + var jsSource = compileCoffeeScript(filePath); + vm.runInNewContext(jsSource, context); + break; + case '.litcoffee': + var jsSource = compileCoffeeScript(filePath); + vm.runInNewContext(jsSource, context); + break; + default: + vm.runInNewContext(fs.readFileSync(filePath), context, filePath); + break; + } + } catch (e) { + e.stack = e.name + ': ' + e.message + '\n' + + '\tat ' + filePath; + + throw e; + } return context; }; +/** + * compile coffeescript + * + * @param {string} filePath Absolute path to module (file to load) + * @return {string} javascript source + */ +function compileCoffeeScript(filePath) { + var coffeeSource = fs.readFileSync(filePath, {encoding: 'utf8'}); + var options = {encoding: 'utf8', bare: true, literate: false}; + if (filePath.substr(-10) === '.litcoffee') { + options.literate = true; + } + return CoffeeScript.compile(coffeeSource, options); +} // PUBLIC stuff exports.loadFile = loadFile; diff --git a/package.json b/package.json index 9613c06..5f0e048 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "Damien Duportal ", "Taichi " ], - "dependencies": {}, + "dependencies": { + "coffee-script": ">=1.5.0" + }, "devDependencies": { "coffee-script": "1.1.2", "jasmine-node": "1.0.11", @@ -38,4 +40,4 @@ "node": ">= 0.6.5" }, "version": "0.0.14" -} \ No newline at end of file +} diff --git a/test/fixtures/other.coffee b/test/fixtures/other.coffee new file mode 100644 index 0000000..3b3183e --- /dev/null +++ b/test/fixtures/other.coffee @@ -0,0 +1,4 @@ +#A fake module for testing util.loadFile() + +exports.id = 'LOCAL_MODULE' +exports.fs = require 'fs' diff --git a/test/fixtures/other.litcoffee b/test/fixtures/other.litcoffee new file mode 100644 index 0000000..3f3f780 --- /dev/null +++ b/test/fixtures/other.litcoffee @@ -0,0 +1,4 @@ +A fake module for testing util.loadFile() + + exports.id = 'LOCAL_MODULE' + exports.fs = require 'fs' diff --git a/test/fixtures/some.coffee b/test/fixtures/some.coffee new file mode 100644 index 0000000..5494816 --- /dev/null +++ b/test/fixtures/some.coffee @@ -0,0 +1,6 @@ +# A fake module for testing util.loadFile() + +privateNumber = 100 +privateFs = require 'fs' +privateLocalModule = require './other.coffee' +privateConsole = console diff --git a/test/fixtures/some.litcoffee b/test/fixtures/some.litcoffee new file mode 100644 index 0000000..dc6558e --- /dev/null +++ b/test/fixtures/some.litcoffee @@ -0,0 +1,7 @@ +A fake module for testing util.loadFile() + + privateNumber = 100 + privateFs = require 'fs' + privateLocalModule = require './other.litcoffee' + privateConsole = console + diff --git a/test/util.spec.coffee b/test/util.spec.coffee index 501df27..30db922 100644 --- a/test/util.spec.coffee +++ b/test/util.spec.coffee @@ -180,3 +180,81 @@ describe 'mock-util', -> expect(module.privateLocalModule.fs).toBe fsMock + + #============================================================================ + # util.loadFile() CoffeeScript + #============================================================================ + describe 'loadFile', -> + loadFile = util.loadFile + fixturePath = __dirname + '/fixtures/some.coffee' + + it 'should load file with access to private state', -> + module = loadFile fixturePath + expect(module.privateNumber).toBe 100 + + + it 'should inject mocks', -> + fsMock = {} + module = loadFile fixturePath, {fs: fsMock} + expect(module.privateFs).toBe fsMock + + + it 'should load local modules', -> + module = loadFile fixturePath + expect(module.privateLocalModule).toBeDefined() + expect(module.privateLocalModule.id).toBe 'LOCAL_MODULE' + + + it 'should inject globals', -> + fakeConsole = {} + module = loadFile fixturePath, {}, {console: fakeConsole} + expect(module.privateConsole).toBe fakeConsole + + + it 'should inject mocks into nested modules', -> + fsMock = {} + + # /fixtures/some.coffee requires /fixtures/other.coffee + # /fixtures/other.coffee requires fs + module = loadFile fixturePath, {fs: fsMock}, {}, true + + expect(module.privateLocalModule.fs).toBe fsMock + + #============================================================================ + # util.loadFile() literate style CoffeeScript + #============================================================================ + describe 'loadFile', -> + loadFile = util.loadFile + fixturePath = __dirname + '/fixtures/some.litcoffee' + + it 'should load file with access to private state', -> + module = loadFile fixturePath + expect(module.privateNumber).toBe 100 + + + it 'should inject mocks', -> + fsMock = {} + module = loadFile fixturePath, {fs: fsMock} + expect(module.privateFs).toBe fsMock + + + it 'should load local modules', -> + module = loadFile fixturePath + expect(module.privateLocalModule).toBeDefined() + expect(module.privateLocalModule.id).toBe 'LOCAL_MODULE' + + + it 'should inject globals', -> + fakeConsole = {} + module = loadFile fixturePath, {}, {console: fakeConsole} + expect(module.privateConsole).toBe fakeConsole + + + it 'should inject mocks into nested modules', -> + fsMock = {} + + # /fixtures/some.litcoffee requires /fixtures/other.litcoffee + # /fixtures/other.litcoffee requires fs + module = loadFile fixturePath, {fs: fsMock}, {}, true + + expect(module.privateLocalModule.fs).toBe fsMock From 7032b0e56d1a7116549306157ed100209f71228a Mon Sep 17 00:00:00 2001 From: Hiroaki Kamei Date: Mon, 29 Jul 2013 21:29:06 +0900 Subject: [PATCH 12/18] refine code along a review accorging to a review --- lib/util.js | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/lib/util.js b/lib/util.js index 5ac14b6..a5d4a9a 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,7 +1,7 @@ var vm = require('vm'); var fs = require('fs'); var path = require('path'); -CoffeeScript = require('coffee-script') +var coffee = require('coffee-script') var nextTickQueue = []; var nextTickRegistered = false; @@ -84,15 +84,8 @@ var loadFile = function(filePath, mocks, globals, mockNested) { filePath = path.normalize(filePath); var extname = path.extname(filePath); - switch (extname) { - case '.js': - break; - case '.coffee': - break; - case '.litcoffee': - break; - default: - filePath += '.js'; + if (extname !== '.js' && extname !== '.coffee' && extname !== '.litcoffee'){ + filePath += '.js'; } var exports = {}; @@ -137,19 +130,12 @@ var loadFile = function(filePath, mocks, globals, mockNested) { }); try { - switch (extname) { - case '.coffee': - var jsSource = compileCoffeeScript(filePath); - vm.runInNewContext(jsSource, context); - break; - case '.litcoffee': - var jsSource = compileCoffeeScript(filePath); - vm.runInNewContext(jsSource, context); - break; - default: - vm.runInNewContext(fs.readFileSync(filePath), context, filePath); - break; + if (extname === '.coffee' || extname === '.litcoffee') { + jsSource = compileCoffeeScript(filePath); + } else { + jsSource = fs.readFileSync(filePath); } + vm.runInNewContext(jsSource, context); } catch (e) { e.stack = e.name + ': ' + e.message + '\n' + '\tat ' + filePath; @@ -172,7 +158,7 @@ function compileCoffeeScript(filePath) { if (filePath.substr(-10) === '.litcoffee') { options.literate = true; } - return CoffeeScript.compile(coffeeSource, options); + return coffee.compile(coffeeSource, options); } // PUBLIC stuff From 2eafb164c1c33b63287d266f2f0f30062aa3d9bd Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Thu, 1 Aug 2013 14:49:23 -0700 Subject: [PATCH 13/18] feat(fs): support relative paths --- lib/fs.js | 11 ++++++++--- test/fs.spec.coffee | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 887dcbd..a3ceece 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1,4 +1,3 @@ -// TODO(vojta): allow relative paths var util = require('util'); var path = require('path'); var predictableNextTick = require('./util.js').predictableNextTick; @@ -50,11 +49,13 @@ var Directory = function(mtime) { */ var Mock = function(structure) { var watchers = {}; + var cwd = '/'; // TODO(vojta): convert structure to contain only instances of File/Directory (not primitives) - var getPointer = function(path, pointer) { - var parts = path.replace(/\\/g, '/').replace(/\/$/, '').split('/').slice(1); + var getPointer = function(filepath, pointer) { + var absPath = path.resolve(cwd, filepath); + var parts = absPath.replace(/\\/g, '/').replace(/\/$/, '').split('/').slice(1); while (parts.length) { if (!pointer[parts[0]]) break; @@ -275,6 +276,10 @@ var Mock = function(structure) { callback(current, previous); }); }; + + this._setCWD = function(path) { + cwd = path; + }; }; diff --git a/test/fs.spec.coffee b/test/fs.spec.coffee index e618df3..af52a49 100644 --- a/test/fs.spec.coffee +++ b/test/fs.spec.coffee @@ -387,3 +387,17 @@ describe 'fs', -> fs.exists '/home/vojta/none-existing.js', callback waitForFinished() + + + describe 'relative paths', -> + + it 'should read file with a relative path', -> + callback = (err, data) -> + expect(err).toBeFalsy() + expect(data instanceof Buffer).toBe true + expect(data.toString()).toBe 'some' + finished++ + + fs._setCWD '/home/vojta' + fs.readFile './some.js', callback + waitForFinished() From e42ab03853bd68922db13d66330f722c27e67591 Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Fri, 2 Aug 2013 19:27:52 -0700 Subject: [PATCH 14/18] Bump version to v0.0.15 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf90c71..6b72f2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### v0.0.15 +* feat(fs): support relative paths +* fix(util.loadFile): do not override the exceptions + ### v0.0.14 * http.ServerResponse: publish headerSent, getHeader, write * http.ServerRequest: add getHeader diff --git a/package.json b/package.json index 9613c06..d3b69b9 100644 --- a/package.json +++ b/package.json @@ -37,5 +37,5 @@ "engines": { "node": ">= 0.6.5" }, - "version": "0.0.14" + "version": "0.0.15" } \ No newline at end of file From 57394159d9805ccdaf0be42ac187372c61e76cff Mon Sep 17 00:00:00 2001 From: Hiroaki Kamei Date: Sat, 1 Jun 2013 11:36:48 +0900 Subject: [PATCH 15/18] Update loadFile - support coffee-script file --- lib/util.js | 50 ++++++++++++++++++++-- package.json | 6 ++- test/fixtures/other.coffee | 4 ++ test/fixtures/other.litcoffee | 4 ++ test/fixtures/some.coffee | 6 +++ test/fixtures/some.litcoffee | 7 ++++ test/util.spec.coffee | 78 +++++++++++++++++++++++++++++++++++ 7 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/other.coffee create mode 100644 test/fixtures/other.litcoffee create mode 100644 test/fixtures/some.coffee create mode 100644 test/fixtures/some.litcoffee diff --git a/lib/util.js b/lib/util.js index cb79496..5ac14b6 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,6 +1,7 @@ var vm = require('vm'); var fs = require('fs'); var path = require('path'); +CoffeeScript = require('coffee-script') var nextTickQueue = []; var nextTickRegistered = false; @@ -81,9 +82,17 @@ var loadFile = function(filePath, mocks, globals, mockNested) { globals = globals || {}; filePath = path.normalize(filePath); - - if (filePath.substr(-3) !== '.js') { - filePath += '.js'; + var extname = path.extname(filePath); + + switch (extname) { + case '.js': + break; + case '.coffee': + break; + case '.litcoffee': + break; + default: + filePath += '.js'; } var exports = {}; @@ -127,11 +136,44 @@ var loadFile = function(filePath, mocks, globals, mockNested) { context[name] = globals[name]; }); - vm.runInNewContext(fs.readFileSync(filePath), context, filePath); + try { + switch (extname) { + case '.coffee': + var jsSource = compileCoffeeScript(filePath); + vm.runInNewContext(jsSource, context); + break; + case '.litcoffee': + var jsSource = compileCoffeeScript(filePath); + vm.runInNewContext(jsSource, context); + break; + default: + vm.runInNewContext(fs.readFileSync(filePath), context, filePath); + break; + } + } catch (e) { + e.stack = e.name + ': ' + e.message + '\n' + + '\tat ' + filePath; + + throw e; + } return context; }; +/** + * compile coffeescript + * + * @param {string} filePath Absolute path to module (file to load) + * @return {string} javascript source + */ +function compileCoffeeScript(filePath) { + var coffeeSource = fs.readFileSync(filePath, {encoding: 'utf8'}); + var options = {encoding: 'utf8', bare: true, literate: false}; + if (filePath.substr(-10) === '.litcoffee') { + options.literate = true; + } + return CoffeeScript.compile(coffeeSource, options); +} // PUBLIC stuff exports.loadFile = loadFile; diff --git a/package.json b/package.json index d3b69b9..a2323a9 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "Damien Duportal ", "Taichi " ], - "dependencies": {}, + "dependencies": { + "coffee-script": ">=1.5.0" + }, "devDependencies": { "coffee-script": "1.1.2", "jasmine-node": "1.0.11", @@ -38,4 +40,4 @@ "node": ">= 0.6.5" }, "version": "0.0.15" -} \ No newline at end of file +} diff --git a/test/fixtures/other.coffee b/test/fixtures/other.coffee new file mode 100644 index 0000000..3b3183e --- /dev/null +++ b/test/fixtures/other.coffee @@ -0,0 +1,4 @@ +#A fake module for testing util.loadFile() + +exports.id = 'LOCAL_MODULE' +exports.fs = require 'fs' diff --git a/test/fixtures/other.litcoffee b/test/fixtures/other.litcoffee new file mode 100644 index 0000000..3f3f780 --- /dev/null +++ b/test/fixtures/other.litcoffee @@ -0,0 +1,4 @@ +A fake module for testing util.loadFile() + + exports.id = 'LOCAL_MODULE' + exports.fs = require 'fs' diff --git a/test/fixtures/some.coffee b/test/fixtures/some.coffee new file mode 100644 index 0000000..5494816 --- /dev/null +++ b/test/fixtures/some.coffee @@ -0,0 +1,6 @@ +# A fake module for testing util.loadFile() + +privateNumber = 100 +privateFs = require 'fs' +privateLocalModule = require './other.coffee' +privateConsole = console diff --git a/test/fixtures/some.litcoffee b/test/fixtures/some.litcoffee new file mode 100644 index 0000000..dc6558e --- /dev/null +++ b/test/fixtures/some.litcoffee @@ -0,0 +1,7 @@ +A fake module for testing util.loadFile() + + privateNumber = 100 + privateFs = require 'fs' + privateLocalModule = require './other.litcoffee' + privateConsole = console + diff --git a/test/util.spec.coffee b/test/util.spec.coffee index 501df27..30db922 100644 --- a/test/util.spec.coffee +++ b/test/util.spec.coffee @@ -180,3 +180,81 @@ describe 'mock-util', -> expect(module.privateLocalModule.fs).toBe fsMock + + #============================================================================ + # util.loadFile() CoffeeScript + #============================================================================ + describe 'loadFile', -> + loadFile = util.loadFile + fixturePath = __dirname + '/fixtures/some.coffee' + + it 'should load file with access to private state', -> + module = loadFile fixturePath + expect(module.privateNumber).toBe 100 + + + it 'should inject mocks', -> + fsMock = {} + module = loadFile fixturePath, {fs: fsMock} + expect(module.privateFs).toBe fsMock + + + it 'should load local modules', -> + module = loadFile fixturePath + expect(module.privateLocalModule).toBeDefined() + expect(module.privateLocalModule.id).toBe 'LOCAL_MODULE' + + + it 'should inject globals', -> + fakeConsole = {} + module = loadFile fixturePath, {}, {console: fakeConsole} + expect(module.privateConsole).toBe fakeConsole + + + it 'should inject mocks into nested modules', -> + fsMock = {} + + # /fixtures/some.coffee requires /fixtures/other.coffee + # /fixtures/other.coffee requires fs + module = loadFile fixturePath, {fs: fsMock}, {}, true + + expect(module.privateLocalModule.fs).toBe fsMock + + #============================================================================ + # util.loadFile() literate style CoffeeScript + #============================================================================ + describe 'loadFile', -> + loadFile = util.loadFile + fixturePath = __dirname + '/fixtures/some.litcoffee' + + it 'should load file with access to private state', -> + module = loadFile fixturePath + expect(module.privateNumber).toBe 100 + + + it 'should inject mocks', -> + fsMock = {} + module = loadFile fixturePath, {fs: fsMock} + expect(module.privateFs).toBe fsMock + + + it 'should load local modules', -> + module = loadFile fixturePath + expect(module.privateLocalModule).toBeDefined() + expect(module.privateLocalModule.id).toBe 'LOCAL_MODULE' + + + it 'should inject globals', -> + fakeConsole = {} + module = loadFile fixturePath, {}, {console: fakeConsole} + expect(module.privateConsole).toBe fakeConsole + + + it 'should inject mocks into nested modules', -> + fsMock = {} + + # /fixtures/some.litcoffee requires /fixtures/other.litcoffee + # /fixtures/other.litcoffee requires fs + module = loadFile fixturePath, {fs: fsMock}, {}, true + + expect(module.privateLocalModule.fs).toBe fsMock From 99e60cb0f3c716fc439ede73683bf55f84d05e71 Mon Sep 17 00:00:00 2001 From: Hiroaki Kamei Date: Mon, 29 Jul 2013 21:29:06 +0900 Subject: [PATCH 16/18] refine code along a review accorging to a review --- lib/util.js | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/lib/util.js b/lib/util.js index 5ac14b6..a5d4a9a 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,7 +1,7 @@ var vm = require('vm'); var fs = require('fs'); var path = require('path'); -CoffeeScript = require('coffee-script') +var coffee = require('coffee-script') var nextTickQueue = []; var nextTickRegistered = false; @@ -84,15 +84,8 @@ var loadFile = function(filePath, mocks, globals, mockNested) { filePath = path.normalize(filePath); var extname = path.extname(filePath); - switch (extname) { - case '.js': - break; - case '.coffee': - break; - case '.litcoffee': - break; - default: - filePath += '.js'; + if (extname !== '.js' && extname !== '.coffee' && extname !== '.litcoffee'){ + filePath += '.js'; } var exports = {}; @@ -137,19 +130,12 @@ var loadFile = function(filePath, mocks, globals, mockNested) { }); try { - switch (extname) { - case '.coffee': - var jsSource = compileCoffeeScript(filePath); - vm.runInNewContext(jsSource, context); - break; - case '.litcoffee': - var jsSource = compileCoffeeScript(filePath); - vm.runInNewContext(jsSource, context); - break; - default: - vm.runInNewContext(fs.readFileSync(filePath), context, filePath); - break; + if (extname === '.coffee' || extname === '.litcoffee') { + jsSource = compileCoffeeScript(filePath); + } else { + jsSource = fs.readFileSync(filePath); } + vm.runInNewContext(jsSource, context); } catch (e) { e.stack = e.name + ': ' + e.message + '\n' + '\tat ' + filePath; @@ -172,7 +158,7 @@ function compileCoffeeScript(filePath) { if (filePath.substr(-10) === '.litcoffee') { options.literate = true; } - return CoffeeScript.compile(coffeeSource, options); + return coffee.compile(coffeeSource, options); } // PUBLIC stuff From a6bda288404e4c4cd3670e504df971fe595f614d Mon Sep 17 00:00:00 2001 From: Hiroaki Kamei Date: Sat, 1 Jun 2013 11:36:48 +0900 Subject: [PATCH 17/18] Update loadFile - support coffee-script file --- lib/util.js | 36 ++++++++++++++++++++++++++++++++++++ package.json | 4 ++++ 2 files changed, 40 insertions(+) diff --git a/lib/util.js b/lib/util.js index a5d4a9a..cd9d170 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,7 +1,11 @@ var vm = require('vm'); var fs = require('fs'); var path = require('path'); +<<<<<<< HEAD var coffee = require('coffee-script') +======= +CoffeeScript = require('coffee-script') +>>>>>>> Update loadFile - support coffee-script file var nextTickQueue = []; var nextTickRegistered = false; @@ -84,8 +88,20 @@ var loadFile = function(filePath, mocks, globals, mockNested) { filePath = path.normalize(filePath); var extname = path.extname(filePath); +<<<<<<< HEAD if (extname !== '.js' && extname !== '.coffee' && extname !== '.litcoffee'){ filePath += '.js'; +======= + switch (extname) { + case '.js': + break; + case '.coffee': + break; + case '.litcoffee': + break; + default: + filePath += '.js'; +>>>>>>> Update loadFile - support coffee-script file } var exports = {}; @@ -130,12 +146,28 @@ var loadFile = function(filePath, mocks, globals, mockNested) { }); try { +<<<<<<< HEAD if (extname === '.coffee' || extname === '.litcoffee') { jsSource = compileCoffeeScript(filePath); } else { jsSource = fs.readFileSync(filePath); } vm.runInNewContext(jsSource, context); +======= + switch (extname) { + case '.coffee': + var jsSource = compileCoffeeScript(filePath); + vm.runInNewContext(jsSource, context); + break; + case '.litcoffee': + var jsSource = compileCoffeeScript(filePath); + vm.runInNewContext(jsSource, context); + break; + default: + vm.runInNewContext(fs.readFileSync(filePath), context, filePath); + break; + } +>>>>>>> Update loadFile - support coffee-script file } catch (e) { e.stack = e.name + ': ' + e.message + '\n' + '\tat ' + filePath; @@ -158,7 +190,11 @@ function compileCoffeeScript(filePath) { if (filePath.substr(-10) === '.litcoffee') { options.literate = true; } +<<<<<<< HEAD return coffee.compile(coffeeSource, options); +======= + return CoffeeScript.compile(coffeeSource, options); +>>>>>>> Update loadFile - support coffee-script file } // PUBLIC stuff diff --git a/package.json b/package.json index a2323a9..0967f63 100644 --- a/package.json +++ b/package.json @@ -39,5 +39,9 @@ "engines": { "node": ">= 0.6.5" }, +<<<<<<< HEAD "version": "0.0.15" +======= + "version": "0.0.14" +>>>>>>> Update loadFile - support coffee-script file } From 29c779d037819f6ecc4ce4c3b3661b681da8b96a Mon Sep 17 00:00:00 2001 From: Hiroaki Kamei Date: Mon, 29 Jul 2013 21:29:06 +0900 Subject: [PATCH 18/18] refine code along a review accorging to a review --- lib/util.js | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/lib/util.js b/lib/util.js index cd9d170..c17f941 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,11 +1,7 @@ var vm = require('vm'); var fs = require('fs'); var path = require('path'); -<<<<<<< HEAD var coffee = require('coffee-script') -======= -CoffeeScript = require('coffee-script') ->>>>>>> Update loadFile - support coffee-script file var nextTickQueue = []; var nextTickRegistered = false; @@ -88,20 +84,8 @@ var loadFile = function(filePath, mocks, globals, mockNested) { filePath = path.normalize(filePath); var extname = path.extname(filePath); -<<<<<<< HEAD if (extname !== '.js' && extname !== '.coffee' && extname !== '.litcoffee'){ filePath += '.js'; -======= - switch (extname) { - case '.js': - break; - case '.coffee': - break; - case '.litcoffee': - break; - default: - filePath += '.js'; ->>>>>>> Update loadFile - support coffee-script file } var exports = {}; @@ -146,14 +130,11 @@ var loadFile = function(filePath, mocks, globals, mockNested) { }); try { -<<<<<<< HEAD if (extname === '.coffee' || extname === '.litcoffee') { jsSource = compileCoffeeScript(filePath); } else { jsSource = fs.readFileSync(filePath); } - vm.runInNewContext(jsSource, context); -======= switch (extname) { case '.coffee': var jsSource = compileCoffeeScript(filePath); @@ -167,7 +148,7 @@ var loadFile = function(filePath, mocks, globals, mockNested) { vm.runInNewContext(fs.readFileSync(filePath), context, filePath); break; } ->>>>>>> Update loadFile - support coffee-script file + vm.runInNewContext(jsSource, context); } catch (e) { e.stack = e.name + ': ' + e.message + '\n' + '\tat ' + filePath; @@ -190,11 +171,7 @@ function compileCoffeeScript(filePath) { if (filePath.substr(-10) === '.litcoffee') { options.literate = true; } -<<<<<<< HEAD return coffee.compile(coffeeSource, options); -======= - return CoffeeScript.compile(coffeeSource, options); ->>>>>>> Update loadFile - support coffee-script file } // PUBLIC stuff