text: 
  /**
   * Module dependencies.
   */
  
  var mongoose = require('./common').mongoose
    , should = require('should')
    , Schema = mongoose.Schema
    , Document = mongoose.Document
    , SchemaType = mongoose.SchemaType
    , VirtualType = mongoose.VirtualType
    , ObjectId = Schema.ObjectId
    , ValidatorError = SchemaType.ValidatorError
    , CastError = SchemaType.CastError
    , SchemaTypes = Schema.Types
    , DocumentObjectId = mongoose.Types.ObjectId
    , Mixed = SchemaTypes.Mixed
    , MongooseNumber = mongoose.Types.Number
    , MongooseArray = mongoose.Types.Array
    , vm = require('vm')
  
  /**
   * Test Document constructor.
   */
  
  function TestDocument () {
    Document.apply(this, arguments);
  };
  
  /**
   * Inherits from Document.
   */
  
  TestDocument.prototype.__proto__ = Document.prototype;
  
  /**
   * Set a dummy schema to simulate compilation.
   */
  
  TestDocument.prototype.schema = new Schema({
      test    : String
  });
  
  /**
   * Test.
   */
  
  module.exports = {
  
    'test different schema types support': function(){
      var Checkin = new Schema({
          date      : Date 
        , location  : {
              lat: Number
            , lng: Number
          }
      });
  
      var Ferret = new Schema({
          name      : String
        , owner     : ObjectId
        , fur       : String
        , color     : { type: String }
        , age       : Number
        , checkins  : [Checkin]
        , friends   : [ObjectId]
        , likes     : Array
        , alive     : Boolean
        , extra     : Mixed
      });
  
      Ferret.path('name').should.be.an.instanceof(SchemaTypes.String);
      Ferret.path('owner').should.be.an.instanceof(SchemaTypes.ObjectId);
      Ferret.path('fur').should.be.an.instanceof(SchemaTypes.String);
      Ferret.path('color').should.be.an.instanceof(SchemaTypes.String);
      Ferret.path('age').should.be.an.instanceof(SchemaTypes.Number);
      Ferret.path('checkins').should.be.an.instanceof(SchemaTypes.DocumentArray);
      Ferret.path('friends').should.be.an.instanceof(SchemaTypes.Array);
      Ferret.path('likes').should.be.an.instanceof(SchemaTypes.Array);
      Ferret.path('alive').should.be.an.instanceof(SchemaTypes.Boolean);
      Ferret.path('extra').should.be.an.instanceof(SchemaTypes.Mixed);
  
      should.strictEqual(Ferret.path('unexistent'), undefined);
  
      Checkin.path('date').should.be.an.instanceof(SchemaTypes.Date);
    },
  
    'dot notation support for accessing paths': function(){
      var Racoon = new Schema({
          name  : { type: String, enum: ['Edwald', 'Tobi'] }
        , age   : Number
      });
  
      var Person = new Schema({
          name      : String
        , raccoons  : [Racoon]
        , location  : {
              city  : String
            , state : String
          }
      });
  
      Person.path('name').should.be.an.instanceof(SchemaTypes.String);
      Person.path('raccoons').should.be.an.instanceof(SchemaTypes.DocumentArray);
      Person.path('location.city').should.be.an.instanceof(SchemaTypes.String);
      Person.path('location.state').should.be.an.instanceof(SchemaTypes.String);
  
      should.strictEqual(Person.path('location.unexistent'), undefined);
    },
  
    'nested paths more than 2 levels deep': function () {
      var Nested = new Schema({
        first: {
          second: {
            third: String
          }
        }
      });
      Nested.path('first.second.third').should.be.an.instanceof(SchemaTypes.String);
    },
  
    'test default definition': function(){
      var Test = new Schema({
          simple    : { type: String, default: 'a' }
        , array     : { type: Array, default: [1,2,3,4,5] }
        , arrayX    : { type: Array, default: 9 }
        , arrayFn   : { type: Array, default: function () { return [8] } }
        , callback  : { type: Number, default: function(){
            this.a.should.eql('b');
            return '3';
          }}
      });
  
      Test.path('simple').defaultValue.should.eql('a');
      Test.path('callback').defaultValue.should.be.a('function');
  
      Test.path('simple').getDefault().should.eql('a');
      (+Test.path('callback').getDefault({ a: 'b' })).should.eql(3);
      Test.path('array').defaultValue.should.be.a('function');
      Test.path('array').getDefault(new TestDocument)[3].should.eql(4);
      Test.path('arrayX').getDefault(new TestDocument)[0].should.eql(9);
      Test.path('arrayFn').defaultValue.should.be.a('function');
      Test.path('arrayFn').getDefault(new TestDocument).should.be.an.instanceof(MongooseArray);
    },
  
    'test Mixed defaults can be empty arrays': function () {
      var Test = new Schema({
          mixed1    : { type: Mixed, default: [] }
        , mixed2    : { type: Mixed, default: Array }
      });
  
      Test.path('mixed1').getDefault().should.be.an.instanceof(Array);
      Test.path('mixed1').getDefault().length.should.be.eql(0);
      Test.path('mixed2').getDefault().should.be.an.instanceof(Array);
      Test.path('mixed2').getDefault().length.should.be.eql(0);
    },
  
    'test string required validation': function(){
      var Test = new Schema({
          simple: String
      });
  
      Test.path('simple').required(true);
      Test.path('simple').validators.should.have.length(1);
      
      Test.path('simple').doValidate(null, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Test.path('simple').doValidate(undefined, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
      
      Test.path('simple').doValidate('', function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Test.path('simple').doValidate('woot', function(err){
        should.strictEqual(err, null);
      });
    },
  
    'test string enum validation': function(){
      var Test = new Schema({
          complex: { type: String, enum: ['a', 'b', undefined, 'c', null] }
      });
  
      Test.path('complex').should.be.an.instanceof(SchemaTypes.String);
      Test.path('complex').enumValues.should.eql(['a', 'b', 'c', null]);
      Test.path('complex').validators.should.have.length(1);
  
      Test.path('complex').enum('d', 'e');
  
      Test.path('complex').enumValues.should.eql(['a', 'b', 'c', null, 'd', 'e']);
  
      Test.path('complex').doValidate('x', function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Test.path('complex').doValidate(undefined, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Test.path('complex').doValidate(null, function(err){
        should.strictEqual(null, err);
      });
  
      Test.path('complex').doValidate('da', function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
    },
  
    'test string regular expression validation': function(){
      var Test = new Schema({
          simple: { type: String, match: /[a-z]/ }
      });
  
      Test.path('simple').validators.should.have.length(1);
  
      Test.path('simple').doValidate('az', function(err){
        should.strictEqual(err, null);
      });
  
      Test.path('simple').match(/[0-9]/);
      Test.path('simple').validators.should.have.length(2);
  
      Test.path('simple').doValidate('12', function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Test.path('simple').doValidate('a12', function(err){
        should.strictEqual(err, null);
      });
    },
  
    'test string casting': function(){
      var Tobi = new Schema({
          nickname: String
      });
  
      function Test(){};
      Test.prototype.toString = function(){
        return 'woot';
      };
  
      // test Number -> String cast
      Tobi.path('nickname').cast(0).should.be.a('string');
      Tobi.path('nickname').cast(0).should.eql('0');
  
      // test any object that implements toString
      Tobi.path('nickname').cast(new Test()).should.be.a('string');
      Tobi.path('nickname').cast(new Test()).should.eql('woot');
    },
  
    'test number minimums and maximums validation': function(){
      var Tobi = new Schema({
          friends: { type: Number, max: 15, min: 5 }
      });
  
      Tobi.path('friends').validators.should.have.length(2);
  
      Tobi.path('friends').doValidate(10, function(err){
        should.strictEqual(err, null);
      });
  
      Tobi.path('friends').doValidate(100, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Tobi.path('friends').doValidate(1, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      // null is allowed
      Tobi.path('friends').doValidate(null, function(err){
        should.strictEqual(err, null);
      });
    },
  
    'test number required validation': function(){
      var Edwald = new Schema({
          friends: { type: Number, required: true }
      });
  
      Edwald.path('friends').doValidate(null, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Edwald.path('friends').doValidate(undefined, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Edwald.path('friends').doValidate(0, function(err){
        should.strictEqual(err, null);
      });
    },
  
    'test number casting': function(){
      var Tobi = new Schema({
          age: Number
      });
  
      // test String -> Number cast
      Tobi.path('age').cast('0').should.be.an.instanceof(MongooseNumber);
      (+Tobi.path('age').cast('0')).should.eql(0);
  
      Tobi.path('age').cast(0).should.be.an.instanceof(MongooseNumber);
      (+Tobi.path('age').cast(0)).should.eql(0);
    },
  
    'test date required validation': function(){
      var Loki = new Schema({
          birth_date: { type: Date, required: true }
      });
  
      Loki.path('birth_date').doValidate(null, function (err) {
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Loki.path('birth_date').doValidate(undefined, function (err) {
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Loki.path('birth_date').doValidate(new Date(), function (err) {
        should.strictEqual(err, null);
      });
    },
  
    'test date casting': function(){
      var Loki = new Schema({
          birth_date: { type: Date }
      });
  
      Loki.path('birth_date').cast(1294525628301).should.be.an.instanceof(Date);
      Loki.path('birth_date').cast('8/24/2000').should.be.an.instanceof(Date);
      Loki.path('birth_date').cast(new Date).should.be.an.instanceof(Date);
    },
  
    'test object id required validator': function(){
      var Loki = new Schema({
          owner: { type: ObjectId, required: true }
      });
  
      Loki.path('owner').doValidate(new DocumentObjectId(), function(err){
        should.strictEqual(err, null);
      });
  
      Loki.path('owner').doValidate(null, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Loki.path('owner').doValidate(undefined, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
    },
  
    'test object id casting': function(){
      var Loki = new Schema({
          owner: { type: ObjectId }
      });
  
      var doc = new TestDocument()
        , id = doc._id.toString();
  
      Loki.path('owner').cast('4c54f3453e688c000000001a')
                       .should.be.an.instanceof(DocumentObjectId);
  
      Loki.path('owner').cast(new DocumentObjectId())
                       .should.be.an.instanceof(DocumentObjectId);
  
      Loki.path('owner').cast(doc)
                       .should.be.an.instanceof(DocumentObjectId);
  
      Loki.path('owner').cast(doc).toString().should.eql(id);
    },
  
    'test array required validation': function(){
      var Loki = new Schema({
          likes: { type: Array, required: true }
      });
  
      Loki.path('likes').doValidate(null, function (err) {
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Loki.path('likes').doValidate(undefined, function (err) {
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Loki.path('likes').doValidate([], function (err) {
        err.should.be.an.instanceof(ValidatorError);
      });
    },
  
    'test array casting': function(){
      var Loki = new Schema({
          oids        : [ObjectId]
        , dates       : [Date]
        , numbers     : [Number]
        , strings     : [String]
        , buffers     : [Buffer]
        , nocast      : []
        , mixed       : [Mixed]
      });
  
      var oids = Loki.path('oids').cast(['4c54f3453e688c000000001a', new DocumentObjectId]);
  
      oids[0].should.be.an.instanceof(DocumentObjectId);
      oids[1].should.be.an.instanceof(DocumentObjectId);
  
      var dates = Loki.path('dates').cast(['8/24/2010', 1294541504958]);
  
      dates[0].should.be.an.instanceof(Date);
      dates[1].should.be.an.instanceof(Date);
  
      var numbers = Loki.path('numbers').cast([152, '31']);
  
      numbers[0].should.be.a('number');
      numbers[1].should.be.a('number');
  
      var strings = Loki.path('strings').cast(['test', 123]);
  
      strings[0].should.be.a('string');
      strings[0].should.eql('test');
  
      strings[1].should.be.a('string');
      strings[1].should.eql('123');
  
      var buffers = Loki.path('buffers').cast(['\0\0\0', new Buffer("abc")]);
  
      buffers[0].should.be.an.instanceof(Buffer);
      buffers[1].should.be.an.instanceof(Buffer);
  
      var nocasts = Loki.path('nocast').cast(['test', 123]);
  
      nocasts[0].should.be.a('string');
      nocasts[0].should.eql('test');
  
      nocasts[1].should.be.a('number');
      nocasts[1].should.eql(123);
  
      var mixed = Loki.path('mixed').cast(['test', 123, '123', {}, new Date, new DocumentObjectId]);
  
      mixed[0].should.be.a('string');
      mixed[1].should.be.a('number');
      mixed[2].should.be.a('string');
      mixed[3].should.be.a('object');
      mixed[4].should.be.an.instanceof(Date);
      mixed[5].should.be.an.instanceof(DocumentObjectId);
    },
  
    'test boolean required validator': function(){
      var Animal = new Schema({
          isFerret: { type: Boolean, required: true }
      });
  
      Animal.path('isFerret').doValidate(null, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Animal.path('isFerret').doValidate(undefined, function(err){
        err.should.be.an.instanceof(ValidatorError);
      });
  
      Animal.path('isFerret').doValidate(true, function(err){
        should.strictEqual(err, null);
      });
  
      Animal.path('isFerret').doValidate(false, function(err){
        should.strictEqual(err, null);
      });
    },
  
    'test boolean casting': function(){
      var Animal = new Schema({
          isFerret: { type: Boolean, required: true }
      });
  
      should.strictEqual(Animal.path('isFerret').cast(null), null);
      Animal.path('isFerret').cast(undefined).should.be.false;
      Animal.path('isFerret').cast(false).should.be.false;
      Animal.path('isFerret').cast(0).should.be.false;
      Animal.path('isFerret').cast('0').should.be.false;
      Animal.path('isFerret').cast({}).should.be.true;
      Animal.path('isFerret').cast(true).should.be.true;
      Animal.path('isFerret').cast(1).should.be.true;
      Animal.path('isFerret').cast('1').should.be.true;
    },
  
    'test async multiple validators': function(beforeExit){
      var executed = 0;
  
      function validator (value, fn) {
        setTimeout(function(){
          executed++;
          fn(value === true);
        }, 50);
      };
  
      var Animal = new Schema({
        ferret: {
          type: Boolean,
          validate: [
            {
              'validator': validator,
              'msg': 'validator1'
            },
            {
              'validator': validator,
              'msg': 'validator2'
            },
          ],
        }
      });
  
      Animal.path('ferret').doValidate(true, function(err){
        should.strictEqual(err, null);
      });
  
      beforeExit(function(){
        executed.should.eql(2);
      });
    },
  
    'test async validators': function(beforeExit){
      var executed = 0;
  
      function validator (value, fn) {
        setTimeout(function(){
          executed++;
          fn(value === true);
        }, 50);
      };
  
      var Animal = new Schema({
          ferret: { type: Boolean, validate: validator }
      });
  
      Animal.path('ferret').doValidate(true, function(err){
        should.strictEqual(err, null);
      });
  
      Animal.path('ferret').doValidate(false, function(err){
        err.should.be.an.instanceof(Error);
      });
  
      beforeExit(function(){
        executed.should.eql(2);
      });
    },
  
    'test async validators scope': function(beforeExit){
      var executed = false;
      
      function validator (value, fn) {
        this.a.should.eql('b');
  
        setTimeout(function(){
          executed = true;
          fn(true);
        }, 50);
      };
  
      var Animal = new Schema({
          ferret: { type: Boolean, validate: validator }
      });
  
      Animal.path('ferret').doValidate(true, function(err){
        should.strictEqual(err, null);
      }, { a: 'b' });
  
      beforeExit(function(){
        executed.should.be.true;
      });
    },
  
    'test declaring new methods': function(){
      var a = new Schema();
      a.method('test', function(){});
      a.method({
          a: function(){}
        , b: function(){}
      });
  
      Object.keys(a.methods).should.have.length(3);
    },
  
    'test declaring new statics': function(){
      var a = new Schema();
      a.static('test', function(){});
      a.static({
          a: function(){}
        , b: function(){}
        , c: function(){}
      });
  
      Object.keys(a.statics).should.have.length(4);
    },
  
    'test setter(s)': function(){
      function lowercase (v) {
        return v.toLowerCase();
      };
  
      var Tobi = new Schema({
          name: { type: String, set: lowercase }
      });
  
      Tobi.path('name').applySetters('WOOT').should.eql('woot');
      Tobi.path('name').setters.should.have.length(1);
  
      Tobi.path('name').set(function(v){
        return v + 'WOOT';
      });
  
      Tobi.path('name').applySetters('WOOT').should.eql('wootwoot');
      Tobi.path('name').setters.should.have.length(2);
    },
  
    'test setters scope': function(){
      function lowercase (v, self) {
        this.a.should.eql('b');
        self.path.should.eql('name');
        return v.toLowerCase();
      };
  
      var Tobi = new Schema({
          name: { type: String, set: lowercase }
      });
  
      Tobi.path('name').applySetters('WHAT', { a: 'b' }).should.eql('what');
    },
  
    'test string built-in setter `lowercase`': function () {
      var Tobi = new Schema({
          name: { type: String, lowercase: true }
      });
  
      Tobi.path('name').applySetters('WHAT').should.eql('what');
    },
  
    'test string built-in setter `uppercase`': function () {
      var Tobi = new Schema({
          name: { type: String, uppercase: true }
      });
  
      Tobi.path('name').applySetters('what').should.eql('WHAT');
    },
  
    'test string built-in setter `trim`': function () {
      var Tobi = new Schema({
          name: { type: String, uppercase: true, trim: true }
      });
  
      Tobi.path('name').applySetters('    what      ').should.eql('WHAT');
    },
  
    'test getter(s)': function(){
      function woot (v) {
        return v + ' woot';
      };
  
      var Tobi = new Schema({
          name: { type: String, get: woot }
      });
  
      Tobi.path('name').getters.should.have.length(1);
      Tobi.path('name').applyGetters('test').should.eql('test woot');
    },
  
    'test getters scope': function(){
      function woot (v, self) {
        this.a.should.eql('b');
        self.path.should.eql('name');
        return v.toLowerCase();
      };
  
      var Tobi = new Schema({
          name: { type: String, get: woot }
      });
  
      Tobi.path('name').applyGetters('YEP', { a: 'b' }).should.eql('yep');
    },
  
    'test setters casting': function(){
      function last (v) {
        v.should.be.a('string');
        v.should.eql('0');
        return 'last';
      };
  
      function first (v) {
        return 0;
      };
      
      var Tobi = new Schema({
          name: { type: String, set: last }
      });
  
      Tobi.path('name').set(first);
      Tobi.path('name').applySetters('woot').should.eql('last');
    },
  
    'test getters casting': function(){
      function last (v) {
        v.should.be.a('string');
        v.should.eql('0');
        return 'last';
      };
  
      function first (v) {
        return 0;
      };
      
      var Tobi = new Schema({
          name: { type: String, get: last }
      });
  
      Tobi.path('name').get(first);
      Tobi.path('name').applyGetters('woot').should.eql('last');
    },
  
    'test hooks registration': function(){
      var Tobi = new Schema();
  
      Tobi.pre('save', function(){});
      Tobi.callQueue.should.have.length(1);
  
      Tobi.post('save', function(){});
      Tobi.callQueue.should.have.length(2);
  
      Tobi.pre('save', function(){});
      Tobi.callQueue.should.have.length(3);
    },
  
    'test applying setters when none have been defined': function(){
      var Tobi = new Schema({
          name: String
      });
  
      Tobi.path('name').applySetters('woot').should.eql('woot');
    },
  
    'test applying getters when none have been defined': function(){
      var Tobi = new Schema({
          name: String
      });
  
      Tobi.path('name').applyGetters('woot').should.eql('woot');
    },
  
    'test defining an index': function(){
      var Tobi = new Schema({
          name: { type: String, index: true }
      });
  
      Tobi.path('name')._index.should.be.true;
      Tobi.path('name').index({ unique: true });
      Tobi.path('name')._index.should.eql({ unique: true });
      Tobi.path('name').unique(false);
      Tobi.path('name')._index.should.eql({ unique: false});
  
      var T1 = new Schema({
          name: { type: String, sparse: true }
      });
      T1.path('name')._index.should.eql({ sparse: true });
  
      var T2 = new Schema({
          name: { type: String, unique: true }
      });
      T2.path('name')._index.should.eql({ unique: true });
  
      var T3 = new Schema({
          name: { type: String, sparse: true, unique: true }
      });
      T3.path('name')._index.should.eql({ sparse: true, unique: true });
  
      var T4 = new Schema({
          name: { type: String, unique: true, sparse: true }
      });
      var i = T4.path('name')._index;
      i.unique.should.be.true;
      i.sparse.should.be.true;
  
      var T5 = new Schema({
          name: { type: String, index: { sparse: true, unique: true } }
      });
      var i = T5.path('name')._index;
      i.unique.should.be.true;
      i.sparse.should.be.true;
    },
  
    'test defining compound indexes': function(){
      var Tobi = new Schema({
          name: { type: String, index: true }
        , last: { type: Number, sparse: true }
      });
  
      Tobi.index({ firstname: 1, last: 1 }, { unique: true });
  
      Tobi.indexes.should.eql([
          [{ name: 1 }, {}]
        , [{ last: 1 }, { sparse: true }]
        , [{ firstname: 1, last: 1}, {unique: true}]
      ]);
    },
  
    'test plugins': function (beforeExit) {
      var Tobi = new Schema()
        , called = false;
  
      Tobi.plugin(function(schema){
        schema.should.equal(Tobi);
        called = true;
      });
  
      beforeExit(function () {
        called.should.be.true;
      });
    },
  
    'test that default options are set': function () {
      var Tobi = new Schema();
  
      Tobi.options.should.be.a('object');
      Tobi.options.safe.should.be.true;
    },
  
    'test setting options': function () {
      var Tobi = new Schema({}, { collection: 'users' });
  
      Tobi.set('a', 'b');
      Tobi.set('safe', false);
      Tobi.options.collection.should.eql('users');
  
      Tobi.options.a.should.eql('b');
      Tobi.options.safe.should.be.false;
    },
  
    'test declaring virtual attributes': function () {
      var Contact = new Schema({
          firstName: String
        , lastName: String
      });
      Contact.virtual('fullName')
        .get( function () {
          return this.get('firstName') + ' ' + this.get('lastName');
        }).set(function (fullName) {
          var split = fullName.split(' ');
          this.set('firstName', split[0]);
          this.set('lastName', split[1]);
        });
  
      Contact.virtualpath('fullName').should.be.an.instanceof(VirtualType);
    },
  
    'test GH-298 - The default creation of a virtual `id` should be muted when someone defines their own `id` attribute': function () {
      new Schema({ id: String });
    },
  
    'allow disabling the auto .id virtual': function () {
      var schema = new Schema({ name: String }, { noVirtualId: true });
      should.strictEqual(undefined, schema.virtuals.id);
    },
  
    'selected option': function () {
      var s = new Schema({ thought: { type: String, select: false }});
      s.path('thought').selected.should.be.false;
  
      var a = new Schema({ thought: { type: String, select: true }});
      a.path('thought').selected.should.be.true;
    },
  
    'schema creation works with objects from other contexts': function () {
      var str = 'code = {' +
        '  name: String' +
        ', arr1: Array ' +
        ', arr2: { type: [] }' +
        ', date: Date  ' +
        ', num: { type: Number }' +
        ', bool: Boolean' +
        ', nest: { sub: { type: {}, required: true }}' +
        '}';
  
      var script = vm.createScript(str, 'testSchema.vm');
      var sandbox = { code: null };
      script.runInNewContext(sandbox);
  
      var Ferret = new Schema(sandbox.code);
      Ferret.path('nest.sub').should.be.an.instanceof(SchemaTypes.Mixed);
      Ferret.path('name').should.be.an.instanceof(SchemaTypes.String);
      Ferret.path('arr1').should.be.an.instanceof(SchemaTypes.Array);
      Ferret.path('arr2').should.be.an.instanceof(SchemaTypes.Array);
      Ferret.path('date').should.be.an.instanceof(SchemaTypes.Date);
      Ferret.path('num').should.be.an.instanceof(SchemaTypes.Number);
      Ferret.path('bool').should.be.an.instanceof(SchemaTypes.Boolean);
    },
  
    'schema string casts undefined to "undefined"': function () {
      var db= require('./common')();
      var schema = new Schema({ arr: [String] });
      var M = db.model('castingStringArrayWithUndefined', schema);
      M.find({ arr: { $in: [undefined] }}, function (err) {
        db.close();
        should.equal(err && err.message, 'Cast to string failed for value "undefined"');
      })
    },
  
    'array of object literal missing a `type` is interpreted as Mixed': function () {
      var s = new Schema({
          arr: [
            { something: { type: String } }
          ]
      });
    },
  
    'helpful schema debugging msg': function () {
      var err;
      try {
        new Schema({ name: { first: null } })
      } catch (e) {
        err = e;
      }
      err.message.should.equal('Invalid value for schema path `name.first`')
      try {
        new Schema({ age: undefined })
      } catch (e) {
        err = e;
      }
      err.message.should.equal('Invalid value for schema path `age`')
    },
  
    'add() does not polute existing paths': function () {
      var o = { name: String }
      var s = new Schema(o);
      s.add({ age: Number }, 'name.');
      ;('age' in o.name).should.be.false;
    },
  
    // gh-700
    'nested schemas should throw': function () {
      var a = new Schema({ title: String })
        , err
  
      try {
        new Schema({ blah: Boolean, a: a });
      } catch (err_) {
        err = err_;
      }
  
      should.exist(err);
      ;/Did you try nesting Schemas/.test(err.message).should.be.true;
    },
  
    'non-function etters throw': function () {
      var schema = new Schema({ fun: String });
      var g, s;
  
      try {
        schema.path('fun').get(true);
      } catch (err_) {
        g = err_;
      }
  
      should.exist(g);
      g.message.should.equal('A getter must be a function.');
  
      try {
        schema.path('fun').set(4);
      } catch (err_) {
        s = err_;
      }
  
      should.exist(s);
      s.message.should.equal('A setter must be a function.');
    }
  
  };
  