Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
### 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

### v0.0.13
* Add http.ServerRequest.headers

### v0.0.12
* http.ServerResponse emit "end" event

### v0.0.11
* Added exists/existsSync to fs mocks

Expand Down
20 changes: 20 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -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.
11 changes: 8 additions & 3 deletions lib/fs.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// TODO(vojta): allow relative paths
var util = require('util');
var path = require('path');
var predictableNextTick = require('./util.js').predictableNextTick;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -275,6 +276,10 @@ var Mock = function(structure) {
callback(current, previous);
});
};

this._setCWD = function(path) {
cwd = path;
};
};


Expand Down
39 changes: 30 additions & 9 deletions lib/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,70 @@ var EventEmitter = require('events').EventEmitter;


var ServerResponse = function() {
var headSent = false;
var bodySent = false;

this._headers = {};
this._body = null;
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.");
}

this._body = this._body ? this._body + content.toString() : content.toString();
};

this.end = function(content) {
if (content) {
this.write(content );
}

bodySent = true;
this._body = body.toString();
this.emit('end');
};
};

util.inherits(ServerResponse, EventEmitter);

var ServerRequest = function(url) {
var ServerRequest = function(url, headers) {
this.url = url;
this.headers = headers || {};

this.getHeader = function(key) {
return this.headers[key];
};
};

util.inherits(ServerRequest, EventEmitter);
Expand Down
27 changes: 24 additions & 3 deletions lib/util.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var vm = require('vm');
var fs = require('fs');
var path = require('path');
var coffee = require('coffee-script')

var nextTickQueue = [];
var nextTickRegistered = false;
Expand Down Expand Up @@ -81,8 +82,9 @@ var loadFile = function(filePath, mocks, globals, mockNested) {
globals = globals || {};

filePath = path.normalize(filePath);

if (filePath.substr(-3) !== '.js') {
var extname = path.extname(filePath);

if (extname !== '.js' && extname !== '.coffee' && extname !== '.litcoffee'){
filePath += '.js';
}

Expand Down Expand Up @@ -128,7 +130,12 @@ var loadFile = function(filePath, mocks, globals, mockNested) {
});

try {
vm.runInNewContext(fs.readFileSync(filePath), context, filePath);
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;
Expand All @@ -139,6 +146,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 coffee.compile(coffeeSource, options);
}

// PUBLIC stuff
exports.loadFile = loadFile;
Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
"Damien Duportal <damien.duportal@gmail.com>",
"Taichi <ryushi@gmail.com>"
],
"dependencies": {},
"dependencies": {
"coffee-script": ">=1.5.0"
},
"devDependencies": {
"coffee-script": "1.1.2",
"jasmine-node": "1.0.11",
Expand All @@ -37,5 +39,5 @@
"engines": {
"node": ">= 0.6.5"
},
"version": "0.0.11"
}
"version": "0.0.15"
}
4 changes: 4 additions & 0 deletions test/fixtures/other.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#A fake module for testing util.loadFile()

exports.id = 'LOCAL_MODULE'
exports.fs = require 'fs'
4 changes: 4 additions & 0 deletions test/fixtures/other.litcoffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
A fake module for testing util.loadFile()

exports.id = 'LOCAL_MODULE'
exports.fs = require 'fs'
6 changes: 6 additions & 0 deletions test/fixtures/some.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# A fake module for testing util.loadFile()

privateNumber = 100
privateFs = require 'fs'
privateLocalModule = require './other.coffee'
privateConsole = console
7 changes: 7 additions & 0 deletions test/fixtures/some.litcoffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
A fake module for testing util.loadFile()

privateNumber = 100
privateFs = require 'fs'
privateLocalModule = require './other.litcoffee'
privateConsole = console

14 changes: 14 additions & 0 deletions test/fs.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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()
36 changes: 34 additions & 2 deletions test/http.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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'


Expand All @@ -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

Expand All @@ -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

Expand All @@ -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'
Loading