<commit_before>/**
 * Module dependencies.
 */
var Schema = storage.Schema
  , utils = storage.utils
  , random = utils.random;

var Document = storage.Document
  , SchemaType = storage.SchemaType
  , VirtualType = storage.VirtualType
  , ValidatorError = storage.Error.ValidatorError
  , SchemaTypes = Schema.Types
  , ObjectId = SchemaTypes.ObjectId
  , Mixed = SchemaTypes.Mixed
  , DocumentObjectId = storage.Types.ObjectId
  , StorageArray = storage.Types.Array;

/**
 * Setup
 */
var PersonSchema = new Schema({
  name: { first: String, last: String }
  , gender: String
}, { collection: 'model-discriminator-'+random() });

PersonSchema.index({ name: 1 });
PersonSchema.methods.getFullName = function() {
  return this.name.first + ' ' + this.name.last;
};
PersonSchema.statics.findByGender = function(gender, cb) {};
PersonSchema.virtual('name.full').get(function () {
  return this.name.first + ' ' + this.name.last;
});
PersonSchema.virtual('name.full').set(function (name) {
  var split = name.split(' ');
  this.name.first = split[0];
  this.name.last = split[1];
});
PersonSchema.path('gender').validate(function(value) {
  return /[A-Z]/.test(value);
}, 'Invalid name');
PersonSchema.post('save', function (next) {
  next();
});
PersonSchema.set('toObject', { getters: true, virtuals: true });
PersonSchema.set('toJSON',   { getters: true, virtuals: true });

var EmployeeSchema = new Schema({ department: String });
EmployeeSchema.index({ department: 1 });
EmployeeSchema.methods.getDepartment = function() {
  return this.department;
};
EmployeeSchema.statics.findByDepartment = function(department, cb) {};
EmployeeSchema.path('department').validate(function(value) {
  return /[a-zA-Z]/.test(value);
}, 'Invalid name');
var employeeSchemaPreSaveFn = function (next) {
  next();
};
EmployeeSchema.pre('save', employeeSchemaPreSaveFn);
EmployeeSchema.set('toObject', { getters: true, virtuals: false });
EmployeeSchema.set('toJSON',   { getters: false, virtuals: true });

describe('model', function() {
  describe('discriminator()', function() {
    var Person, Employee;

    before(function(){
      Person = storage.createCollection('model-discriminator-person', PersonSchema);
      Employee = Person.discriminator('model-discriminator-employee', EmployeeSchema);
    });

    it('model defaults without discriminator', function(done) {
      var Model = db.model('model-discriminator-defaults', new Schema(), 'model-discriminator-'+random());
      assert.equal(Model.discriminators, undefined);
      done();
    });

    it('is instance of root', function(done) {
      var employee = new Employee();
      assert.ok(employee instanceof Person);
      assert.ok(employee instanceof Employee);
      assert.strictEqual(employee.__proto__.constructor, Employee);
      assert.strictEqual(employee.__proto__.__proto__.constructor, Person);
      done();
    });

    it('can define static and instance methods', function(done) {
      function BossBaseSchema() {
        Schema.apply(this, arguments);

        this.add({
          name: String,
          createdAt: Date
        });
      }
      util.inherits(BossBaseSchema, Schema);

      var PersonSchema = new BossBaseSchema();
      var BossSchema = new BossBaseSchema({ department: String });
      BossSchema.methods.myName = function(){
        return this.name;
      };
      BossSchema.statics.currentPresident = function(){
        return 'obama';
      };
      var Person = db.model('Person', PersonSchema);
      var Boss = Person.discriminator('Boss', BossSchema);

      var boss = new Boss({name:'Bernenke'});
      assert.equal(boss.myName(), 'Bernenke');
      assert.equal(boss.notInstanceMethod, undefined);
      assert.equal(Boss.currentPresident(), 'obama');
      assert.equal(Boss.notStaticMethod, undefined);
      done();
    });

    it('sets schema root discriminator mapping', function(done) {
      assert.deepEqual(PersonSchema.discriminatorMapping, { key: '__t', value: null, isRoot: true });
      done();
    });

    it('sets schema discriminator type mapping', function(done) {
      assert.deepEqual(EmployeeSchema.discriminatorMapping, { key: '__t', value: 'model-discriminator-employee', isRoot: false });
      done();
    });

    it('adds discriminatorKey to schema with default as name', function(done) {
      var type = EmployeeSchema.paths.__t;
      assert.equal(type.options.type, String);
      assert.equal(type.options.default, 'model-discriminator-employee');
      done();
    });

    it('adds discriminator to Model.discriminators object', function(done) {
      assert.equal(Object.keys(Person.discriminators).length, 1);
      assert.equal(Person.discriminators['model-discriminator-employee'], Employee);
      var newName = 'model-discriminator-' + random();
      var NewDiscriminatorType = Person.discriminator(newName, new Schema());
      assert.equal(Object.keys(Person.discriminators).length, 2);
      assert.equal(Person.discriminators[newName], NewDiscriminatorType);
      done();
    });

    it('throws error on invalid schema', function(done) {
      assert.throws(
        function() {
          Person.discriminator('Foo');
        },
        /You must pass a valid discriminator Schema/
      );
      done();
    });

    it('throws error when attempting to nest discriminators', function(done) {
      assert.throws(
        function() {
          Employee.discriminator('model-discriminator-foo', new Schema());
        },
        /Discriminator "model-discriminator-foo" can only be a discriminator of the root model/
      );
      done();
    });

    it('throws error when discriminator has mapped discriminator key in schema', function(done) {
      assert.throws(
        function() {
          Person.discriminator('model-discriminator-foo', new Schema({ __t: String }));
        },
        /Discriminator "model-discriminator-foo" cannot have field with name "__t"/
      );
      done();
    });

    it('throws error when discriminator has mapped discriminator key in schema with discriminatorKey option set', function(done) {
      assert.throws(
        function() {
          var Foo = db.model('model-discriminator-foo', new Schema({}, { discriminatorKey: '_type' }), 'model-discriminator-'+random());
          Foo.discriminator('model-discriminator-bar', new Schema({ _type: String }));
        },
        /Discriminator "model-discriminator-bar" cannot have field with name "_type"/
      );
      done();
    });

    it('throws error when discriminator with taken name is added', function(done) {
      var Foo = db.model('model-discriminator-foo', new Schema({}), 'model-discriminator-'+random());
      Foo.discriminator('model-discriminator-taken', new Schema());
      assert.throws(
        function() {
          Foo.discriminator('model-discriminator-taken', new Schema());
        },
        /Discriminator with name "model-discriminator-taken" already exists/
      );
      done();
    });

    describe('options', function() {
      it('allows toObject to be overridden', function(done) {
        assert.notDeepEqual(Employee.schema.get('toObject'), Person.schema.get('toObject'));
        assert.deepEqual(Employee.schema.get('toObject'), { getters: true, virtuals: false });
        done();
      });

      it('allows toJSON to be overridden', function(done) {
        assert.notDeepEqual(Employee.schema.get('toJSON'), Person.schema.get('toJSON'));
        assert.deepEqual(Employee.schema.get('toJSON'), { getters: false, virtuals: true });
        done();
      });

      it('is not customizable', function(done) {
        var errorMessage
          , CustomizedSchema = new Schema({}, { capped: true });
        try {
          Person.discriminator('model-discriminator-custom', CustomizedSchema);
        } catch (e) {
          errorMessage = e.message;
        }

        assert.equal(errorMessage, 'Discriminator options are not customizable (except toJSON & toObject)');
        done();
      });
    });

    describe('root schema inheritance', function() {
      it('inherits field mappings', function(done) {
        assert.strictEqual(Employee.schema.path('name'), Person.schema.path('name'));
        assert.strictEqual(Employee.schema.path('gender'), Person.schema.path('gender'));
        assert.equal(Person.schema.paths.department, undefined);
        done();
      });

      it('inherits validators', function(done) {
        assert.strictEqual(Employee.schema.path('gender').validators, PersonSchema.path('gender').validators);
        assert.strictEqual(Employee.schema.path('department').validators, EmployeeSchema.path('department').validators);
        done();
      });

      it('does not inherit and override fields that exist', function(done) {
        var FemaleSchema = new Schema({ gender: { type: String, default: 'F' }})
          , Female = Person.discriminator('model-discriminator-female', FemaleSchema);

        var gender = Female.schema.paths.gender;

        assert.notStrictEqual(gender, Person.schema.paths.gender);
        assert.equal(gender.instance, 'String');
        assert.equal(gender.options.default, 'F');
        done();
      });

      it('inherits methods', function(done) {
        var employee = new Employee();
        assert.strictEqual(employee.getFullName, PersonSchema.methods.getFullName);
        assert.strictEqual(employee.getDepartment, EmployeeSchema.methods.getDepartment);
        assert.equal((new Person()).getDepartment, undefined);
        done();
      });

      it('inherits statics', function(done) {
        assert.strictEqual(Employee.findByGender, EmployeeSchema.statics.findByGender);
        assert.strictEqual(Employee.findByDepartment, EmployeeSchema.statics.findByDepartment);
        assert.equal(Person.findByDepartment, undefined);
        done();
      });

      it('inherits virtual (g.s)etters', function(done) {
        var employee = new Employee();
        employee.name.full = '<NAME>';
        assert.equal(employee.name.full, '<NAME>');
        done();
      });

      it('merges callQueue with base queue defined before discriminator types callQueue', function(done) {
        assert.equal(Employee.schema.callQueue.length, 4);
        // PersonSchema.post('save')
        assert.strictEqual(Employee.schema.callQueue[0], Person.schema.callQueue[0]);

        // EmployeeSchema.pre('save')
        assert.strictEqual(Employee.schema.callQueue[3][0], 'pre');
        assert.strictEqual(Employee.schema.callQueue[3][1]['0'], 'save');
        assert.strictEqual(Employee.schema.callQueue[3][1]['1'], employeeSchemaPreSaveFn);
        done();
      });

      it('does not inherit indexes', function(done) {
        assert.deepEqual(Person.schema.indexes(), [[{ name: 1 }, { background: true, safe: undefined }]]);
        assert.deepEqual(Employee.schema.indexes(), [[{ department: 1 }, { background: true, safe: undefined }]]);
        done();
      });

      it('gets options overridden by root options except toJSON and toObject', function(done) {
        var personOptions = clone(Person.schema.options)
          , employeeOptions = clone(Employee.schema.options);

        delete personOptions.toJSON;
        delete personOptions.toObject;
        delete employeeOptions.toJSON;
        delete employeeOptions.toObject;

        assert.deepEqual(personOptions, employeeOptions);
        done();
      });
    });
  });<commit_msg>дотавлены тесты на дискриминатор<commit_after>/* jshint strict: false */
/* global describe, before, it */
/**
 * Module dependencies.
 */
var
  Schema = storage.Schema,
  utils = storage.utils,
  random = utils.random;

var
  clone = utils.clone,
  Document = storage.Document;

/**
 * Setup
 */
var PersonSchema = new Schema('Person', {
  name: { first: String, last: String },
  gender: String
});

PersonSchema.methods.getFullName = function() {
  return this.name.first + ' ' + this.name.last;
};
PersonSchema.statics.findByGender = function(gender, cb) {};
PersonSchema.virtual('name.full').get(function () {
  return this.name.first + ' ' + this.name.last;
});
PersonSchema.virtual('name.full').set(function (name) {
  var split = name.split(' ');
  this.name.first = split[0];
  this.name.last = split[1];
});
PersonSchema.path('gender').validate(function(value) {
  return /[A-Z]/.test(value);
}, 'Invalid name');
PersonSchema.post('save', function (next) {
  next();
});
PersonSchema.set('toObject', { getters: true, virtuals: true });
PersonSchema.set('toJSON',   { getters: true, virtuals: true });

var EmployeeSchema = new Schema('Employee', PersonSchema, { department: String });
EmployeeSchema.methods.getDepartment = function() {
  return this.department;
};
EmployeeSchema.statics.findByDepartment = function(department, cb) {};
EmployeeSchema.path('department').validate(function(value) {
  return /[a-zA-Z]/.test(value);
}, 'Invalid name');
var employeeSchemaPreSaveFn = function (next) {
  next();
};
EmployeeSchema.pre('save', employeeSchemaPreSaveFn);
EmployeeSchema.set('toObject', { getters: true, virtuals: false });
EmployeeSchema.set('toJSON',   { getters: false, virtuals: true });

describe('schema', function() {
  describe('discriminator()', function() {
    var personCollection, employeeCollection;
    var person, employee;

    before(function(){
      personCollection = storage.createCollection('model-discriminator-person', PersonSchema);
      employeeCollection = storage.createCollection('model-discriminator-employee', EmployeeSchema);

      person = personCollection.add();
      employee = employeeCollection.add();
    });

    it('model defaults without discriminator', function(done) {
      var schemaDefaults = new Schema();
      assert.equal(schemaDefaults.discriminators, undefined);
      done();
    });

    it('can define static and instance methods', function(done) {
      var PersonSchema = new Schema('Person' + Math.random(), {
        name: String,
        createdAt: Date
      });

      var BossSchema = new Schema('Boss' + Math.random(), PersonSchema, { department: String });
      BossSchema.methods.myName = function(){
        return this.name;
      };
      BossSchema.statics.currentPresident = function(){
        return 'Putin';
      };

      var boss = new Document({name:'Bernenke'}, BossSchema);

      assert.equal(boss.myName(), 'Bernenke');
      assert.equal(boss.notInstanceMethod, undefined);
      assert.equal(boss.currentPresident(), 'Putin');
      assert.equal(boss.notStaticMethod, undefined);
      done();
    });

    it('call discriminator method directly', function(done) {
      var PersonSchema = new Schema('Person' + Math.random(), {
        name: String,
        createdAt: Date
      });

      var BossSchema = new Schema('Boss' + Math.random(), { department: String });
      BossSchema.methods.myName = function(){
        return this.name;
      };
      BossSchema.statics.currentPresident = function(){
        return 'Putin';
      };

      PersonSchema.discriminator( BossSchema.name, BossSchema );

      var boss = new Document({name:'Bernenke'}, BossSchema);

      assert.equal(boss.myName(), 'Bernenke');
      assert.equal(boss.notInstanceMethod, undefined);
      assert.equal(boss.currentPresident(), 'Putin');
      assert.equal(boss.notStaticMethod, undefined);
      done();
    });

    it('sets schema root discriminator mapping', function(done) {
      assert.deepEqual(PersonSchema.discriminatorMapping, { key: '__t', value: null, isRoot: true });
      done();
    });

    it('sets schema discriminator type mapping', function(done) {
      assert.deepEqual(EmployeeSchema.discriminatorMapping, { key: '__t', value: 'Employee', isRoot: false });
      done();
    });

    it('adds discriminatorKey to schema with default as name', function(done) {
      var type = EmployeeSchema.paths.__t;
      assert.equal(type.options.type, String);
      assert.equal(type.options.default, 'Employee');
      done();
    });

    it('adds discriminator to Schema.discriminators object', function(done) {
      assert.equal(Object.keys(PersonSchema.discriminators).length, 1);
      assert.equal(PersonSchema.discriminators.Employee, EmployeeSchema);

      var newName = 'model-discriminator-' + random();
      var newDiscriminatorSchema = new Schema( newName, PersonSchema );

      assert.equal(Object.keys(PersonSchema.discriminators).length, 2);
      assert.equal(PersonSchema.discriminators[newName], newDiscriminatorSchema);
      done();
    });

    it('throws error on invalid schema', function(done) {
      assert.throws(
        function() {
          PersonSchema.discriminator('Foo');
        },
        /You must pass a valid discriminator Schema/
      );
      done();
    });

    it('throws error when attempting to nest discriminators', function(done) {
      assert.throws(
        function() {
          EmployeeSchema.discriminator('model-discriminator-foo', new Schema());
        },
        /Discriminator "model-discriminator-foo" can only be a discriminator of the root model/
      );
      done();
    });

    it('throws error when discriminator has mapped discriminator key in schema', function(done) {
      assert.throws(
        function() {
          PersonSchema.discriminator('model-discriminator-foo', new Schema({ __t: String }));
        },
        /Discriminator "model-discriminator-foo" cannot have field with name "__t"/
      );
      done();
    });

    it('throws error when discriminator has mapped discriminator key in schema with discriminatorKey option set', function(done) {
      assert.throws(
        function() {
          var FooSchema = new Schema('model-discriminator-'+random(), {}, { discriminatorKey: '_type' });
          FooSchema.discriminator('model-discriminator-bar', new Schema({ _type: String }));
        },
        /Discriminator "model-discriminator-bar" cannot have field with name "_type"/
      );
      done();
    });

    it('throws error when discriminator with taken name is added', function(done) {
      var Foo = new Schema('model-discriminator-'+random(), {});
      Foo.discriminator('model-discriminator-taken', new Schema());
      assert.throws(
        function() {
          Foo.discriminator('model-discriminator-taken', new Schema());
        },
        /Discriminator with name "model-discriminator-taken" already exists/
      );
      done();
    });

    describe('options', function() {
      it('allows toObject to be overridden', function(done) {
        assert.notDeepEqual(EmployeeSchema.get('toObject'), PersonSchema.get('toObject'));
        assert.deepEqual(EmployeeSchema.get('toObject'), { getters: true, virtuals: false });
        done();
      });

      it('allows toJSON to be overridden', function(done) {
        assert.notDeepEqual(EmployeeSchema.get('toJSON'), PersonSchema.get('toJSON'));
        assert.deepEqual(EmployeeSchema.get('toJSON'), { getters: false, virtuals: true });
        done();
      });

      it('is not customizable', function(done) {
        var errorMessage
          , CustomizedSchema = new Schema({}, { capped: true });
        try {
          PersonSchema.discriminator('model-discriminator-custom', CustomizedSchema);
        } catch (e) {
          errorMessage = e.message;
        }

        assert.equal(errorMessage, 'Discriminator options are not customizable (except toJSON & toObject)');
        done();
      });
    });

    describe('root schema inheritance', function() {
      it('inherits field mappings', function(done) {
        assert.deepEqual(EmployeeSchema.path('name'), PersonSchema.path('name')); // is undefined
        assert.strictEqual(EmployeeSchema.path('gender'), PersonSchema.path('gender'));
        assert.equal(PersonSchema.paths.department, undefined);
        done();
      });

      it('inherits validators', function(done) {
        assert.deepEqual(EmployeeSchema.path('gender').validators, PersonSchema.path('gender').validators);
        assert.deepEqual(EmployeeSchema.path('department').validators, EmployeeSchema.path('department').validators);
        done();
      });

      it('does not inherit and override fields that exist', function(done) {
        var FemaleSchema = new Schema({ gender: { type: String, default: 'F' }})
          , Female = PersonSchema.discriminator('model-discriminator-female', FemaleSchema);

        var gender = Female.paths.gender;

        assert.notStrictEqual(gender, PersonSchema.paths.gender);
        assert.equal(gender.instance, 'String');
        assert.equal(gender.options.default, 'F');
        done();
      });

      it('inherits methods', function(done) {
        assert.strictEqual(EmployeeSchema.methods.getFullName, PersonSchema.methods.getFullName);
        assert.strictEqual(employee.getFullName, PersonSchema.methods.getFullName);
        assert.strictEqual(employee.getDepartment, EmployeeSchema.methods.getDepartment);
        assert.equal( person.getDepartment, undefined);
        done();
      });

      it('inherits statics', function(done) {
        assert.strictEqual(employee.findByGender, EmployeeSchema.statics.findByGender);
        assert.strictEqual(employee.findByDepartment, EmployeeSchema.statics.findByDepartment);
        assert.equal(person.findByDepartment, undefined);
        done();
      });

      it('inherits virtual (g.s)etters', function(done) {
        var employee = employeeCollection.add();
        employee.name.full = '<NAME>';
        assert.equal(employee.name.full, '<NAME>');
        done();
      });

      it('merges callQueue with base queue defined before discriminator types callQueue', function(done) {
        assert.equal(EmployeeSchema.callQueue.length, 2);
        // PersonSchema.post('save')
        assert.strictEqual(EmployeeSchema.callQueue[0], PersonSchema.callQueue[0]);

        // EmployeeSchema.pre('save')
        assert.strictEqual(EmployeeSchema.callQueue[1][0], 'pre');
        assert.strictEqual(EmployeeSchema.callQueue[1][1]['0'], 'save');
        assert.strictEqual(EmployeeSchema.callQueue[1][1]['1'], employeeSchemaPreSaveFn);
        done();
      });

      it('gets options overridden by root options except toJSON and toObject', function(done) {
        var personOptions = clone(person.schema.options)
          , employeeOptions = clone(employee.schema.options);

        delete personOptions.toJSON;
        delete personOptions.toObject;
        delete employeeOptions.toJSON;
        delete employeeOptions.toObject;

        assert.deepEqual(personOptions, employeeOptions);
        done();
      });
    });
  });
{'fraction_non_alphanumeric': 0.14202257136534632, 'fraction_numerical': 0.0015047576897543704, 'mean_word_length': 3.29500095038966, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3202858', 'n_tokens_mistral': 6446, 'n_tokens_neox': 6149, 'n_words': 1305}