/** @module certainty */
var Subject = require('./subject');
var ProxyBase = require('./proxy');
function isEmpty(obj) {
/* eslint no-unused-vars: ["off"] */
for (var x in obj) { return false; }
return true;
}
/** A fluent context object containing the value of the field that was just tested. Used for
additional assertions about a field.
@constructor
*/
function FieldValue(subject, name, value) {
this.subject = subject;
this.name = name;
this.value = subject.value[name];
this.format = subject.format;
}
/** Ensure that the field has the expected value.
@param {*} value The expected value of the field.
*/
FieldValue.prototype.withValue = function (expected) {
if (this.value != expected) {
this.subject.fail('Expected ' + this.subject.describe() + ' to have a field \'' + this.name +
'\' with value ' + this.format(expected) + ', actual value was ' +
this.format(this.value) + '.');
}
return this;
}
ProxyBase.addMethods(FieldValue);
// Used when the key is missing, so that .withValue() doesn't produce a second error message.
function MissingKeyValue() {}
MissingKeyValue.prototype.withValue = function (expected) {
return this;
}
/** Subclass of Subject which provides assertions methods for object types.
@param {FailureStrategy} failureStrategy The failure strategy to use when an assertion fails.
@param {object} value The value being checked.
@constructor
@extends Subject
*/
function ObjectSubject(failureStrategy, value) {
Subject.call(this, failureStrategy, value);
}
ObjectSubject.prototype = Object.create(Subject.prototype);
ObjectSubject.prototype.constructor = ObjectSubject;
/** Ensure that the object being tested is empty. This only checks for fields on the object, not
its prototype.
@return {ObjectSubject} `this` for chaining.
*/
ObjectSubject.prototype.isEmpty = function () {
if (!isEmpty(this.value)) {
this.fail('Expected ' + this.describe() + ' to be empty.');
}
return this;
};
/** Ensure that the object being tested is non-empty. This only checks for fields on the object,
not its prototype.
@return {ObjectSubject} `this` for chaining.
*/
ObjectSubject.prototype.isNotEmpty = function () {
if (isEmpty(this.value)) {
this.fail('Expected ' + this.describe() + ' to be non-empty.');
}
return this;
};
/** Ensure that the object being tested has a property (either its own or inherited) with the
specified field name.
@param {string} fieldName The name of the property.
@return {FieldValue} FieldValue for additional assertions on the field value.
*/
ObjectSubject.prototype.hasField = function (fieldName) {
if (!(fieldName in this.value)) {
this.fail('Expected ' + this.describe() + ' to have a field named \'' +
fieldName + '\'.');
return new MissingKeyValue();
}
return new FieldValue(this, fieldName);
};
/** Ensure that the object being tested dows not have a property (either its own or inherited)
with the specified field name.
@param {string} fieldName The name of the property.
@return {ObjectSubject} `this` for chaining.
*/
ObjectSubject.prototype.doesNotHaveField = function (fieldName) {
if (fieldName in this.value) {
this.fail('Expected ' + this.describe() + ' to not have a field named \'' +
fieldName + '\'.');
}
return this;
};
/** Ensure that the object has a property with the given field name. The property must be one
of the object's own properties, not one inherited from a prototype.
@param {string} fieldName The name of the property.
@return {FieldValue} FieldValue for additional assertions on the field value.
*/
ObjectSubject.prototype.hasOwnField = function (fieldName) {
if (!Object.prototype.hasOwnProperty.call(this.value, fieldName)) {
this.fail('Expected ' + this.describe() + ' to have own field named \'' +
fieldName + '\'.');
}
return new FieldValue(this, fieldName);
};
/** Ensure that the object does not have it's own property with the given field name.
@param {string} fieldName The name of the property.
@return {ObjectSubject} `this` for chaining.
*/
ObjectSubject.prototype.doesNotHaveOwnField = function (fieldName) {
if (Object.prototype.hasOwnProperty.call(this.value, fieldName)) {
this.fail('Expected ' + this.describe() + ' to not have own field named \'' +
fieldName + '\'.');
}
return this;
};
module.exports = ObjectSubject;