diff --git a/.gitignore b/.gitignore index 87259533..a2b3c49f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store *tmp.* *.log -node_modules/ \ No newline at end of file +node_modules/ +coverage/ diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..0f1fd42e --- /dev/null +++ b/.jshintrc @@ -0,0 +1,13 @@ +{ + "boss": true, + "node": true, + "strict": true, + "smarttabs": true, + "maxlen": 80, + "newcap": false, + "undef": true, + "unused": true, + "onecase": true, + "indent": 2, + "sub": true +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1f72f648..c0405ec9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,4 +17,9 @@ npm run nock_off check this [blogpost](http://writings.nunojob.com/2012/05/Mock-HTTP-Integration-Testing-in-Node.js-using-Nock-and-Specify.html) to learn more about how to write your own tests -[2]: http://github.com/dscape/nano/issues \ No newline at end of file +change this +add NOCK_OFF +add DEBUG +base from message-queue + +[2]: http://github.com/dscape/nano/issues diff --git a/package.json b/package.json index a41477c7..281e2ff5 100644 --- a/package.json +++ b/package.json @@ -1,48 +1,11 @@ { "name": "nano", "description": "minimalistic couchdb driver for node.js", - "license": "Apache 2.0", + "license": "apache 2.0", "homepage": "http://github.com/dscape/nano", "repository": "git://github.com/dscape/nano", - "version": "5.12.1", + "version": "6.0.0", "author": "Nuno Job (http://nunojob.com)", - "contributors": [ - "Thiago Arrais (http://thiagoarrais.com)", - "Derek Perez (http://blog.derekperez.com)", - "Patrick Heneise (http://patrickheneise.com)", - "Artur Konarski (http://tarantoga.com)", - "Pedro Teixeira (http://metaduck.com)", - "Tom Wilson (http://jackhq.tumblr.com)", - "Dale Harvey (http://arandomurl.com)", - "Jan Lehnardt (http://jan.prima.de/plok/)", - "InTheFiveByFive", - "Stéphane Alnet (http://blog.shimaore.net)", - "Cliffano Subagio (http://blog.cliffano.com)", - "Mark Hahn (http://hahnca.com)", - "Francesco Ceccon (http://francesco-cek.com/)", - "Oliver Leics (http://oleics.github.com)", - "Jonathan Mahoney (http://mahoney.eu)", - "Dominique Sandoz ", - "John Lancaster (http://jlank.com)", - "Clemens Stolle (https://github.com/klaemo)", - "Jay Beavers (http://jaybeavers.org)", - "Juraj Vitko", - "Paul Iannazzo (http://pppaul.me)", - "Sebastian Tiedtke ", - "Gregory T. Corrigan (https://github.com/corrigang)", - "Etienne Folio (https://github.com/Ornthalas)", - "John Chesley (http://chesl.es)", - "Damon Oehlman ", - "Patrick Paul-Hus (https://github.com/hydrozen)", - "Sven Lito (http://svenlito.com)", - "Gerrit Renker", - "Andreas Lappe ", - "Aram Kocharyan ", - "Jan Krems @jkrems", - "Owen Evans (http://www.bgeek.net)", - "Johannes J. Schmidt (http://die-tf.de)", - "Alex Schenkman " - ], "keywords": [ "couchdb", "data", @@ -54,23 +17,36 @@ "database" ], "dependencies": { - "request": "~2.42.0", - "follow": "~0.11.2", - "errs": "~0.3.0", - "underscore": "~1.7.0" + "request": "^2.45.0", + "follow": "^0.11.2", + "errs": "^0.3.0", + "underscore": "^1.7.0", + "debug": "^2.0.0" }, "devDependencies": { - "async": "~0.2.9", - "specify": "~1.2.0", - "nock": "~0.18.2" + "async": "^0.9.0", + "tape": "^3.0.0", + "istanbul": "^0.3.2", + "jshint": "^2.5.6", + "jscs": "^1.7.0", + "nock": "^0.48.0", + "endswith": "^0.0.0", + "tape-it": "^0.0.1" }, "scripts": { - "test": "node node_modules/specify/bin/specify -e NOCK=on", - "compact": "node node_modules/specify/bin/specify -e NOCK=on -r compact", - "nock_off": "node node_modules/specify/bin/specify" + "test": "DEBUG=* NOCK_OFF=true istanbul cover tape tests/att/*.js", + "jshint": "jshint tests/att/*.js", + "codestyle": "jscs -p google tests/att/*.js", + "checkcoverage": "istanbul check-coverage --statements 100 --functions 100 --lines 100 --branches 100" }, "main": "./nano.js", "engines": { - "node": ">=0.6.0" - } + "node": ">=0.8.0" + }, + "pre-commit": [ + "jshint", + "codestyle", + "test", + "checkcoverage" + ] } diff --git a/tests/att/destroy.js b/tests/att/destroy.js index 9f050ce8..a022fa1a 100644 --- a/tests/att/destroy.js +++ b/tests/att/destroy.js @@ -1,52 +1,32 @@ -var specify = require('specify') - , helpers = require('../helpers') - , timeout = helpers.timeout - , nano = helpers.nano - , nock = helpers.nock - ; +'use strict'; -var mock = nock(helpers.couch, "att/destroy") - , db = nano.use("att_destroy") - ; +var helpers = require('../helpers'); +var harness = helpers.harness(); +var it = harness.it; -specify("att_destroy:setup", timeout, function (assert) { - nano.db.create("att_destroy", function (err) { - assert.equal(err, undefined, "Failed to create database"); - }); -}); - -specify("att_destroy:test", timeout, function (assert) { - db.attachment.insert("new", "att", "Hello World!", "text/plain", - function (error, att) { - assert.equal(error, undefined, "Should store the attachment"); - assert.equal(att.ok, true, "Response should be ok"); - assert.ok(att.rev, "Should have a revision number"); - db.attachment.destroy("new", "att", att.rev, function(error, response) { - assert.equal(error, undefined, "Should delete the attachment"); - assert.equal(response.ok, true, "Response should be ok"); - assert.equal(response.id, "new", "Id should be new"); - }); - }); -}); - -specify("att_destroy:att_name_missing", timeout, function (assert) { - db.attachment.insert("new2", "att2", "Hello World!", "text/plain", - function (error, att) { - assert.equal(error, undefined, "Should store the attachment"); - assert.equal(att.ok, true, "Response should be ok"); - assert.ok(att.rev, "Should have a revision number"); - db.attachment.destroy("new", false, att.rev, function(error, response) { - assert.equal(error.errid, "bad_params", "Should throw error because att_name is not a string"); - assert.equal(response, undefined, "No response should be given"); +it('should be able to insert a new plain text attachment', function(assert) { + var locals = this; + locals.db.attachment.insert('new', + 'att', 'Hello World!', 'text/plain', function(error, att) { + assert.equal(error, null, 'store the attachment'); + assert.equal(att.ok, true, 'response ok'); + assert.ok(att.rev, 'have a revision number'); + locals.db.attachment.destroy('new', 'att', + att.rev, function(error, response) { + assert.equal(error, null, 'delete the attachment'); + assert.equal(response.ok, true, 'response ok'); + assert.equal(response.id, 'new', '`id` should be `new`'); + assert.end(); }); }); }); -specify("att_destroy:teardown", timeout, function (assert) { - nano.db.destroy("att_destroy", function (err) { - assert.equal(err, undefined, "Failed to destroy database"); - assert.ok(mock.isDone(), "Some mocks didn't run"); +it('should fail destroying with a bad filename', function(assert) { + var locals = this; + locals.db.attachment.destroy('new', false, true, function(error, response) { + assert.equal(error.errid, 'bad_params', + '`att_name` should be a string'); + assert.equal(response, undefined, 'no response should be given'); + assert.end(); }); }); - -specify.run(process.argv.slice(2)); diff --git a/tests/att/get.js b/tests/att/get.js index c62b4f2d..e6c9e445 100644 --- a/tests/att/get.js +++ b/tests/att/get.js @@ -1,54 +1,37 @@ -var specify = require('specify') - , helpers = require('../helpers') - , timeout = helpers.timeout - , nano = helpers.nano - , nock = helpers.nock - ; +'use strict'; -var mock = nock(helpers.couch, "att/get") - , db = nano.use("att_get") - ; +var helpers = require('../helpers'); +var harness = helpers.harness(); +var it = harness.it; - -specify("att_get:setup", timeout, function (assert) { - nano.db.create("att_get", function (err) { - assert.equal(err, undefined, "Failed to create database"); - }); -}); - -specify("att_get:test_string", timeout, function (assert) { - db.attachment.insert("new_string", "att", "Hello", "text/plain", +it('should be able to fetch an attachment', function(assert) { + var locals = this; + locals.db.attachment.insert('new_string', 'att', 'Hello', 'text/plain', function(error, hello) { - assert.equal(error, undefined, "Should store hello"); - assert.equal(hello.ok, true, "Response should be ok"); - assert.ok(hello.rev, "Should have a revision number"); - db.attachment.get("new_string", "att", - function (error, helloWorld) { - assert.equal(error, undefined, "Should get the hello"); - assert.equal("Hello", helloWorld, "string is reflexive"); + assert.equal(error, null, 'should store `hello`'); + assert.equal(hello.ok, true, 'response ok'); + assert.ok(hello.rev, 'should have a revision number'); + locals.db.attachment.get('new_string', 'att', + function(error, helloWorld) { + assert.equal(error, null, 'should get `hello`'); + assert.equal('Hello', helloWorld.toString(), 'string is reflexive'); + assert.end(); }); }); }); -specify("att_get:test_binary", timeout, function (assert) { - db.attachment.insert("new_binary", "att", new Buffer("123"), "text/plain", - function(error, hello) { - assert.equal(error, undefined, "Should store 123"); - assert.equal(hello.ok, true, "Response should be ok"); - assert.ok(hello.rev, "Should have a revision number"); - db.attachment.get("new_binary", "att", - function (error, binaryData) { - assert.equal(error, undefined, "Should get the binary data"); - assert.equal("123", binaryData, "binary data is reflexive"); +it('should insert and fetch a binary file', function(assert) { + var locals = this; + locals.db.attachment.insert('new_binary', 'att', + new Buffer('123'), 'text/plain', function(error, hello) { + assert.equal(error, null, 'should store `123`'); + assert.equal(hello.ok, true, 'response ok'); + assert.ok(hello.rev, 'should have a revision number'); + locals.db.attachment.get('new_binary', 'att', + function(error, binaryData) { + assert.equal(error, null, 'should get the binary data'); + assert.equal('123', binaryData.toString(), 'binary data is reflexive'); + assert.end(); }); }); }); - -specify("att_get:teardown", timeout, function (assert) { - nano.db.destroy("att_get", function (err) { - assert.equal(err, undefined, "Failed to destroy database"); - assert.ok(mock.isDone(), "Some mocks didn't run"); - }); -}); - -specify.run(process.argv.slice(2)); \ No newline at end of file diff --git a/tests/att/insert.js b/tests/att/insert.js index 7783cf02..d65b9476 100644 --- a/tests/att/insert.js +++ b/tests/att/insert.js @@ -1,34 +1,15 @@ -var specify = require('specify') - , helpers = require('../helpers') - , timeout = helpers.timeout - , nano = helpers.nano - , nock = helpers.nock - ; - -var mock = nock(helpers.couch, "att/insert") - , db = nano.use("att_insert") - ; - -specify("att_insert:setup", timeout, function (assert) { - nano.db.create("att_insert", function (err) { - assert.equal(err, undefined, "Failed to create database"); - }); -}); - -specify("att_insert:test", timeout, function (assert) { - db.attachment.insert("new", "att", "Hello World!", "text/plain", - function (error, att) { - assert.equal(error, undefined, "Should store the attachment"); - assert.equal(att.ok, true, "Response should be ok"); - assert.ok(att.rev, "Should have a revision number"); +'use strict'; + +var helpers = require('../helpers'); +var harness = helpers.harness(); +var it = harness.it; + +it('should be able to insert a simple attachment', function(assert) { + this.db.attachment.insert('new', 'att', 'Hello World!', 'text/plain', + function(error, att) { + assert.equal(error, null, 'should store the attachment'); + assert.equal(att.ok, true, 'response ok'); + assert.ok(att.rev, 'should have a revision'); + assert.end(); }); }); - -specify("att_insert:teardown", timeout, function (assert) { - nano.db.destroy("att_insert", function (err) { - assert.equal(err, undefined, "Failed to destroy database"); - assert.ok(mock.isDone(), "Some mocks didn't run"); - }); -}); - -specify.run(process.argv.slice(2)); \ No newline at end of file diff --git a/tests/att/pipe.js b/tests/att/pipe.js index 672909a4..56f1e78d 100644 --- a/tests/att/pipe.js +++ b/tests/att/pipe.js @@ -1,62 +1,46 @@ -var fs = require('fs') - , path = require('path') - , specify = require('specify') - , helpers = require('../helpers') - , timeout = helpers.timeout - , nano = helpers.nano - , nock = helpers.nock - , pixel = helpers.pixel - ; - -var mock = nock(helpers.couch, "att/pipe") - , db = nano.use("att_pipe") - ; - -specify("att_pipe:setup", timeout, function (assert) { - nano.db.create("att_pipe", function (err) { - assert.equal(err, undefined, "Failed to create database"); +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var helpers = require('../helpers'); +var harness = helpers.harness(); +var it = harness.it; +var pixel = helpers.pixel; + +it('should be able to pipe to a writeStream', function(assert) { + var locals = this; + var buffer = new Buffer(pixel, 'base64'); + var filename = path.join(__dirname, '.temp.bmp'); + var ws = fs.createWriteStream(filename); + + ws.on('close', function() { + assert.equal(fs.readFileSync(filename).toString('base64'), pixel); + fs.unlinkSync(filename); + assert.end(); }); -}); -specify("att_pipe:write", timeout, function (assert) { - var buffer = new Buffer(pixel, 'base64') - , filename = path.join(__dirname, '.temp.bmp') - , ws = fs.createWriteStream(filename) - ; - ws.on('close', function () { - assert.equal(fs.readFileSync(filename).toString('base64'), pixel); - fs.unlinkSync(filename); - }); - db.attachment.insert("new", "att", buffer, "image/bmp", - function (error, bmp) { - assert.equal(error, undefined, "Should store the pixel"); - db.attachment.get("new", "att", {rev: bmp.rev}).pipe(ws); - }); + locals.db.attachment.insert('new', 'att', buffer, 'image/bmp', + function(error, bmp) { + assert.equal(error, null, 'Should store the pixel'); + locals.db.attachment.get('new', 'att', {rev: bmp.rev}).pipe(ws); + }); }); -specify("att_pipe:read", timeout, function (assert) { - var logo = __dirname + "/../fixtures/logo.png" - , rs = fs.createReadStream(logo) - , is = db.attachment.insert("nodejs", "logo.png", null, "image/png") - ; +it('should be able to pipe from a readStream', function(assert) { + var locals = this; + var logo = path.join(__dirname, '..', 'fixtures', 'logo.png'); + var rs = fs.createReadStream(logo); + var is = locals.db.attachment.insert('nodejs', 'logo.png', null, 'image/png'); - is.on('end', function () { - db.attachment.get("nodejs", "logo.png", function (err, buffer) { - assert.equal(err, undefined, "Should get the logo"); + is.on('end', function() { + locals.db.attachment.get('nodejs', 'logo.png', function(err, buffer) { + assert.equal(err, null, 'should get the logo'); assert.equal( fs.readFileSync(logo).toString('base64'), buffer.toString('base64'), - "Data should remain unchanged"); + 'logo should remain unchanged'); + assert.end(); }); }); rs.pipe(is); }); - -specify("att_pipe:teardown", timeout, function (assert) { - nano.db.destroy("att_pipe", function (err) { - assert.equal(err, undefined, "Failed to destroy database"); - assert.ok(mock.isDone(), "Some mocks didn't run"); - }); -}); - -specify.run(process.argv.slice(2)); diff --git a/tests/att/update.js b/tests/att/update.js index 1c697a07..0f3584b3 100644 --- a/tests/att/update.js +++ b/tests/att/update.js @@ -1,54 +1,39 @@ -var specify = require('specify') - , helpers = require('../helpers') - , timeout = helpers.timeout - , nano = helpers.nano - , nock = helpers.nock - , pixel = helpers.pixel - , rev - ; +'use strict'; -var mock = nock(helpers.couch, "att/update") - , db = nano.use("att_update") - ; +var helpers = require('../helpers'); +var pixel = helpers.pixel; +var harness = helpers.harness(); +var it = harness.it; -specify("att_update:setup", timeout, function (assert) { - nano.db.create("att_update", function (err) { - assert.equal(err, undefined, "Failed to create database"); - }); -}); +var rev; -specify("att_update:test", timeout, function (assert) { +it('should be able to insert and update attachments', function(assert) { + var locals = this; var buffer = new Buffer(pixel, 'base64'); - db.attachment.insert("new", "att", "Hello", "text/plain", - function(error, hello) { - assert.equal(error, undefined, "Should store hello"); - assert.equal(hello.ok, true, "Response should be ok"); - assert.ok(hello.rev, "Should have a revision number"); - db.attachment.insert("new", "att", buffer, "image/bmp", - { rev: hello.rev }, function (error, bmp) { - assert.equal(error, undefined, "Should store the pixel"); - assert.ok(bmp.rev, "Should have a revision number"); - rev = bmp.rev; - }); + locals.db.attachment.insert('new', 'att', 'Hello', 'text/plain', + function(error, hello) { + assert.equal(error, null, 'should store hello'); + assert.equal(hello.ok, true, 'response ok'); + assert.ok(hello.rev, 'should have a revision'); + locals.db.attachment.insert('new', 'att', buffer, 'image/bmp', + { rev: hello.rev }, function(error, bmp) { + assert.equal(error, null, 'should store the pixel'); + assert.ok(bmp.rev, 'should store a revision'); + rev = bmp.rev; + assert.end(); }); + }); }); -specify("att_update:metadata", timeout, function (assert) { - db.get("new", function (error, new_doc) { - assert.equal(error, undefined, "Should get new"); +it('should be able to fetch the updated pixel', function(assert) { + var locals = this; + locals.db.get('new', function(error, new_doc) { + assert.equal(error, null, 'should get new'); new_doc.works = true; - db.insert(new_doc, "new", function (error, response) { - assert.equal(error, undefined, "Should update doc"); - assert.equal(response.ok, true, "Response should be ok"); + locals.db.insert(new_doc, 'new', function(error, response) { + assert.equal(error, null, 'should update doc'); + assert.equal(response.ok, true, 'response ok'); + assert.end(); }); }); }); - -specify("att_update:teardown", timeout, function (assert) { - nano.db.destroy("att_update", function (err) { - assert.equal(err, undefined, "Failed to destroy database"); - assert.ok(mock.isDone(), "Some mocks didn't run"); - }); -}); - -specify.run(process.argv.slice(2)); \ No newline at end of file diff --git a/tests/fixtures/att/pipe.json b/tests/fixtures/att/pipe.json index 0f5e430f..2dfb69da 100644 --- a/tests/fixtures/att/pipe.json +++ b/tests/fixtures/att/pipe.json @@ -2,11 +2,11 @@ { "method" : "put" , "path" : "/att_pipe" , "status" : 201 - , "response" : "{ \"ok\": true }" + , "response" : "{ \"ok\": true }" } , { "method" : "put" , "path" : "/att_pipe/new/att" - , "base64" : "Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BABgAAAAAAAAAAAATCwAAEwsAAAAAAAAAAAAAWm2CAA==" + , "body" : "*" , "status" : 201 , "response" : "{\"ok\":true,\"id\":\"new\",\"rev\":\"1-3b1f88\"}\n" } @@ -26,6 +26,6 @@ , { "method" : "delete" , "path" : "/att_pipe" , "status" : 200 - , "response" : "{ \"ok\": true }" + , "response" : "{ \"ok\": true }" } -] \ No newline at end of file +] diff --git a/tests/fixtures/att/update.json b/tests/fixtures/att/update.json index 4dd94a94..6532445d 100644 --- a/tests/fixtures/att/update.json +++ b/tests/fixtures/att/update.json @@ -2,7 +2,7 @@ { "method" : "put" , "path" : "/att_update" , "status" : 201 - , "response" : "{ \"ok\": true }" + , "response" : "{ \"ok\": true }" } , { "method" : "put" , "path" : "/att_update/new/att" @@ -12,7 +12,7 @@ } , { "method" : "put" , "path" : "/att_update/new/att?rev=1-5142a2" - , "base64" : "Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BABgAAAAAAAAAAAATCwAAEwsAAAAAAAAAAAAAWm2CAA==" + , "body" : "*" , "status" : 201 , "response" : "{\"ok\":true,\"id\":\"new\",\"rev\":\"2-3b1f88\"}\n" } @@ -30,6 +30,6 @@ , { "method" : "delete" , "path" : "/att_update" , "status" : 200 - , "response" : "{ \"ok\": true }" + , "response" : "{ \"ok\": true }" } -] \ No newline at end of file +] diff --git a/tests/fixtures/cfg.json b/tests/fixtures/cfg.json index b5d29c48..fa0834b3 100644 --- a/tests/fixtures/cfg.json +++ b/tests/fixtures/cfg.json @@ -1,4 +1,4 @@ -{ "timeout" : 20000 +{ "timeout" : 2000 , "couch" : "http://localhost:5984" , "admin" : "http://admin:password@localhost:5984" } diff --git a/tests/helpers.js b/tests/helpers.js index 54e50bd0..940868f9 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -1,44 +1,25 @@ -var path = require('path') - , fs = require('fs') - , cfg = JSON.parse( - fs.readFileSync(path.join(__dirname, '/fixtures/cfg.json'))) - , nano = require('../nano') - , helpers = exports - ; - -function endsWith (string, ending) { - return string.length >= ending.length && - string.substr(string.length - ending.length) == ending; -} - -function noop(){} - -function fake_chain() { - return { - "get" : fake_chain - , "post" : fake_chain - , "delete" : fake_chain - , "put" : fake_chain - , "intercept" : fake_chain - , "done" : fake_chain - , "isDone" : function () { return true; } - , "filteringPath" : fake_chain - , "filteringRequestBody" : fake_chain - , "matchHeader" : fake_chain - , "defaultReplyHeaders" : fake_chain - , "log" : fake_chain - }; -} +'use strict'; -helpers.timeout = cfg.timeout; -helpers.nano = nano(cfg.couch); -helpers.Nano = nano; -helpers.couch = cfg.couch; -helpers.admin = cfg.admin; -helpers.pixel = "Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BABgAAAAA" + - "AAAAAAATCwAAEwsAAAAAAAAAAAAAWm2CAA=="; +var path = require('path'); +var fs = require('fs'); +var url = require('url'); +var harness = require('tape-it'); +var debug = require('debug'); +var path = require('path'); +var endsWith = require('endswith'); +var cfg = require('./fixtures/cfg'); +var nano = require('../nano'); +var helpers = exports; -var auth = require("url").parse(cfg.admin).auth.split(":"); +var auth = url.parse(cfg.admin).auth.split(':'); + +helpers.timeout = cfg.timeout; +helpers.nano = nano(cfg.couch); +helpers.Nano = nano; +helpers.couch = cfg.couch; +helpers.admin = cfg.admin; +helpers.pixel = 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BABgAAAAA' + + 'AAAAAAATCwAAEwsAAAAAAAAAAAAAWm2CAA=='; helpers.username = auth[0]; helpers.password = auth[1]; @@ -46,54 +27,95 @@ helpers.password = auth[1]; helpers.loadFixture = function helpersLoadFixture(filename, json) { var contents = fs.readFileSync( path.join(__dirname, 'fixtures', filename), (json ? 'ascii' : null)); - return json ? JSON.parse(contents): contents; + return json ? JSON.parse(contents) : contents; }; -helpers.nock = function helpersNock(url, fixture) { - if(process.env.NOCK) { - var nock = require('nock') - , nocks = helpers.loadFixture(fixture + '.json', true) - ; - nocks.forEach(function(n) { - var npath = n.path - , method = n.method || "get" - , status = n.status || 200 - , response = n.buffer - ? endsWith(n.buffer, '.png') - ? helpers.loadFixture(n.buffer) - : new Buffer(n.buffer, 'base64') - : n.response || "" - , headers = n.headers || {} - , reqheaders = n.reqheaders || {} - , body = n.base64 - ? new Buffer(n.base64, 'base64').toString() - : n.body || "" - ; - - if(typeof response === "string" && endsWith(response, '.json')) { - response = helpers.loadFixture(path.join(fixture, response)); - } - if(typeof headers === "string" && endsWith(headers, '.json')) { - headers = helpers.loadFixture(path.join(fixture, headers)); - } - - if(body==="*") { - nock(url).filteringRequestBody(function() { - return "*"; - })[method](npath, "*").reply(status, response, headers); - } else { - var nk = nock(url); - if(reqheaders !== {}) { - for (var k in reqheaders) { - nk = nk.matchHeader(k, reqheaders[k]); - } - } - nk.intercept(npath, method, body).reply(status, response, headers); - } +helpers.setup = function() { + var self = this; + var args = Array.prototype.slice.call(arguments); + + return function(assert) { + args.push(function(err) { + assert.equal(err, null, 'create database'); + assert.end(); }); - nock(url).log(console.log); - return nock(url); - } else { - return fake_chain(); - } -}; \ No newline at end of file + + self.nano.db.create.apply(this, args); + }; +}; + +helpers.teardown = function() { + var self = this; + var args = Array.prototype.slice.call(arguments); + + return function(assert) { + args.push(function(err) { + assert.equal(err, null, 'destroy database'); + assert.ok(self.mock.isDone(), 'mocks didn\'t run'); + assert.end(); + }); + + self.nano.db.destroy.apply(this, args); + }; +}; + +helpers.harness = function(opts) { + opts = opts || {}; + var fileName = path.basename(module.parent.filename).split('.')[0]; + var parentDir = path.dirname(module.parent.filename) + .split(path.sep).reverse()[0]; + var shortPath = path.join(parentDir, fileName); + var log = debug(path.join('tests', shortPath)); + var dbName = shortPath.replace('/', '_'); + var nanoLog = nano({ + url: cfg.couch, + log: log + }); + var mock = helpers.nock(helpers.couch, shortPath, log); + var db = nanoLog.use(dbName); + var locals = { + mock: mock, + db: db, + nano: nanoLog + }; + + return harness({ + id: shortPath, + timeout: helpers.timeout, + checkLeaks: false, + locals: locals, + setup: helpers.setup.call(locals, dbName), + teardown: helpers.teardown.call(locals, dbName) + }); +}; + +helpers.nock = function helpersNock(url, fixture, log) { + var nock = require('nock'); + var nockDefs = require('./fixtures/' + fixture + '.json'); + + nockDefs.forEach(function(n) { + var headers = n.headers || {}; + var response = n.buffer ? endsWith(n.buffer, '.png') ? + helpers.loadFixture(n.buffer) : new Buffer(n.buffer, 'base64') : + n.response || ''; + var body = n.base64 ? new Buffer(n.base64, 'base64').toString() : + n.body || ''; + + if (typeof headers === 'string' && endsWith(headers, '.json')) { + headers = require(path.join(fixture, headers)); + } + + n.method = n.method || 'get'; + n.options = {log: log}; + n.scope = url; + n.headers = headers; + n.response = response; + n.body = body; + + return n; + }); + + nock.define(nockDefs); + + return nock(url); +};