deno_asserts@0.168.0.mjs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. // deno-fmt-ignore-file
  2. // deno-lint-ignore-file
  3. // This code was bundled using `deno bundle` and it's not recommended to edit it manually
  4. // Using `deno bundle https://deno.land/std@0.168.0/testing/asserts.ts > npm/deno_asserts@0.168.0.mjs`
  5. const { Deno } = globalThis;
  6. const noColor = typeof Deno?.noColor === "boolean" ? Deno.noColor : true;
  7. let enabled = !noColor;
  8. function code(open, close) {
  9. return {
  10. open: `\x1b[${open.join(";")}m`,
  11. close: `\x1b[${close}m`,
  12. regexp: new RegExp(`\\x1b\\[${close}m`, "g")
  13. };
  14. }
  15. function run(str, code) {
  16. return enabled ? `${code.open}${str.replace(code.regexp, code.open)}${code.close}` : str;
  17. }
  18. function bold(str) {
  19. return run(str, code([
  20. 1
  21. ], 22));
  22. }
  23. function red(str) {
  24. return run(str, code([
  25. 31
  26. ], 39));
  27. }
  28. function green(str) {
  29. return run(str, code([
  30. 32
  31. ], 39));
  32. }
  33. function white(str) {
  34. return run(str, code([
  35. 37
  36. ], 39));
  37. }
  38. function gray(str) {
  39. return brightBlack(str);
  40. }
  41. function brightBlack(str) {
  42. return run(str, code([
  43. 90
  44. ], 39));
  45. }
  46. function bgRed(str) {
  47. return run(str, code([
  48. 41
  49. ], 49));
  50. }
  51. function bgGreen(str) {
  52. return run(str, code([
  53. 42
  54. ], 49));
  55. }
  56. const ANSI_PATTERN = new RegExp([
  57. "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
  58. "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"
  59. ].join("|"), "g");
  60. function stripColor(string) {
  61. return string.replace(ANSI_PATTERN, "");
  62. }
  63. var DiffType;
  64. (function(DiffType) {
  65. DiffType["removed"] = "removed";
  66. DiffType["common"] = "common";
  67. DiffType["added"] = "added";
  68. })(DiffType || (DiffType = {}));
  69. const REMOVED = 1;
  70. const COMMON = 2;
  71. const ADDED = 3;
  72. function createCommon(A, B, reverse) {
  73. const common = [];
  74. if (A.length === 0 || B.length === 0) return [];
  75. for(let i = 0; i < Math.min(A.length, B.length); i += 1){
  76. if (A[reverse ? A.length - i - 1 : i] === B[reverse ? B.length - i - 1 : i]) {
  77. common.push(A[reverse ? A.length - i - 1 : i]);
  78. } else {
  79. return common;
  80. }
  81. }
  82. return common;
  83. }
  84. function diff(A, B) {
  85. const prefixCommon = createCommon(A, B);
  86. const suffixCommon = createCommon(A.slice(prefixCommon.length), B.slice(prefixCommon.length), true).reverse();
  87. A = suffixCommon.length ? A.slice(prefixCommon.length, -suffixCommon.length) : A.slice(prefixCommon.length);
  88. B = suffixCommon.length ? B.slice(prefixCommon.length, -suffixCommon.length) : B.slice(prefixCommon.length);
  89. const swapped = B.length > A.length;
  90. [A, B] = swapped ? [
  91. B,
  92. A
  93. ] : [
  94. A,
  95. B
  96. ];
  97. const M = A.length;
  98. const N = B.length;
  99. if (!M && !N && !suffixCommon.length && !prefixCommon.length) return [];
  100. if (!N) {
  101. return [
  102. ...prefixCommon.map((c)=>({
  103. type: DiffType.common,
  104. value: c
  105. })),
  106. ...A.map((a)=>({
  107. type: swapped ? DiffType.added : DiffType.removed,
  108. value: a
  109. })),
  110. ...suffixCommon.map((c)=>({
  111. type: DiffType.common,
  112. value: c
  113. }))
  114. ];
  115. }
  116. const offset = N;
  117. const delta = M - N;
  118. const size = M + N + 1;
  119. const fp = Array.from({
  120. length: size
  121. }, ()=>({
  122. y: -1,
  123. id: -1
  124. }));
  125. const routes = new Uint32Array((M * N + size + 1) * 2);
  126. const diffTypesPtrOffset = routes.length / 2;
  127. let ptr = 0;
  128. let p = -1;
  129. function backTrace(A, B, current, swapped) {
  130. const M = A.length;
  131. const N = B.length;
  132. const result = [];
  133. let a = M - 1;
  134. let b = N - 1;
  135. let j = routes[current.id];
  136. let type = routes[current.id + diffTypesPtrOffset];
  137. while(true){
  138. if (!j && !type) break;
  139. const prev = j;
  140. if (type === 1) {
  141. result.unshift({
  142. type: swapped ? DiffType.removed : DiffType.added,
  143. value: B[b]
  144. });
  145. b -= 1;
  146. } else if (type === 3) {
  147. result.unshift({
  148. type: swapped ? DiffType.added : DiffType.removed,
  149. value: A[a]
  150. });
  151. a -= 1;
  152. } else {
  153. result.unshift({
  154. type: DiffType.common,
  155. value: A[a]
  156. });
  157. a -= 1;
  158. b -= 1;
  159. }
  160. j = routes[prev];
  161. type = routes[prev + diffTypesPtrOffset];
  162. }
  163. return result;
  164. }
  165. function createFP(slide, down, k, M) {
  166. if (slide && slide.y === -1 && down && down.y === -1) {
  167. return {
  168. y: 0,
  169. id: 0
  170. };
  171. }
  172. if (down && down.y === -1 || k === M || (slide && slide.y) > (down && down.y) + 1) {
  173. const prev = slide.id;
  174. ptr++;
  175. routes[ptr] = prev;
  176. routes[ptr + diffTypesPtrOffset] = ADDED;
  177. return {
  178. y: slide.y,
  179. id: ptr
  180. };
  181. } else {
  182. const prev1 = down.id;
  183. ptr++;
  184. routes[ptr] = prev1;
  185. routes[ptr + diffTypesPtrOffset] = REMOVED;
  186. return {
  187. y: down.y + 1,
  188. id: ptr
  189. };
  190. }
  191. }
  192. function snake(k, slide, down, _offset, A, B) {
  193. const M = A.length;
  194. const N = B.length;
  195. if (k < -N || M < k) return {
  196. y: -1,
  197. id: -1
  198. };
  199. const fp = createFP(slide, down, k, M);
  200. while(fp.y + k < M && fp.y < N && A[fp.y + k] === B[fp.y]){
  201. const prev = fp.id;
  202. ptr++;
  203. fp.id = ptr;
  204. fp.y += 1;
  205. routes[ptr] = prev;
  206. routes[ptr + diffTypesPtrOffset] = COMMON;
  207. }
  208. return fp;
  209. }
  210. while(fp[delta + offset].y < N){
  211. p = p + 1;
  212. for(let k = -p; k < delta; ++k){
  213. fp[k + offset] = snake(k, fp[k - 1 + offset], fp[k + 1 + offset], offset, A, B);
  214. }
  215. for(let k1 = delta + p; k1 > delta; --k1){
  216. fp[k1 + offset] = snake(k1, fp[k1 - 1 + offset], fp[k1 + 1 + offset], offset, A, B);
  217. }
  218. fp[delta + offset] = snake(delta, fp[delta - 1 + offset], fp[delta + 1 + offset], offset, A, B);
  219. }
  220. return [
  221. ...prefixCommon.map((c)=>({
  222. type: DiffType.common,
  223. value: c
  224. })),
  225. ...backTrace(A, B, fp[delta + offset], swapped),
  226. ...suffixCommon.map((c)=>({
  227. type: DiffType.common,
  228. value: c
  229. }))
  230. ];
  231. }
  232. function diffstr(A, B) {
  233. function unescape(string) {
  234. return string.replaceAll("\b", "\\b").replaceAll("\f", "\\f").replaceAll("\t", "\\t").replaceAll("\v", "\\v").replaceAll(/\r\n|\r|\n/g, (str)=>str === "\r" ? "\\r" : str === "\n" ? "\\n\n" : "\\r\\n\r\n");
  235. }
  236. function tokenize(string, { wordDiff =false } = {}) {
  237. if (wordDiff) {
  238. const tokens = string.split(/([^\S\r\n]+|[()[\]{}'"\r\n]|\b)/);
  239. const words = /^[a-zA-Z\u{C0}-\u{FF}\u{D8}-\u{F6}\u{F8}-\u{2C6}\u{2C8}-\u{2D7}\u{2DE}-\u{2FF}\u{1E00}-\u{1EFF}]+$/u;
  240. for(let i = 0; i < tokens.length - 1; i++){
  241. if (!tokens[i + 1] && tokens[i + 2] && words.test(tokens[i]) && words.test(tokens[i + 2])) {
  242. tokens[i] += tokens[i + 2];
  243. tokens.splice(i + 1, 2);
  244. i--;
  245. }
  246. }
  247. return tokens.filter((token)=>token);
  248. } else {
  249. const tokens1 = [], lines = string.split(/(\n|\r\n)/);
  250. if (!lines[lines.length - 1]) {
  251. lines.pop();
  252. }
  253. for(let i1 = 0; i1 < lines.length; i1++){
  254. if (i1 % 2) {
  255. tokens1[tokens1.length - 1] += lines[i1];
  256. } else {
  257. tokens1.push(lines[i1]);
  258. }
  259. }
  260. return tokens1;
  261. }
  262. }
  263. function createDetails(line, tokens) {
  264. return tokens.filter(({ type })=>type === line.type || type === DiffType.common).map((result, i, t)=>{
  265. if (result.type === DiffType.common && t[i - 1] && t[i - 1]?.type === t[i + 1]?.type && /\s+/.test(result.value)) {
  266. result.type = t[i - 1].type;
  267. }
  268. return result;
  269. });
  270. }
  271. const diffResult = diff(tokenize(`${unescape(A)}\n`), tokenize(`${unescape(B)}\n`));
  272. const added = [], removed = [];
  273. for (const result of diffResult){
  274. if (result.type === DiffType.added) {
  275. added.push(result);
  276. }
  277. if (result.type === DiffType.removed) {
  278. removed.push(result);
  279. }
  280. }
  281. const aLines = added.length < removed.length ? added : removed;
  282. const bLines = aLines === removed ? added : removed;
  283. for (const a of aLines){
  284. let tokens = [], b;
  285. while(bLines.length){
  286. b = bLines.shift();
  287. tokens = diff(tokenize(a.value, {
  288. wordDiff: true
  289. }), tokenize(b?.value ?? "", {
  290. wordDiff: true
  291. }));
  292. if (tokens.some(({ type , value })=>type === DiffType.common && value.trim().length)) {
  293. break;
  294. }
  295. }
  296. a.details = createDetails(a, tokens);
  297. if (b) {
  298. b.details = createDetails(b, tokens);
  299. }
  300. }
  301. return diffResult;
  302. }
  303. function createColor(diffType, { background =false } = {}) {
  304. background = false;
  305. switch(diffType){
  306. case DiffType.added:
  307. return (s)=>background ? bgGreen(white(s)) : green(bold(s));
  308. case DiffType.removed:
  309. return (s)=>background ? bgRed(white(s)) : red(bold(s));
  310. default:
  311. return white;
  312. }
  313. }
  314. function createSign(diffType) {
  315. switch(diffType){
  316. case DiffType.added:
  317. return "+ ";
  318. case DiffType.removed:
  319. return "- ";
  320. default:
  321. return " ";
  322. }
  323. }
  324. function buildMessage(diffResult, { stringDiff =false } = {}) {
  325. const messages = [], diffMessages = [];
  326. messages.push("");
  327. messages.push("");
  328. messages.push(` ${gray(bold("[Diff]"))} ${red(bold("Actual"))} / ${green(bold("Expected"))}`);
  329. messages.push("");
  330. messages.push("");
  331. diffResult.forEach((result)=>{
  332. const c = createColor(result.type);
  333. const line = result.details?.map((detail)=>detail.type !== DiffType.common ? createColor(detail.type, {
  334. background: true
  335. })(detail.value) : detail.value).join("") ?? result.value;
  336. diffMessages.push(c(`${createSign(result.type)}${line}`));
  337. });
  338. messages.push(...stringDiff ? [
  339. diffMessages.join("")
  340. ] : diffMessages);
  341. messages.push("");
  342. return messages;
  343. }
  344. function format(v) {
  345. const { Deno } = globalThis;
  346. return typeof Deno?.inspect === "function" ? Deno.inspect(v, {
  347. depth: Infinity,
  348. sorted: true,
  349. trailingComma: true,
  350. compact: false,
  351. iterableLimit: Infinity,
  352. getters: true
  353. }) : `"${String(v).replace(/(?=["\\])/g, "\\")}"`;
  354. }
  355. const CAN_NOT_DISPLAY = "[Cannot display]";
  356. class AssertionError extends Error {
  357. name = "AssertionError";
  358. constructor(message){
  359. super(message);
  360. }
  361. }
  362. function isKeyedCollection(x) {
  363. return [
  364. Symbol.iterator,
  365. "size"
  366. ].every((k)=>k in x);
  367. }
  368. function equal(c, d) {
  369. const seen = new Map();
  370. return function compare(a, b) {
  371. if (a && b && (a instanceof RegExp && b instanceof RegExp || a instanceof URL && b instanceof URL)) {
  372. return String(a) === String(b);
  373. }
  374. if (a instanceof Date && b instanceof Date) {
  375. const aTime = a.getTime();
  376. const bTime = b.getTime();
  377. if (Number.isNaN(aTime) && Number.isNaN(bTime)) {
  378. return true;
  379. }
  380. return aTime === bTime;
  381. }
  382. if (typeof a === "number" && typeof b === "number") {
  383. return Number.isNaN(a) && Number.isNaN(b) || a === b;
  384. }
  385. if (Object.is(a, b)) {
  386. return true;
  387. }
  388. if (a && typeof a === "object" && b && typeof b === "object") {
  389. if (a && b && !constructorsEqual(a, b)) {
  390. return false;
  391. }
  392. if (a instanceof WeakMap || b instanceof WeakMap) {
  393. if (!(a instanceof WeakMap && b instanceof WeakMap)) return false;
  394. throw new TypeError("cannot compare WeakMap instances");
  395. }
  396. if (a instanceof WeakSet || b instanceof WeakSet) {
  397. if (!(a instanceof WeakSet && b instanceof WeakSet)) return false;
  398. throw new TypeError("cannot compare WeakSet instances");
  399. }
  400. if (seen.get(a) === b) {
  401. return true;
  402. }
  403. if (Object.keys(a || {}).length !== Object.keys(b || {}).length) {
  404. return false;
  405. }
  406. seen.set(a, b);
  407. if (isKeyedCollection(a) && isKeyedCollection(b)) {
  408. if (a.size !== b.size) {
  409. return false;
  410. }
  411. let unmatchedEntries = a.size;
  412. for (const [aKey, aValue] of a.entries()){
  413. for (const [bKey, bValue] of b.entries()){
  414. if (aKey === aValue && bKey === bValue && compare(aKey, bKey) || compare(aKey, bKey) && compare(aValue, bValue)) {
  415. unmatchedEntries--;
  416. break;
  417. }
  418. }
  419. }
  420. return unmatchedEntries === 0;
  421. }
  422. const merged = {
  423. ...a,
  424. ...b
  425. };
  426. for (const key of [
  427. ...Object.getOwnPropertyNames(merged),
  428. ...Object.getOwnPropertySymbols(merged)
  429. ]){
  430. if (!compare(a && a[key], b && b[key])) {
  431. return false;
  432. }
  433. if (key in a && !(key in b) || key in b && !(key in a)) {
  434. return false;
  435. }
  436. }
  437. if (a instanceof WeakRef || b instanceof WeakRef) {
  438. if (!(a instanceof WeakRef && b instanceof WeakRef)) return false;
  439. return compare(a.deref(), b.deref());
  440. }
  441. return true;
  442. }
  443. return false;
  444. }(c, d);
  445. }
  446. function constructorsEqual(a, b) {
  447. return a.constructor === b.constructor || a.constructor === Object && !b.constructor || !a.constructor && b.constructor === Object;
  448. }
  449. function assert(expr, msg = "") {
  450. if (!expr) {
  451. throw new AssertionError(msg);
  452. }
  453. }
  454. function assertFalse(expr, msg = "") {
  455. if (expr) {
  456. throw new AssertionError(msg);
  457. }
  458. }
  459. function assertEquals(actual, expected, msg) {
  460. if (equal(actual, expected)) {
  461. return;
  462. }
  463. let message = "";
  464. const actualString = format(actual);
  465. const expectedString = format(expected);
  466. try {
  467. const stringDiff = typeof actual === "string" && typeof expected === "string";
  468. const diffResult = stringDiff ? diffstr(actual, expected) : diff(actualString.split("\n"), expectedString.split("\n"));
  469. const diffMsg = buildMessage(diffResult, {
  470. stringDiff
  471. }).join("\n");
  472. message = `Values are not equal:\n${diffMsg}`;
  473. } catch {
  474. message = `\n${red(CAN_NOT_DISPLAY)} + \n\n`;
  475. }
  476. if (msg) {
  477. message = msg;
  478. }
  479. throw new AssertionError(message);
  480. }
  481. function assertNotEquals(actual, expected, msg) {
  482. if (!equal(actual, expected)) {
  483. return;
  484. }
  485. let actualString;
  486. let expectedString;
  487. try {
  488. actualString = String(actual);
  489. } catch {
  490. actualString = "[Cannot display]";
  491. }
  492. try {
  493. expectedString = String(expected);
  494. } catch {
  495. expectedString = "[Cannot display]";
  496. }
  497. if (!msg) {
  498. msg = `actual: ${actualString} expected not to be: ${expectedString}`;
  499. }
  500. throw new AssertionError(msg);
  501. }
  502. function assertStrictEquals(actual, expected, msg) {
  503. if (Object.is(actual, expected)) {
  504. return;
  505. }
  506. let message;
  507. if (msg) {
  508. message = msg;
  509. } else {
  510. const actualString = format(actual);
  511. const expectedString = format(expected);
  512. if (actualString === expectedString) {
  513. const withOffset = actualString.split("\n").map((l)=>` ${l}`).join("\n");
  514. message = `Values have the same structure but are not reference-equal:\n\n${red(withOffset)}\n`;
  515. } else {
  516. try {
  517. const stringDiff = typeof actual === "string" && typeof expected === "string";
  518. const diffResult = stringDiff ? diffstr(actual, expected) : diff(actualString.split("\n"), expectedString.split("\n"));
  519. const diffMsg = buildMessage(diffResult, {
  520. stringDiff
  521. }).join("\n");
  522. message = `Values are not strictly equal:\n${diffMsg}`;
  523. } catch {
  524. message = `\n${red(CAN_NOT_DISPLAY)} + \n\n`;
  525. }
  526. }
  527. }
  528. throw new AssertionError(message);
  529. }
  530. function assertNotStrictEquals(actual, expected, msg) {
  531. if (!Object.is(actual, expected)) {
  532. return;
  533. }
  534. throw new AssertionError(msg ?? `Expected "actual" to be strictly unequal to: ${format(actual)}\n`);
  535. }
  536. function assertAlmostEquals(actual, expected, tolerance = 1e-7, msg) {
  537. if (Object.is(actual, expected)) {
  538. return;
  539. }
  540. const delta = Math.abs(expected - actual);
  541. if (delta <= tolerance) {
  542. return;
  543. }
  544. const f = (n)=>Number.isInteger(n) ? n : n.toExponential();
  545. throw new AssertionError(msg ?? `actual: "${f(actual)}" expected to be close to "${f(expected)}": \
  546. delta "${f(delta)}" is greater than "${f(tolerance)}"`);
  547. }
  548. function assertInstanceOf(actual, expectedType, msg = "") {
  549. if (!msg) {
  550. const expectedTypeStr = expectedType.name;
  551. let actualTypeStr = "";
  552. if (actual === null) {
  553. actualTypeStr = "null";
  554. } else if (actual === undefined) {
  555. actualTypeStr = "undefined";
  556. } else if (typeof actual === "object") {
  557. actualTypeStr = actual.constructor?.name ?? "Object";
  558. } else {
  559. actualTypeStr = typeof actual;
  560. }
  561. if (expectedTypeStr == actualTypeStr) {
  562. msg = `Expected object to be an instance of "${expectedTypeStr}".`;
  563. } else if (actualTypeStr == "function") {
  564. msg = `Expected object to be an instance of "${expectedTypeStr}" but was not an instanced object.`;
  565. } else {
  566. msg = `Expected object to be an instance of "${expectedTypeStr}" but was "${actualTypeStr}".`;
  567. }
  568. }
  569. assert(actual instanceof expectedType, msg);
  570. }
  571. function assertNotInstanceOf(actual, unexpectedType, msg = `Expected object to not be an instance of "${typeof unexpectedType}"`) {
  572. assertFalse(actual instanceof unexpectedType, msg);
  573. }
  574. function assertExists(actual, msg) {
  575. if (actual === undefined || actual === null) {
  576. if (!msg) {
  577. msg = `actual: "${actual}" expected to not be null or undefined`;
  578. }
  579. throw new AssertionError(msg);
  580. }
  581. }
  582. function assertStringIncludes(actual, expected, msg) {
  583. if (!actual.includes(expected)) {
  584. if (!msg) {
  585. msg = `actual: "${actual}" expected to contain: "${expected}"`;
  586. }
  587. throw new AssertionError(msg);
  588. }
  589. }
  590. function assertArrayIncludes(actual, expected, msg) {
  591. const missing = [];
  592. for(let i = 0; i < expected.length; i++){
  593. let found = false;
  594. for(let j = 0; j < actual.length; j++){
  595. if (equal(expected[i], actual[j])) {
  596. found = true;
  597. break;
  598. }
  599. }
  600. if (!found) {
  601. missing.push(expected[i]);
  602. }
  603. }
  604. if (missing.length === 0) {
  605. return;
  606. }
  607. if (!msg) {
  608. msg = `actual: "${format(actual)}" expected to include: "${format(expected)}"\nmissing: ${format(missing)}`;
  609. }
  610. throw new AssertionError(msg);
  611. }
  612. function assertMatch(actual, expected, msg) {
  613. if (!expected.test(actual)) {
  614. if (!msg) {
  615. msg = `actual: "${actual}" expected to match: "${expected}"`;
  616. }
  617. throw new AssertionError(msg);
  618. }
  619. }
  620. function assertNotMatch(actual, expected, msg) {
  621. if (expected.test(actual)) {
  622. if (!msg) {
  623. msg = `actual: "${actual}" expected to not match: "${expected}"`;
  624. }
  625. throw new AssertionError(msg);
  626. }
  627. }
  628. function assertObjectMatch(actual, expected) {
  629. function filter(a, b) {
  630. const seen = new WeakMap();
  631. return fn(a, b);
  632. function fn(a, b) {
  633. if (seen.has(a) && seen.get(a) === b) {
  634. return a;
  635. }
  636. seen.set(a, b);
  637. const filtered = {};
  638. const entries = [
  639. ...Object.getOwnPropertyNames(a),
  640. ...Object.getOwnPropertySymbols(a)
  641. ].filter((key)=>key in b).map((key)=>[
  642. key,
  643. a[key]
  644. ]);
  645. for (const [key, value] of entries){
  646. if (Array.isArray(value)) {
  647. const subset = b[key];
  648. if (Array.isArray(subset)) {
  649. filtered[key] = fn({
  650. ...value
  651. }, {
  652. ...subset
  653. });
  654. continue;
  655. }
  656. } else if (value instanceof RegExp) {
  657. filtered[key] = value;
  658. continue;
  659. } else if (typeof value === "object") {
  660. const subset1 = b[key];
  661. if (typeof subset1 === "object" && subset1) {
  662. if (value instanceof Map && subset1 instanceof Map) {
  663. filtered[key] = new Map([
  664. ...value
  665. ].filter(([k])=>subset1.has(k)).map(([k, v])=>[
  666. k,
  667. typeof v === "object" ? fn(v, subset1.get(k)) : v
  668. ]));
  669. continue;
  670. }
  671. if (value instanceof Set && subset1 instanceof Set) {
  672. filtered[key] = new Set([
  673. ...value
  674. ].filter((v)=>subset1.has(v)));
  675. continue;
  676. }
  677. filtered[key] = fn(value, subset1);
  678. continue;
  679. }
  680. }
  681. filtered[key] = value;
  682. }
  683. return filtered;
  684. }
  685. }
  686. return assertEquals(filter(actual, expected), filter(expected, expected));
  687. }
  688. function fail(msg) {
  689. assert(false, `Failed assertion${msg ? `: ${msg}` : "."}`);
  690. }
  691. function assertIsError(error, ErrorClass, msgIncludes, msg) {
  692. if (error instanceof Error === false) {
  693. throw new AssertionError(`Expected "error" to be an Error object.`);
  694. }
  695. if (ErrorClass && !(error instanceof ErrorClass)) {
  696. msg = `Expected error to be instance of "${ErrorClass.name}", but was "${typeof error === "object" ? error?.constructor?.name : "[not an object]"}"${msg ? `: ${msg}` : "."}`;
  697. throw new AssertionError(msg);
  698. }
  699. if (msgIncludes && (!(error instanceof Error) || !stripColor(error.message).includes(stripColor(msgIncludes)))) {
  700. msg = `Expected error message to include "${msgIncludes}", but got "${error instanceof Error ? error.message : "[not an Error]"}"${msg ? `: ${msg}` : "."}`;
  701. throw new AssertionError(msg);
  702. }
  703. }
  704. function assertThrows(fn, errorClassOrMsg, msgIncludesOrMsg, msg) {
  705. let ErrorClass = undefined;
  706. let msgIncludes = undefined;
  707. let err;
  708. if (typeof errorClassOrMsg !== "string") {
  709. if (errorClassOrMsg === undefined || errorClassOrMsg.prototype instanceof Error || errorClassOrMsg.prototype === Error.prototype) {
  710. ErrorClass = errorClassOrMsg;
  711. msgIncludes = msgIncludesOrMsg;
  712. } else {
  713. msg = msgIncludesOrMsg;
  714. }
  715. } else {
  716. msg = errorClassOrMsg;
  717. }
  718. let doesThrow = false;
  719. const msgToAppendToError = msg ? `: ${msg}` : ".";
  720. try {
  721. fn();
  722. } catch (error) {
  723. if (ErrorClass) {
  724. if (error instanceof Error === false) {
  725. throw new AssertionError("A non-Error object was thrown.");
  726. }
  727. assertIsError(error, ErrorClass, msgIncludes, msg);
  728. }
  729. err = error;
  730. doesThrow = true;
  731. }
  732. if (!doesThrow) {
  733. msg = `Expected function to throw${msgToAppendToError}`;
  734. throw new AssertionError(msg);
  735. }
  736. return err;
  737. }
  738. async function assertRejects(fn, errorClassOrMsg, msgIncludesOrMsg, msg) {
  739. let ErrorClass = undefined;
  740. let msgIncludes = undefined;
  741. let err;
  742. if (typeof errorClassOrMsg !== "string") {
  743. if (errorClassOrMsg === undefined || errorClassOrMsg.prototype instanceof Error || errorClassOrMsg.prototype === Error.prototype) {
  744. ErrorClass = errorClassOrMsg;
  745. msgIncludes = msgIncludesOrMsg;
  746. }
  747. } else {
  748. msg = errorClassOrMsg;
  749. }
  750. let doesThrow = false;
  751. let isPromiseReturned = false;
  752. const msgToAppendToError = msg ? `: ${msg}` : ".";
  753. try {
  754. const possiblePromise = fn();
  755. if (possiblePromise && typeof possiblePromise === "object" && typeof possiblePromise.then === "function") {
  756. isPromiseReturned = true;
  757. await possiblePromise;
  758. }
  759. } catch (error) {
  760. if (!isPromiseReturned) {
  761. throw new AssertionError(`Function throws when expected to reject${msgToAppendToError}`);
  762. }
  763. if (ErrorClass) {
  764. if (error instanceof Error === false) {
  765. throw new AssertionError("A non-Error object was rejected.");
  766. }
  767. assertIsError(error, ErrorClass, msgIncludes, msg);
  768. }
  769. err = error;
  770. doesThrow = true;
  771. }
  772. if (!doesThrow) {
  773. throw new AssertionError(`Expected function to reject${msgToAppendToError}`);
  774. }
  775. return err;
  776. }
  777. function unimplemented(msg) {
  778. throw new AssertionError(msg || "unimplemented");
  779. }
  780. function unreachable() {
  781. throw new AssertionError("unreachable");
  782. }
  783. export { AssertionError as AssertionError };
  784. export { equal as equal };
  785. export { assert as assert };
  786. export { assertFalse as assertFalse };
  787. export { assertEquals as assertEquals };
  788. export { assertNotEquals as assertNotEquals };
  789. export { assertStrictEquals as assertStrictEquals };
  790. export { assertNotStrictEquals as assertNotStrictEquals };
  791. export { assertAlmostEquals as assertAlmostEquals };
  792. export { assertInstanceOf as assertInstanceOf };
  793. export { assertNotInstanceOf as assertNotInstanceOf };
  794. export { assertExists as assertExists };
  795. export { assertStringIncludes as assertStringIncludes };
  796. export { assertArrayIncludes as assertArrayIncludes };
  797. export { assertMatch as assertMatch };
  798. export { assertNotMatch as assertNotMatch };
  799. export { assertObjectMatch as assertObjectMatch };
  800. export { fail as fail };
  801. export { assertIsError as assertIsError };
  802. export { assertThrows as assertThrows };
  803. export { assertRejects as assertRejects };
  804. export { unimplemented as unimplemented };
  805. export { unreachable as unreachable };