@plugjs/expect5
Version:
Unit Testing for the PlugJS Build System ========================================
146 lines (145 loc) • 4.53 kB
JavaScript
// expectation/include.ts
import { $plur } from "@plugjs/plug/logging";
import { diff } from "./diff.mjs";
import {
ExpectationError,
stringifyObjectType,
stringifyValue
} from "./types.mjs";
function toInclude(expectations, negative, contents) {
if (contents instanceof Map) return includesMappings(expectations, negative, contents);
if (contents instanceof Set) return includesValues(expectations, negative, contents);
if (Array.isArray(contents)) return includesValues(expectations, negative, new Set(contents));
if (contents instanceof Object) return includesProps(expectations, negative, contents);
throw new TypeError(`Invalid type for "toInclude(...)": ${stringifyValue(contents)}`);
}
function toMatchContents(expectations, contents) {
let actual;
let expected;
try {
actual = new Set(expectations.value);
expected = new Set(contents);
} catch {
throw new ExpectationError(expectations, "to be an iterable object");
}
const result = diff(actual, expected);
delete result.error;
if (!result.diff) return;
throw new ExpectationError(
expectations,
`to match contents of ${stringifyObjectType(contents)}`,
{ ...result, value: expectations.value }
);
}
function includesProps(expectations, negative, expected) {
if (expectations.value instanceof Map) {
return includesMappings(expectations, negative, new Map(Object.entries(expected)));
}
expectations.toBeInstanceOf(Object);
const actual = expectations.value;
const keys = new Set(Object.keys(expected));
const props = {};
if (negative) {
for (const key of keys) {
if (actual[key] !== void 0 || key in actual) {
props[key] = { diff: true, extra: actual[key] };
}
}
} else {
for (const key of keys) {
const act = actual[key];
const exp = expected[key];
const result = diff(act, exp);
if (!result.diff) continue;
if (act === void 0 && !(key in actual)) {
props[key] = { diff: true, missing: exp };
} else {
props[key] = result;
}
}
}
const count = Object.keys(props).length;
if (count === 0) return;
const type = $plur(count, "property", "properties", false);
const not = negative ? "not " : "";
throw new ExpectationError(expectations, `${not}to include ${type}`, {
diff: true,
value: actual,
props
});
}
function includesValues(expectations, negative, expected) {
expectations.toBeInstanceOf(Object);
if (typeof expectations.value[Symbol.iterator] !== "function") {
throw new ExpectationError(expectations, "to be an iterable object");
}
const actual = new Set(expectations.value);
const values = [];
if (negative) {
for (const exp of expected) {
for (const act of actual) {
const result = diff(act, exp);
if (result.diff) continue;
values.push({ diff: true, extra: act });
break;
}
}
} else {
for (const exp of expected) {
let found = false;
for (const act of actual) {
const result = diff(act, exp);
if (result.diff) continue;
found = true;
break;
}
if (!found) {
values.push({ diff: true, missing: exp });
}
}
}
const count = values.length;
if (count === 0) return;
const type = $plur(count, "value", "values", false);
const not = negative ? "not " : "";
throw new ExpectationError(expectations, `${not}to include ${type}`, {
diff: true,
value: expectations.value,
values
});
}
function includesMappings(expectations, negative, expected) {
const actual = expectations.toBeInstanceOf(Map).value;
const keys = new Set(expected.keys());
const mappings = [];
if (negative) {
for (const key of keys) {
if (actual.has(key)) {
mappings.push([key, { diff: true, extra: actual.get(key) }]);
}
}
} else {
for (const key of keys) {
if (!actual.has(key)) {
mappings.push([key, { diff: true, missing: expected.get(key) }]);
} else {
const result = diff(actual.get(key), expected.get(key));
if (result.diff) mappings.push([key, result]);
}
}
}
const count = mappings.length;
if (count === 0) return;
const type = $plur(count, "mapping", "mappings", false);
const not = negative ? "not " : "";
throw new ExpectationError(expectations, `${not}to include ${type}`, {
diff: true,
value: expectations.value,
mappings
});
}
export {
toInclude,
toMatchContents
};
//# sourceMappingURL=include.mjs.map