UNPKG

mongoose-function

Version:

Function storage for Mongoose

362 lines (315 loc) 10.7 kB
var assert = require('assert') var Mod = require('../') var mongoose = require('mongoose') var Schema = mongoose.Schema; var FunctionSchema; var MongooseFunction; describe('MongooseFunction', function(){ before(function(){ FunctionSchema = Mod(mongoose) MongooseFunction = mongoose.Types.Function }) it('has a version', function(){ assert.equal(require('../package').version, Mod.version); }) it('is a function', function(){ assert.equal('function', typeof FunctionSchema); }) it('extends mongoose.Schema.Types', function(){ assert.ok(Schema.Types.Function); assert.equal(FunctionSchema, Schema.Types.Function); }) it('extends mongoose.Types', function(){ assert.ok(mongoose.Types.Function); }) it('can be used in schemas', function(){ var s = new Schema({ fn: FunctionSchema }); var fn = s.path('fn') assert.ok(fn instanceof mongoose.SchemaType); assert.equal('function', typeof fn.get); var s = new Schema({ fn: 'Function' }); var fn = s.path('fn') assert.ok(fn instanceof mongoose.SchemaType); assert.equal('function', typeof fn.get); var s = new Schema({ fn: Function }); var fn = s.path('fn') assert.ok(fn instanceof mongoose.SchemaType); assert.equal('function', typeof fn.get); }) describe('integration', function(){ var db, S, schema, id; before(function(done){ db = mongoose.createConnection('localhost', 'mongoose_function') db.once('open', function () { schema = new Schema({ fn: FunctionSchema , docs: [{ fn: Function }] }); S = db.model('MFunction', schema); done(); }); }) after(function(done){ db.db.dropDatabase(function () { db.close(done); }); }) describe('casts', function(){ it('functions', function(){ var v = function () { return 3 + 9; } var s = new S({ fn: v }); assert.equal('function', typeof s.fn); assert.equal(s.fn, v); assert.equal(12, s.fn()); v = new Function('return 5 + 3'); s = new S({ fn: v }); assert.equal(s.fn, v); assert.equal(8, s.fn()); }); describe('strings', function(){ it('with length', function(){ var v = 'function \n\r woot (){ return "Mario64" }'; var s = new S({ fn: v }); assert.equal('function', typeof s.fn); assert.equal('Mario64', s.fn()); }) it('with length that do not start with "function"', function(){ var v = 'return "Mario64"'; var s = new S({ fn: v }); assert.equal('undefined', typeof s.fn); }) it('that are empty', function(){ var v = ''; var s = new S({ fn: v }); assert.strictEqual(null, s.fn); }) }); it('null', function(){ var s = new S({ fn: null }); assert.equal(null, s.fn); }) it('MongooseFunction', function(){ var s = new S({ fn: new mongoose.Types.Function("function(){return 90}") }); assert.equal('function', typeof s.fn); assert.equal(90, s.fn()); }) it('non-castables produce _saveErrors', function(done){ var schema = new Schema({ fn: 'Function' }, { strict: 'throw' }); var M = db.model('throws', schema); var m = new M({ fn: [] }); m.save(function (err) { assert.ok(err); assert.equal('Function', err.type); assert.equal('CastError', err.name); done(); }); }) it('queries with null properly', function(done){ S.create({ fn: null }, { fn: ' function (){ return 1 } ' }, function (err) { assert.ifError(err); S.findOne({ fn: null }, function (err, doc) { assert.ifError(err); assert.strictEqual(null, doc.fn); done(); }) }) }) it('Code', function(done){ var v = function () { return 3 + 9; } var scope = { x: 1 }; var code = new mongoose.mongo.Code(v, scope); var s = new S({ fn: code }); s.save(function (err) { assert.ok(/MongooseFunction does not support storing Code `scope`/, err); v = function () { return 3 + 9; } s.fn = new mongoose.mongo.Code(v); assert.equal('function', typeof s.fn); assert.equal(12, s.fn()); done(); }) }) }) describe('with db', function(){ it('save', function(done){ function Ab_eiot43$() { return 20 } function multiline () { return 100; } var s = new S({ fn: 'function \n\rn (a, b, c ) {return 10; 3}' , docs: [ { fn: Ab_eiot43$ } , { fn: function stuff ( ) {return 1 } } , { fn: multiline } ] }); id = s.id; s.save(function (err) { assert.ifError(err); done(); }) }) var fnStr; it('findById', function(done){ S.findById(id, function (err, doc) { assert.ifError(err); assert.ok('function' == typeof doc.fn); assert.equal( 131 , doc.fn() + doc.docs[0].fn() + doc.docs[1].fn() + doc.docs[2].fn() ); fnStr = doc.fn.toString(); done(); }); }) it('find', function(done){ S.find({ fn: fnStr }, function (err, docs) { assert.ifError(err); assert.equal(1, docs.length); var doc = docs[0]; assert.ok('function' == typeof doc.fn); assert.equal( 131 , doc.fn() + doc.docs[0].fn() + doc.docs[1].fn() + doc.docs[2].fn() ); done(); }); }) it('find with RegExp', function(done){ S.find({ fn: /return 10/, 'docs.fn': new RegExp('^function', 'i') }, function (err, docs) { assert.ifError(err); assert.equal(1, docs.length); var doc = docs[0]; assert.ok('function' == typeof doc.fn); assert.equal( 131 , doc.fn() + doc.docs[0].fn() + doc.docs[1].fn() + doc.docs[2].fn() ); done(); }); }) describe('is updateable', function(){ it('in general', function(done){ S.findById(id, function (err, doc) { assert.ifError(err); doc.fn = function(){ return require('mongoose').version } doc.save(function (err) { assert.ifError(err); S.findById(id, function (err, doc) { assert.ifError(err); assert.equal(mongoose.version, doc.fn()); done(); }); }) }) }) }) describe('with mongodb.Code', function(){ it('works', function(done){ var v = function () { return 3 + 9; } var code = new mongoose.mongo.Code(v); var s = new S({ fn: code }); s.save(function (err) { assert.ifError(err); S.findById(s._id, function (err, doc) { assert.ifError(err); assert.equal(12, doc.fn()); done(); }) }) }) }) }) it('can be required', function(done){ var s = new Schema({ fn: { type: Function, required: true }}); var M = db.model('required', s); var m = new M; m.save(function (err) { assert.ok(err); m.fn = console.log; m.validate(function (err) { assert.ifError(err); done(); }) }) }) describe('security', function(){ it('handles values returned from db', function(done){ S.create({ docs: [] }, function (err, doc) { assert.ifError(err); var docs = []; docs[0] = { fn: ' ' } docs[1] = { fn: ' function \n ok (a) \r\n { return { a: a\n\r }\n}}}' } docs[2] = { fn: 'function c(){ process.stdout.write("gotcha") }' } docs[3] = { fn: 'eval(5)' } S.collection.update( { _id: doc._id } , { $set: { docs: docs }} , { w: 1 }, function (err) { assert.ifError(err); S.findById(doc._id, function (err, doc) { assert.ifError(err); assert.equal(null, doc.docs[0].fn); assert.equal(4, doc.docs[1].fn(4).a); assert.equal(undefined, doc.docs[2].fn()); assert.equal(undefined, doc.docs[3].fn); done() }) }) }) }) describe('custom toFunction', function(){ it('can be set by user', function(done){ delete mongoose.Types.Function; delete mongoose.Schema.Types.Function; var custom = false; function toFunction (str) { custom = true; return eval('(' + str + ')'); } Mod(mongoose, { toFunction: toFunction }) var schema = new Schema({ fn: FunctionSchema }); var M = db.model('MFunction2', schema); var m= new M({ fn: 'function () { return 10 + 10 }' }) assert.equal(20, m.fn()); assert.ok(custom); m = new M({ fn: 'return 10 + 10' }); assert.equal('undefined', typeof m.fn); m.save(function (err) { assert.ok(err); m.fn = 'function () { return "worked" }' assert.equal('worked', m.fn()); m.save(function (err) { assert.ifError(err); M.findById(m._id, function (err, doc) { assert.ifError(err); assert.equal('worked', doc.fn()); done() }) }) }) }) it('must return functions or null', function(done){ var M = db.model('MFunction2'); var m= new M({ fn: '{ toString: "fail" }' }) assert.equal('undefined', typeof m.fn); var m= new M({ fn: '[]' }) assert.equal('undefined', typeof m.fn); var m= new M({ fn: 'return "hm"' }) assert.equal('undefined', typeof m.fn); var m= new M({ fn: '10' }) assert.equal('undefined', typeof m.fn); var m= new M({ fn: 'new RegExp(".*")' }) assert.equal('undefined', typeof m.fn); var m= new M({ fn: new mongoose.mongo.Code('null') }) assert.strictEqual(null, m.fn); done(); }) }) }) }) })