test('multiple mixins', function(assert) {
  let Validations1 = buildValidations({
    'firstName': validator(Validators.presence)
  });

  let Validations2 = buildValidations({
    'middleName': validator(Validators.presence)
  });

  let Validations3 = buildValidations({
    'lastName': validator(Validators.presence)
  });

  let object = setupObject(this, Ember.Object.extend(Validations1, Validations2, Validations3));

  assert.deepEqual(object.get('validations.validatableAttributes').sort(), ['firstName', 'middleName', 'lastName'].sort());
  assert.equal(object.get('validations.attrs.firstName.isValid'), false);
  assert.equal(object.get('validations.attrs.lastName.isValid'), false);
  assert.equal(object.get('validations.isValid'), false);

  object.set('firstName', 'Offir');

  assert.equal(object.get('validations.attrs.firstName.isValid'), true);
  assert.equal(object.get('validations.isValid'), false);

  object.set('middleName', 'David');

  assert.equal(object.get('validations.attrs.middleName.isValid'), true);
  assert.equal(object.get('validations.isValid'), false);

  object.set('lastName', 'Golan');

  assert.equal(object.get('validations.attrs.lastName.isValid'), true);
  assert.equal(object.get('validations.isValid'), true);
});
test('validations persist with inheritance', function(assert) {
  let Parent = Ember.Object.extend(buildValidations({
    firstName: validator(Validators.presence),
    lastName: validator(Validators.presence)
  }));

  let Child = Parent.extend(buildValidations({
    middleName: validator(Validators.presence),
    dob: validator(Validators.presence)
  }));

  let child = setupObject(this, Child);

  child.validateSync();

  assert.equal(child.get('validations.errors.length'), 4);
  assert.equal(child.get('validations.isValid'), false);
  assert.deepEqual(child.get('validations.validatableAttributes').sort(), ['firstName', 'lastName', 'middleName', 'dob'].sort());

  child.setProperties({
    middleName: 'John',
    dob: '10/22/16'
  });

  assert.equal(child.get('validations.errors.length'), 2);

  child.setProperties({
    firstName: 'Joe',
    lastName: 'Jenkins'
  });

  assert.equal(child.get('validations.isValid'), true);
  assert.equal(child.get('validations.errors.length'), 0);
});
test('volatile validations should not recompute', function(assert) {
  this.register('validator:presence', PresenceValidator);
  this.register('validator:length', LengthValidator);

  let Validations = buildValidations({
    firstName: [
      validator('presence', true),
      validator('length', {
        dependentKeys: ['model.foo'],
        min: 5,
        max: 35,
        volatile: true
      })
    ]
  });

  let obj = setupObject(this, Ember.Object.extend(Validations, {
    isInvalid: computed.not('validations.attrs.firstName.isValid'),
    isInvalidGlobal: computed.not('validations.attrs.isValid')
  }), {
    firstName: null
  });

  assert.equal(obj.get('validations.attrs.firstName.isValid'), false, 'isValid was expected to be FALSE');
  assert.equal(obj.get('validations.attrs.firstName.message'), 'This field can\'t be blank');
  assert.equal(obj.get('isInvalid'), true, 'isInvalid was expected to be TRUE');
  assert.equal(obj.get('isInvalidGlobal'), true, 'isInvalidGlobal was expected to be TRUE');

  obj.set('firstName', 'Offir');
  obj.set('foo', 'bar');

  assert.equal(obj.get('isInvalid'), true, 'isInvalid was expected to be TRUE');
  assert.equal(obj.get('isInvalidGlobal'), true, 'isInvalidGlobal was expected to be TRUE');
  assert.equal(obj.get('validations.attrs.firstName.isValid'), true, 'isValid was expected to be TRUE');
});
test("nested keys - complex", function(assert) {
  var Validations = buildValidations({
    'firstName': validator(Validators.presence),
    'user.foo.bar.baz': validator(Validators.presence),
    'user.foo.boop': validator(Validators.presence)
  });
  var object = setupObject(this, Ember.Object.extend(Validations));

  assert.equal(object.get('validations.attrs.firstName.isValid'), false);
  assert.equal(object.get('validations.attrs.user.foo.bar.baz.isValid'), false);
  assert.equal(object.get('validations.attrs.user.foo.boop.isValid'), false);
  assert.equal(object.get('validations.isValid'), false);

  object.set('user', { foo: { bar: {} } });

  assert.equal(object.get('validations.attrs.firstName.isValid'), false);
  assert.equal(object.get('validations.attrs.user.foo.bar.baz.isValid'), false);
  assert.equal(object.get('validations.attrs.user.foo.boop.isValid'), false);
  assert.equal(object.get('validations.isValid'), false);

  object.set('firstName', 'Offir');
  object.set('user.foo.bar.baz', 'blah');
  object.set('user.foo.boop', 'blah');

  assert.equal(object.get('validations.attrs.firstName.isValid'), true);
  assert.equal(object.get('validations.attrs.user.foo.bar.baz.isValid'), true);
  assert.equal(object.get('validations.attrs.user.foo.boop.isValid'), true);

  assert.ok(object.get('validations.attrs._model'));
  assert.ok(object.get('validations.attrs.user.foo.bar._model'));
  assert.ok(object.get('validations.attrs.user.foo._model'));

  assert.equal(object.get('validations.isValid'), true);
});
test("disabled validations - function with dependent key", function(assert) {
  var Validations = buildValidations({
    firstName: validator(Validators.presence),
    lastName: validator(Validators.presence, {
      dependentKeys: ['validateLastName'],
      disabled() {
        return !this.get('model.validateLastName');
      }
    })
  });
  var object = setupObject(this, Ember.Object.extend(Validations, {
    firstName: 'Offir',
    validateLastName: true
  }));

  assert.equal(object.get('validations.isValid'), false, 'isValid was expected to be FALSE');
  assert.equal(object.get('validations.isValidating'), false, 'isValidating was expected to be TRUE');
  assert.equal(object.get('validations.isTruelyValid'), false, 'isTruelyValid was expected to be FALSE');

  assert.equal(object.get('validations.attrs.lastName.isValid'), false);
  assert.equal(object.get('validations.attrs.firstName.isValid'), true);

  object.set('validateLastName', false);

  assert.equal(object.get('validations.attrs.lastName.isValid'), true);
  assert.equal(object.get('validations.isValid'), true);
});
test("presence on empty DS.PromiseArray", function(assert) {
  this.register('validator:presence', PresenceValidator);

  var Validations = buildValidations({
    friends: validator('presence', true)
  });

  var user = setupObject(this, Ember.Object.extend(Validations), {
    friends: DS.PromiseArray.create()
  });

  const {
    validations,
    model
  } = user.get('validations').validateSync();

  assert.equal(model, user, 'expected model to be the correct model');
  assert.deepEqual(validations.get('content').getEach('attribute').sort(), ['friends'].sort());

  let friends = validations.get('content').findBy('attribute', 'friends');

  assert.equal(friends.get('isValid'), false);
  assert.equal(friends.get('message'), "This field can't be blank");

});
test("alias validation - multiple", function(assert) {
  this.register('validator:alias', AliasValidator);

  var user = setupObject(this, Ember.Object.extend(buildValidations({
    firstName: validator(Validators.presence),
    lastName: validator(Validators.presence),
    fullName: [
      validator('alias', 'firstName'),
      validator('alias', 'lastName')
    ]
  }, { lazy: false })));

  user.get('validations').validateSync();

  assert.equal(user.get('validations.isValid'), false);
  assert.equal(user.get('validations.isValidating'), false);
  assert.equal(user.get('validations.attrs.firstName.isValid'), false);
  assert.equal(user.get('validations.attrs.lastName.isValid'), false);
  assert.equal(user.get('validations.attrs.fullName.isValid'), false);
  assert.deepEqual(user.get('validations.attrs.fullName.messages').sort(), ['firstName should be present', 'lastName should be present'].sort());
  assert.ok(emberArray(user.get('validations.attrs.fullName.errors')).isEvery('parentAttribute', 'fullName'));

  user.set('firstName', 'Offir');

  assert.equal(user.get('validations.attrs.firstName.isValid'), true);
  assert.equal(user.get('validations.attrs.lastName.isValid'), false);
  assert.equal(user.get('validations.attrs.fullName.isValid'), false);

  user.set('lastName', 'Golan');

  assert.equal(user.get('validations.attrs.lastName.isValid'), true);
  assert.equal(user.get('validations.attrs.fullName.isValid'), true);
});
test("alias validation - simple", function(assert) {
  this.register('validator:alias', AliasValidator);

  var user = setupObject(this, Ember.Object.extend(buildValidations({
    firstName: validator(Validators.presence),
    lastName: validator(Validators.presence),
    fullName: validator('alias', 'firstName')
  })));

  user.get('validations').validateSync();

  assert.equal(user.get('validations.isValid'), false);
  assert.equal(user.get('validations.isValidating'), false);
  assert.equal(user.get('validations.attrs.firstName.isValid'), false);
  assert.equal(user.get('validations.attrs.fullName.isValid'), false);
  assert.equal(user.get('validations.attrs.fullName.message'), 'firstName should be present');
  assert.equal(user.get('validations.attrs.fullName.error.attribute'), 'firstName');
  assert.equal(user.get('validations.attrs.fullName.error.parentAttribute'), 'fullName');
  assert.equal(user.get('validations.attrs.fullName.error.message'), 'firstName should be present');

  user.set('firstName', 'Offir');

  assert.equal(user.get('validations.attrs.firstName.isValid'), true);
  assert.equal(user.get('validations.attrs.fullName.isValid'), true);
});
test("belongs-to relationship is async and isWarning", function(assert) {
  this.register('validator:belongs-to', BelongsToValidator);

  var BelongsToValidations = buildValidations({
    friend: validator('belongs-to', { isWarning: true })
  });

  var friend = setupObject(this, Ember.Object.extend(Validations), {
    firstName: 'Offir'
  });

  var user = setupObject(this, Ember.Object.extend(BelongsToValidations), {
    friend: new Ember.RSVP.Promise((resolve) => {
      resolve(friend);
    })
  });

  var validations = user.get('validations').validate();
  assert.equal(user.get('validations.isAsync'), true);
  assert.equal(user.get('validations.isValidating'), true);

  validations.then(({
    model, validations
  }) => {
    assert.equal(model, user, 'expected model to be the correct model');
    assert.deepEqual(validations.get('content').getEach('attribute').sort(), ['friend'].sort());

    let friend = validations.get('content').findBy('attribute', 'friend');

    assert.equal(friend.get('isValid'), true);
  });

  return validations;
});
test("custom dependent keys - default options", function(assert) {
  var Validations = buildValidations({
    fullName: {
      dependentKeys: ['firstName'],
      validators: [
        validator(function(value, options, model) {
          let firstName = model.get('firstName');
          let lastName = model.get('lastName');
          if (!firstName || !lastName) {
            return 'Full name requires first and last name';
          }
          return true;
        }, {
          dependentKeys: ['lastName']
        })
      ]
    }
  });

  var obj = setupObject(this, Ember.Object.extend(Validations));

  assert.equal(obj.get('validations.isValid'), false);
  assert.equal(obj.get('validations.attrs.fullName.isValid'), false);
  assert.equal(obj.get('validations.attrs.fullName.message'), 'Full name requires first and last name');

  obj.set('firstName', 'Offir');
  obj.set('lastName', 'Golan');

  assert.equal(obj.get('validations.isValid'), true);
  assert.equal(obj.get('validations.attrs.fullName.isValid'), true);
});
test("custom dependent keys - array", function(assert) {
  var Validations = buildValidations({
    friends: validator(function(value, options, model) {
      let friends = model.get('friends');
      if (!friends || friends.length === 0) {
        return 'User must have a friend';
      }
      return true;
    }, {
      dependentKeys: ['friends.[]']
    })
  });

  var obj = setupObject(this, Ember.Object.extend(Validations), {
    friends: Ember.A()
  });

  assert.equal(obj.get('validations.isValid'), false);
  assert.equal(obj.get('validations.attrs.friends.isValid'), false);
  assert.equal(obj.get('validations.attrs.friends.message'), 'User must have a friend');

  obj.get('friends').pushObject('Offir');

  assert.equal(obj.get('validations.isValid'), true);
  assert.equal(obj.get('validations.attrs.friends.isValid'), true);

  obj.get('friends').removeObject('Offir');

  assert.equal(obj.get('validations.isValid'), false);
  assert.equal(obj.get('validations.attrs.friends.isValid'), false);
  assert.equal(obj.get('validations.attrs.friends.message'), 'User must have a friend');

});
  test('custom dependent keys - simple', function(assert) {
    let Validations = buildValidations({
      fullName: validator('inline', {
        dependentKeys: ['model.firstName', 'model.lastName'],
        validate(value, options, model) {
          let firstName = model.get('firstName');
          let lastName = model.get('lastName');
          if (!firstName || !lastName) {
            return 'Full name requires first and last name';
          }
          return true;
        }
      })
    });

    let obj = setupObject(this, EmberObject.extend(Validations));

    assert.equal(obj.get('validations.isValid'), false);
    assert.equal(obj.get('validations.attrs.fullName.isValid'), false);
    assert.equal(
      obj.get('validations.attrs.fullName.message'),
      'Full name requires first and last name'
    );

    obj.set('firstName', 'Offir');
    obj.set('lastName', 'Golan');

    assert.equal(obj.get('validations.isValid'), true);
    assert.equal(obj.get('validations.attrs.fullName.isValid'), true);
  });
  test('nested ds-error validator creates correct dependent keys', function(assert) {
    this.owner.register('validator:ds-error', DSErrorValidator);
    this.owner.register('validator:length', LengthValidator);

    let DSErrorValidations = buildValidations({
      'model.username': validator('ds-error')
    });

    let obj = setupObject(this, EmberObject.extend(DSErrorValidations), {
      model: EmberObject.create({
        errors: DS.Errors.create(),
        username: ''
      })
    });

    assert.equal(obj.get('validations.attrs.model.username.isValid'), true);

    obj.get('model.errors').add('username', 'Username is not unique');

    assert.equal(obj.get('validations.attrs.model.username.isValid'), false);
    assert.equal(
      obj.get('validations.attrs.model.username.message'),
      'Username is not unique'
    );
  });
  test('collection validator creates correct dependent keys', function(assert) {
    this.owner.register('validator:collection', CollectionValidator);
    this.owner.register('validator:length', LengthValidator);

    let CollectionValidations = buildValidations({
      array: [
        validator('collection', true),
        validator('length', {
          is: 2,
          message: 'Array must have {is} items'
        })
      ]
    });
    let obj = setupObject(this, EmberObject.extend(CollectionValidations), {
      array: A(['foo', 'bar'])
    });

    assert.equal(obj.get('validations.attrs.array.isValid'), true);

    obj.get('array').removeObject('bar');

    assert.equal(obj.get('validations.attrs.array.isValid'), false);
    assert.equal(
      obj.get('validations.attrs.array.message'),
      'Array must have 2 items'
    );
  });
test('validator should return correct error type', function(assert) {
  this.register('validator:presence', PresenceValidator);
  this.register('validator:length', LengthValidator);

  let Validations = buildValidations({
    firstName: [
      validator('presence', true),
      validator('length', { min: 5, max: 35 })
    ],
    lastName: [
      validator('presence', true),
      validator('length', { min: 5, max: 35 })
    ]
  });

  let obj = setupObject(this, Ember.Object.extend(Validations), {
    firstName: 'Foo',
    lastName: null
  });

  assert.equal(obj.get('validations.attrs.firstName.isValid'), false, 'isValid was expected to be FALSE');
  assert.equal(obj.get('validations.attrs.lastName.error.type'), 'presence', 'error type was expected to be `presence`');
  assert.equal(obj.get('validations.errors.length'), 2, 'number of errors was expected to be 2');
  assert.equal(obj.get('validations.errors').filterBy('type', 'presence').length, 1, 'number of errors was expected to be 1');
});
test("attribute validation result options hash with functions", function(assert) {
  assert.expect(5);
  this.register('validator:length', LengthValidator);

  var Validations = buildValidations({
    firstName: {
      validators: [
        validator('length', {
          dependentKeys: ['max'],
          min: 1,
          max(model) {
            assert.ok(true);
            return model.get('max');
          }
        })
      ]
    }
  });
  var object = setupObject(this, Ember.Object.extend(Validations, { max: 5 }));
  var options = object.get('validations.attrs.firstName.options');
  assert.equal(options.length.max, 5);

  run(() => object.set('max', 3));

  options = object.get('validations.attrs.firstName.options');
  assert.equal(options.length.max, 3);

  options = object.get('validations.attrs.firstName.options');
  assert.equal(options.length.max, 3);
});
test('call super in validations class with no super property', function(assert) {
  // see https://github.com/offirgolan/ember-cp-validations/issues/149
  assert.expect(1);

  let Validations = buildValidations({
    'firstName': validator(Validators.presence)
  });

  let mixin = Ember.Mixin.create({
    actions: {
      foo() {
        // The issue is that __validationsClass__ is calling super but since
        // this is no __validationsClass__ method on the super, it is wrapped
        // with the closest context which is the 'foo' action
        assert.ok(false); // should not reach here
      }
    }
  });

  let controller = setupObject(this, Ember.Controller.extend(Validations, mixin, {
    actions: {
      foo() {
        assert.ok(true);
        let validations = this.get('validations'); // jshint ignore:line
      }
    }
  }));

  controller.send('foo');
});
test('attribute validation result options hash', function(assert) {
  this.register('validator:length', LengthValidator);
  this.register('validator:presence', PresenceValidator);

  let Validations = buildValidations({
    firstName: {
      description: 'First Name',
      validators: [
        validator(Validators.presence, {}),
        validator(Validators.presence, { presence: true }),
        validator('presence', true),
        validator('length', {
          min: 1,
          max: 5
        })
      ]
    }
  });
  let object = setupObject(this, Ember.Object.extend(Validations, { max: 5 }));
  let options = object.get('validations.attrs.firstName.options');

  assert.ok(options);
  assert.deepEqual(Object.keys(options).sort(), ['presence', 'length', 'function'].sort());
  assert.ok(Ember.isArray(options['function']) && options['function'].length === 2);
  assert.ok(options.presence.presence);
  assert.equal(options.length.min, 1);
  assert.ok(options['function'][1].presence);

  // Default options built into option objects
  assert.equal(options.length.description, 'First Name');
  assert.equal(options.presence.description, 'First Name');
  assert.equal(options['function'][0].description, 'First Name');
});
test('debounced validator should only be called once', function(assert) {
  let count = 0;

  let done = assert.async();
  let Validations = buildValidations({
    firstName: validator(() => count++, {
      debounce: 500
    })
  });

  let object = setupObject(this, Ember.Object.extend(Validations));

  object.set('firstName', 'O');
  object.get('validations.attrs.firstName.isValid');

  object.set('firstName', 'Off');
  object.get('validations.attrs.firstName.isValid');

  object.set('firstName', 'Offir');
  object.get('validations.attrs.firstName.isValid');

  run.later(() => {
    assert.equal(count, 1);
    done();
  }, 500);
});
test('debounced validations', function(assert) {
  let done = assert.async();
  let initSetup = true;
  let Validations = buildValidations({
    firstName: validator(Validators.presence),
    lastName: validator(Validators.presence, {
      debounce: computed(function() {
        return initSetup ? 0 : 500; // Do not debounce on initial object creation
      }).volatile()
    })
  });
  let object = setupObject(this, Ember.Object.extend(Validations));

  assert.equal(object.get('validations.isValid'), false, 'isValid was expected to be FALSE');
  assert.equal(object.get('validations.isValidating'), false, 'isValidating was expected to be TRUE');
  assert.equal(object.get('validations.isTruelyValid'), false, 'isTruelyValid was expected to be FALSE');

  assert.equal(object.get('validations.attrs.lastName.isValid'), false);
  assert.equal(object.get('validations.attrs.lastName.isValidating'), false);
  assert.equal(object.get('validations.attrs.lastName.message'), 'lastName should be present');

  initSetup = false;
  object.set('lastName', 'Golan');
  assert.equal(object.get('validations.attrs.lastName.isValidating'), true);

  run.later(() => {
    assert.equal(object.get('validations.attrs.lastName.isValid'), true);
    assert.equal(object.get('validations.attrs.lastName.isValidating'), false);
    assert.equal(object.get('validations.attrs.lastName.message'), null);
    done();
  }, 500);
});
test('global options', function(assert) {
  this.register('validator:length', LengthValidator);

  let Validations = buildValidations({
    firstName: {
      description: 'Test field',
      validators: [
        validator('length', { min: 1, max: 5 })
      ]
    }
  }, {
    message: 'Global error message',
    description: 'Default field',
    max: 10
  });

  let object = setupObject(this, Ember.Object.extend(Validations), {
    firstName: ''
  });

  // Global options present in rules
  let rules = Ember.A(object.get('validations._validationRules.firstName'));
  assert.equal(rules.isAny('globalOptions', undefined), false);
  assert.equal(rules[0].globalOptions.max, 10);

  assert.ok(object.get('validations.attrs.firstName.isInvalid'));

  let v = object.get('validations._validators.firstName.0');
  assert.deepEqual(v.get('options').getProperties(['message', 'description', 'min', 'max']), {
    message: 'Global error message',
    description: 'Test field',
    min: 1,
    max: 5
  });
});
test('validations persist with deep inheritance', function(assert) {
  let Parent = Ember.Object.extend(buildValidations({
    firstName: validator(Validators.presence),
    lastName: validator(Validators.presence)
  }));

  let Child = Parent.extend(buildValidations({
    middleName: validator(Validators.presence),
    dob: validator(Validators.presence)
  }));

  let Baby = Child.extend(buildValidations({
    diaper: validator(Validators.presence),
    favParent: validator(Validators.presence)
  }));

  let baby = setupObject(this, Baby);

  baby.validateSync();

  assert.equal(baby.get('validations.errors.length'), 6);
  assert.equal(baby.get('validations.isValid'), false);
  assert.deepEqual(baby.get('validations.validatableAttributes').sort(), ['firstName', 'lastName', 'middleName', 'dob', 'diaper', 'favParent'].sort());

  baby.setProperties({
    middleName: 'John',
    dob: '10/22/16'
  });

  assert.equal(baby.get('validations.errors.length'), 4);

  baby.setProperties({
    firstName: 'Joe',
    lastName: 'Jenkins'
  });

  assert.equal(baby.get('validations.errors.length'), 2);

  baby.setProperties({
    diaper: 'soiled',
    favParent: 'mom'
  });

  assert.equal(baby.get('validations.isValid'), true);
  assert.equal(baby.get('validations.errors.length'), 0);
});
test('nested keys - inheritance', function(assert) {
  let Parent = Ember.Object.extend(buildValidations({
    'firstName': validator(Validators.presence),
    'user.firstName': validator(Validators.presence),
    'user.middleName': validator(Validators.presence)
  }));

  let Child = Parent.extend(buildValidations({
    'user.lastName': validator(Validators.presence),
    'user.middleName': validator(function() {
      return 'Middle name invalid';
    })
  }));

  let child = setupObject(this, Child);

  child.validateSync();

  assert.equal(child.get('validations.errors.length'), 4);
  assert.equal(child.get('validations.isValid'), false);
  assert.deepEqual(child.get('validations.validatableAttributes').sort(), ['firstName', 'user.firstName', 'user.middleName' ,'user.lastName'].sort());

  child.setProperties({
    user: {
      firstName: 'Offir',
      'middleName': 'David',
      lastName: 'Golan'
    }
  });

  assert.equal(child.get('validations.errors.length'), 2);
  assert.equal(child.get('validations.attrs.user.middleName.message'), 'Middle name invalid');

  child.setProperties({
    firstName: 'John'
  });

  assert.equal(child.get('validations.isValid'), false);
  assert.equal(child.get('validations.errors.length'), 1);
});
test('null message object', function(assert) {
  this.register('validator:messages', DefaultMessages);
  let Validations = buildValidations({
    firstName: validator('presence', {
      presence: true,
      message: null
    })
  });

  let object = setupObject(this, Ember.Object.extend(Validations));

  assert.equal(object.get('validations.attrs.firstName.message'), 'This field can\'t be blank');
});
test('load test', function(assert) {
  this.register('validator:presence', PresenceValidator);

  let Validations = buildValidations({
    a: validator('presence', true),
    b: validator('presence', true),
    c: validator('presence', true),
    d: validator('presence', true),
    e: validator('presence', true)
  });

  let Klass = Ember.Object.extend(Validations, {
    a: null,
    b: null,
    c: null,
    d: null,
    e: null
  });

  let items = Ember.A([]);
  for (let i = 0; i < 50; i++) {
    let obj = setupObject(this, Klass, {
      a: i,
      b: i,
      c: i,
      d: i,
      e: i
    });
    items.push(obj);
  }

  console.time('init');
  items.mapBy('validations.isValid');
  console.timeEnd('init');

  items.forEach((item, i) => {
    item.setProperties({
      a: i + 1000,
      b: i + 1000,
      c: i + 1000,
      d: i + 1000,
      e: i + 1000
    });
  });

  console.time('after set');
  Ember.A(items).mapBy('validations.isValid');
  console.timeEnd('after set');

  assert.ok(true);
});
test('custom messages object', function(assert) {
  this.register('validator:messages', DefaultMessages);
  let Validations = buildValidations({
    firstName: validator(function(value) {
      return this.createErrorMessage('test', value);
    })
  });

  let object = setupObject(this, Ember.Object.extend(Validations));

  assert.equal(object.get('validations.attrs.firstName.isValid'), false);
  assert.equal(object.get('validations.attrs.firstName.isValidating'), false);
  assert.equal(object.get('validations.attrs.firstName.message'), 'Test error message');
});
  test('custom dependent keys - array of objects', function(assert) {
    let Validations = buildValidations({
      friends: validator('inline', {
        dependentKeys: ['*****@*****.**'],
        validate(value, options, model) {
          let friends = model.get('friends');
          if (!friends || friends.length === 0) {
            return 'User must have a friend';
          } else if (friends.length > 0) {
            let names = friends.filter(f => f.name);
            if (names.length !== friends.length) {
              return 'All friends must have a name';
            }
          }
          return true;
        }
      })
    });

    let obj = setupObject(this, EmberObject.extend(Validations), {
      friends: A()
    });

    assert.equal(obj.get('validations.isValid'), false);
    assert.equal(obj.get('validations.attrs.friends.isValid'), false);
    assert.equal(
      obj.get('validations.attrs.friends.message'),
      'User must have a friend'
    );

    obj.get('friends').pushObject(
      EmberObject.create({
        name: 'Offir'
      })
    );

    assert.equal(obj.get('validations.isValid'), true);
    assert.equal(obj.get('validations.attrs.friends.isValid'), true);

    obj.get('friends.0').set('name', undefined);

    assert.equal(obj.get('validations.isValid'), false);
    assert.equal(obj.get('validations.attrs.friends.isValid'), false);
    assert.equal(
      obj.get('validations.attrs.friends.message'),
      'All friends must have a name'
    );
  });
test('debounced validations should cleanup on object destroy', function(assert) {
  let done = assert.async();
  let initSetup = true;

  let debouncedValidator = validator((value, options, model, attr) => {
    model.set('foo', 'bar');
    return Validators.presence(value, options, model, attr);
  }, {
    debounce: computed(function() {
      return initSetup ? 0 : 500;
    }).volatile()
  });

  let Validations = buildValidations({
    firstName: validator(Validators.presence),
    lastName: debouncedValidator,
    'details.url': debouncedValidator
  });
  let object = setupObject(this, Ember.Object.extend(Validations), {
    details: {}
  });

  assert.equal(object.get('validations.isValid'), false, 'isValid was expected to be FALSE');
  assert.equal(object.get('validations.isValidating'), false, 'isValidating was expected to be TRUE');
  assert.equal(object.get('validations.isTruelyValid'), false, 'isTruelyValid was expected to be FALSE');

  assert.equal(object.get('validations.attrs.lastName.isValid'), false);
  assert.equal(object.get('validations.attrs.lastName.isValidating'), false);
  assert.equal(object.get('validations.attrs.lastName.message'), 'lastName should be present');

  initSetup = false;
  object.setProperties({
    'lastName': 'Golan',
    'details.url': 'github.com'
  });
  assert.equal(object.get('validations.attrs.lastName.isValidating'), true);
  assert.equal(object.get('validations.attrs.details.url.isValidating'), true);

  run.later(() => {
    try {
      object.destroy();
      assert.ok(true, 'Object destroy was clean');
    } catch(e) {}
    run.later(() => {
      done();
    }, 400);
  }, 200);
});
test('basic sync validation returns null', function(assert) {
  let Validations = buildValidations({
    firstName: validator(() => null)
  });
  let object = setupObject(this, Ember.Object.extend(Validations), {
    firstName: 'Offir'
  });

  assert.equal(object.get('validations.isValid'), false, 'isValid was expected to be FALSE');
  assert.equal(object.get('validations.isValidating'), false, 'isValidating was expected to be FALSE');
  assert.equal(object.get('validations.isTruelyValid'), false, 'isTruelyValid was expected to be FALSE');

  assert.equal(object.get('validations.attrs.firstName.isValid'), false);
  assert.equal(object.get('validations.attrs.firstName.isValidating'), false);
  assert.equal(object.get('validations.attrs.firstName.message'), undefined);

});
test('default options', function(assert) {
  let Validations = buildValidations({
    firstName: {
      description: 'Test field',
      validators: [
        validator(Validators.presence),
        validator(() => false)
      ]
    }
  });
  let object = setupObject(this, Ember.Object.extend(Validations), {
    firstName: ''
  });
  let rules = Ember.A(object.get('validations._validationRules.firstName'));
  assert.equal(rules.isAny('defaultOptions', undefined), false);
  assert.equal(rules[0].defaultOptions.description, 'Test field');
});