1 | const { dequal } = require('dequal');
|
2 | const { compare, lines } = require('uvu/diff');
|
3 |
|
4 | function dedent(str) {
|
5 | str = str.replace(/\r?\n/g, '\n');
|
6 | let arr = str.match(/^[ \t]*(?=\S)/gm);
|
7 | let i = 0, min = 1/0, len = (arr||[]).length;
|
8 | for (; i < len; i++) min = Math.min(min, arr[i].length);
|
9 | return len && min ? str.replace(new RegExp(`^[ \\t]{${min}}`, 'gm'), '') : str;
|
10 | }
|
11 |
|
12 | class Assertion extends Error {
|
13 | constructor(opts={}) {
|
14 | super(opts.message);
|
15 | this.name = 'Assertion';
|
16 | this.code = 'ERR_ASSERTION';
|
17 | if (Error.captureStackTrace) {
|
18 | Error.captureStackTrace(this, this.constructor);
|
19 | }
|
20 | this.details = opts.details || false;
|
21 | this.generated = !!opts.generated;
|
22 | this.operator = opts.operator;
|
23 | this.expects = opts.expects;
|
24 | this.actual = opts.actual;
|
25 | }
|
26 | }
|
27 |
|
28 | function assert(bool, actual, expects, operator, detailer, backup, msg) {
|
29 | if (bool) return;
|
30 | let message = msg || backup;
|
31 | if (msg instanceof Error) throw msg;
|
32 | let details = detailer && detailer(actual, expects);
|
33 | throw new Assertion({ actual, expects, operator, message, details, generated: !msg });
|
34 | }
|
35 |
|
36 | function ok(val, msg) {
|
37 | assert(!!val, false, true, 'ok', false, 'Expected value to be truthy', msg);
|
38 | }
|
39 |
|
40 | function is(val, exp, msg) {
|
41 | assert(val === exp, val, exp, 'is', compare, 'Expected values to be strictly equal:', msg);
|
42 | }
|
43 |
|
44 | function equal(val, exp, msg) {
|
45 | assert(dequal(val, exp), val, exp, 'equal', compare, 'Expected values to be deeply equal:', msg);
|
46 | }
|
47 |
|
48 | function unreachable(msg) {
|
49 | assert(false, true, false, 'unreachable', false, 'Expected not to be reached!', msg);
|
50 | }
|
51 |
|
52 | function type(val, exp, msg) {
|
53 | let tmp = typeof val;
|
54 | assert(tmp === exp, tmp, exp, 'type', false, `Expected "${tmp}" to be "${exp}"`, msg);
|
55 | }
|
56 |
|
57 | function instance(val, exp, msg) {
|
58 | let name = '`' + (exp.name || exp.constructor.name) + '`';
|
59 | assert(val instanceof exp, val, exp, 'instance', false, `Expected value to be an instance of ${name}`, msg);
|
60 | }
|
61 |
|
62 | function match(val, exp, msg) {
|
63 | if (typeof exp === 'string') {
|
64 | assert(val.includes(exp), val, exp, 'match', false, `Expected value to include "${exp}" substring`, msg);
|
65 | } else {
|
66 | assert(exp.test(val), val, exp, 'match', false, `Expected value to match \`${String(exp)}\` pattern`, msg);
|
67 | }
|
68 | }
|
69 |
|
70 | function snapshot(val, exp, msg) {
|
71 | val=dedent(val); exp=dedent(exp);
|
72 | assert(val === exp, val, exp, 'snapshot', lines, 'Expected value to match snapshot:', msg);
|
73 | }
|
74 |
|
75 | const lineNums = (x, y) => lines(x, y, 1);
|
76 | function fixture(val, exp, msg) {
|
77 | val=dedent(val); exp=dedent(exp);
|
78 | assert(val === exp, val, exp, 'fixture', lineNums, 'Expected value to match fixture:', msg);
|
79 | }
|
80 |
|
81 | function throws(blk, exp, msg) {
|
82 | if (!msg && typeof exp === 'string') {
|
83 | msg = exp; exp = null;
|
84 | }
|
85 |
|
86 | try {
|
87 | blk();
|
88 | assert(false, false, true, 'throws', false, 'Expected function to throw', msg);
|
89 | } catch (err) {
|
90 | if (err instanceof Assertion) throw err;
|
91 |
|
92 | if (typeof exp === 'function') {
|
93 | assert(exp(err), false, true, 'throws', false, 'Expected function to throw matching exception', msg);
|
94 | } else if (exp instanceof RegExp) {
|
95 | assert(exp.test(err.message), false, true, 'throws', false, `Expected function to throw exception matching \`${String(exp)}\` pattern`, msg);
|
96 | }
|
97 | }
|
98 | }
|
99 |
|
100 |
|
101 |
|
102 | function not(val, msg) {
|
103 | assert(!val, true, false, 'not', false, 'Expected value to be falsey', msg);
|
104 | }
|
105 |
|
106 | not.ok = not;
|
107 |
|
108 | is.not = function (val, exp, msg) {
|
109 | assert(val !== exp, val, exp, 'is.not', false, 'Expected values not to be strictly equal', msg);
|
110 | }
|
111 |
|
112 | not.equal = function (val, exp, msg) {
|
113 | assert(!dequal(val, exp), val, exp, 'not.equal', false, 'Expected values not to be deeply equal', msg);
|
114 | }
|
115 |
|
116 | not.type = function (val, exp, msg) {
|
117 | let tmp = typeof val;
|
118 | assert(tmp !== exp, tmp, exp, 'not.type', false, `Expected "${tmp}" not to be "${exp}"`, msg);
|
119 | }
|
120 |
|
121 | not.instance = function (val, exp, msg) {
|
122 | let name = '`' + (exp.name || exp.constructor.name) + '`';
|
123 | assert(!(val instanceof exp), val, exp, 'not.instance', false, `Expected value not to be an instance of ${name}`, msg);
|
124 | }
|
125 |
|
126 | not.snapshot = function (val, exp, msg) {
|
127 | val=dedent(val); exp=dedent(exp);
|
128 | assert(val !== exp, val, exp, 'not.snapshot', false, 'Expected value not to match snapshot', msg);
|
129 | }
|
130 |
|
131 | not.fixture = function (val, exp, msg) {
|
132 | val=dedent(val); exp=dedent(exp);
|
133 | assert(val !== exp, val, exp, 'not.fixture', false, 'Expected value not to match fixture', msg);
|
134 | }
|
135 |
|
136 | not.match = function (val, exp, msg) {
|
137 | if (typeof exp === 'string') {
|
138 | assert(!val.includes(exp), val, exp, 'not.match', false, `Expected value not to include "${exp}" substring`, msg);
|
139 | } else {
|
140 | assert(!exp.test(val), val, exp, 'not.match', false, `Expected value not to match \`${String(exp)}\` pattern`, msg);
|
141 | }
|
142 | }
|
143 |
|
144 | not.throws = function (blk, exp, msg) {
|
145 | if (!msg && typeof exp === 'string') {
|
146 | msg = exp; exp = null;
|
147 | }
|
148 |
|
149 | try {
|
150 | blk();
|
151 | } catch (err) {
|
152 | if (typeof exp === 'function') {
|
153 | assert(!exp(err), true, false, 'not.throws', false, 'Expected function not to throw matching exception', msg);
|
154 | } else if (exp instanceof RegExp) {
|
155 | assert(!exp.test(err.message), true, false, 'not.throws', false, `Expected function not to throw exception matching \`${String(exp)}\` pattern`, msg);
|
156 | } else if (!exp) {
|
157 | assert(false, true, false, 'not.throws', false, 'Expected function not to throw', msg);
|
158 | }
|
159 | }
|
160 | }
|
161 |
|
162 | exports.Assertion = Assertion;
|
163 | exports.equal = equal;
|
164 | exports.fixture = fixture;
|
165 | exports.instance = instance;
|
166 | exports.is = is;
|
167 | exports.match = match;
|
168 | exports.not = not;
|
169 | exports.ok = ok;
|
170 | exports.snapshot = snapshot;
|
171 | exports.throws = throws;
|
172 | exports.type = type;
|
173 | exports.unreachable = unreachable; |
\ | No newline at end of file |