/** @module certainty */
var Subject = require('./subject');
var ProxyBase = require('./proxy');
/** A fluent context object containing the value of the field that was just tested. Used for
additional assertions about a field.
@constructor
*/
function KeyValue(subject, key) {
this.subject = subject;
this.key = key;
this.format = subject.format;
this.value = subject.value.get(key);
}
/** Ensure that the field has the expected value.
@param {*} value The expected value of the field.
*/
KeyValue.prototype.withValue = function (expected) {
if (this.value != expected) {
this.subject.fail('Expected ' + this.subject.describe() + ' to contain key ' +
this.format(this.key) + ' with value ' + this.format(expected) + ', actual value was ' +
this.value + '.');
}
}
ProxyBase.addMethods(KeyValue);
// 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 Map types.
@param {FailureStrategy} failureStrategy The failure strategy to use when an assertion fails.
@param {object} value The value being checked.
@constructor
@extends Subject
*/
function MapSubject(failureStrategy, value) {
Subject.call(this, failureStrategy, value);
}
MapSubject.prototype = Object.create(Subject.prototype);
MapSubject.prototype.constructor = MapSubject;
/** Ensure that the map is empty.
@return {MapSubject} `this` for chaining.
*/
MapSubject.prototype.isEmpty = function () {
if (this.value.size !== 0) {
this.fail('Expected ' + this.describe() + ' to be an empty map.');
}
return this;
};
/** Ensure that the map is non-empty.
@return {MapSubject} `this` for chaining.
*/
MapSubject.prototype.isNotEmpty = function () {
if (this.value.size === 0) {
this.fail('Expected ' + this.describe() + ' to be a non-empty map.');
}
return this;
};
/** Ensure that the map is the expected size.
@param {number} size The expected size of the map.
@return {MapSubject} `this` for chaining.
*/
MapSubject.prototype.hasSize = function (size) {
if (this.value.size !== size) {
this.fail('Expected ' + this.describe() + ' to be of size ' + size +
', actual size was ' + this.value.size + '.');
}
return this;
};
/** Ensure that the map contains a given key.
@return {MapSubject} `this` for chaining.
@param {*} key The key expected to be in the map.
*/
MapSubject.prototype.containsKey = function (key) {
if (!this.value.has(key)) {
this.fail('Expected ' + this.describe() + ' to contain key ' + this.format(key) + '.');
return new MissingKeyValue();
}
return new KeyValue(this, key);
};
/** Ensure that the map does not contain a given key.
@param {*} key The key not expected to be in the map.
@return {MapSubject} `this` for chaining.
*/
MapSubject.prototype.doesNotContainKey = function (key) {
if (this.value.has(key)) {
this.fail('Expected ' + this.describe() + ' to not contain key ' +
this.format(key) + '.');
}
return this;
};
/** Ensure that the map contains a given key / value pair.
@param {*} key The key expected to be in the map.
@param {*} value The expected value for that key.
@return {MapSubject} `this` for chaining.
*/
MapSubject.prototype.containsEntry = function (key, value) {
if (!this.value.has(key)) {
this.fail('Expected ' + this.describe() + ' to contain key ' + this.format(key) + '.');
} else if (this.value.get(key) != value) {
this.fail('Expected ' + this.describe() + ' to contain key ' + this.format(key) +
' with value ' + this.format(value) + ', actual value was ' +
this.format(this.value.get(key)) + '.');
}
return this;
};
module.exports = MapSubject;