Spaces:
Paused
Paused
| /** | |
| * Assert extensions | |
| * | |
| * WARNING: These extensions are added directly to Node's `assert.strict`, | |
| * modifying built-ins. We don't personally consider this a problem because | |
| * it only happens in tests, but you should be aware in case you care. | |
| * | |
| * by Slayer95 and Zarel | |
| */ | |
| ; | |
| const legacyAssert = require('assert'); | |
| const assert = legacyAssert.strict; | |
| const AssertionError = assert.AssertionError; | |
| assert.bounded = function (value, range, message) { | |
| if (value >= range[0] && value <= range[1]) return; | |
| throw new AssertionError({ | |
| actual: value, | |
| expected: `[${range[0]}, ${range[1]}]`, | |
| operator: '\u2208', | |
| message, | |
| stackStartFunction: assert.bounded, | |
| }); | |
| }; | |
| assert.atLeast = function (value, threshold, message) { | |
| if (value >= threshold) return; | |
| throw new AssertionError({ | |
| actual: value, | |
| expected: `${threshold}`, | |
| operator: '>=', | |
| message, | |
| stackStartFunction: assert.atLeast, | |
| }); | |
| }; | |
| assert.atMost = function (value, threshold, message) { | |
| if (value <= threshold) return; | |
| throw new AssertionError({ | |
| actual: value, | |
| expected: `${threshold}`, | |
| operator: '<=', | |
| message, | |
| stackStartFunction: assert.atMost, | |
| }); | |
| }; | |
| assert.legalTeam = function (team, format, message) { | |
| const actual = require('../dist/sim/team-validator').TeamValidator.get(format).validateTeam(team); | |
| if (actual === null) return; | |
| throw new AssertionError({ | |
| message: message || "Expected team to be valid, but it was rejected because:\n" + actual.join("\n"), | |
| stackStartFunction: assert.legalTeam, | |
| }); | |
| }; | |
| assert.species = function (pokemon, species, message) { | |
| const actual = pokemon.species.name; | |
| if (actual === species) return; | |
| throw new AssertionError({ | |
| message: message || `Expected ${pokemon} species to be ${species}, not ${actual}.`, | |
| stackStartFunction: assert.species, | |
| }); | |
| }; | |
| assert.fainted = function (pokemon, message) { | |
| if (!pokemon.hp) return; | |
| throw new AssertionError({ | |
| message: message || `Expected ${pokemon} to be fainted.`, | |
| stackStartFunction: assert.fainted, | |
| }); | |
| }; | |
| assert.fullHP = function (pokemon, message) { | |
| if (pokemon.hp === pokemon.maxhp) return; | |
| throw new AssertionError({ | |
| message: message || `Expected ${pokemon} to be fully healed, not at ${pokemon.hp}/${pokemon.maxhp}.`, | |
| stackStartFunction: assert.fullHP, | |
| }); | |
| }; | |
| assert.hasAbility = function (pokemon, ability, message) { | |
| const actual = pokemon.ability; | |
| const expected = toID(ability); | |
| if (actual === expected) return; | |
| throw new AssertionError({ | |
| message: message || `Expected ${pokemon} ability to be ${expected}, not ${actual}.`, | |
| stackStartFunction: assert.hasAbility, | |
| }); | |
| }; | |
| assert.holdsItem = function (pokemon, message) { | |
| if (pokemon.item) return; | |
| throw new AssertionError({ | |
| message: message || `Expected ${pokemon} to hold an item`, | |
| stackStartFunction: assert.holdsItem, | |
| }); | |
| }; | |
| assert.trapped = function (fn, unavailable, message) { | |
| assert.throws( | |
| fn, | |
| new RegExp(`\\[${unavailable ? 'Unavailable' : 'Invalid'} choice\\] Can't switch: The active Pokémon is trapped`), | |
| message || 'Expected active Pokemon to be trapped.' | |
| ); | |
| }; | |
| assert.cantMove = function (fn, pokemon, move, unavailable, message) { | |
| message = message ? `${message}; ` : ``; | |
| if (pokemon && move) { | |
| try { | |
| fn(); | |
| } catch (e) { | |
| const lcMessage = e.message.toLowerCase(); | |
| const choiceErrorTag = `[${unavailable ? 'Unavailable' : 'Invalid'} choice]`; | |
| assert(e.message.includes(choiceErrorTag), `${message}Error "${e.message}" should contain "${choiceErrorTag}"`); | |
| assert(lcMessage.includes(pokemon.toLowerCase()), `${message}Error "${e.message}" should contain "${pokemon}"`); | |
| assert(lcMessage.includes(move.toLowerCase()), `${message}Error "${e.message}" should contain "${move}"`); | |
| return; | |
| } | |
| } else { | |
| try { | |
| fn(); | |
| } catch { | |
| return; | |
| } | |
| } | |
| assert(false, `${message}${pokemon} should not be able to use ${move}.`); | |
| }; | |
| assert.cantUndo = function (fn, message) { | |
| assert.throws(fn, /\[Invalid choice\] Can't undo:/, message || 'Expected to be unable to undo choice.'); | |
| }; | |
| assert.cantTarget = function (fn, move, message) { | |
| assert.cantMove(fn, 'target', move, false, message || `Expected not to be able to choose a target for ${move}.`); | |
| }; | |
| assert.statStage = function (pokemon, statName, stage, message) { | |
| const actual = pokemon.boosts[statName]; | |
| if (actual === stage) return; | |
| throw new AssertionError({ | |
| message: message || `Expected ${pokemon}'s ${statName} at stage ${stage}, not at ${actual}.`, | |
| stackStartFunction: assert.statStage, | |
| }); | |
| }; | |
| assert.hurts = function (pokemon, fn, message) { | |
| const prevHP = pokemon.hp; | |
| fn(); | |
| if (pokemon.hp < prevHP) return; | |
| throw new AssertionError({ | |
| actual: pokemon.hp, | |
| expected: `${prevHP}`, | |
| operator: '<', | |
| message: message || `Expected ${pokemon} to be hurt.`, | |
| stackStartFunction: assert.hurts, | |
| }); | |
| }; | |
| assert.hurtsBy = function (pokemon, damage, fn, message) { | |
| // Support of healing effects is intentional. | |
| const prevHP = pokemon.hp; | |
| fn(); | |
| const actual = prevHP - pokemon.hp; | |
| if (actual === damage) return; | |
| throw new AssertionError({ | |
| actual, | |
| expected: damage, | |
| operator: '===', | |
| message: message || `Expected ${pokemon} to be hurt by ${damage}, not by ${actual}.`, | |
| stackStartFunction: assert.hurtsBy, | |
| }); | |
| }; | |
| assert.constant = function (getter, fn, message) { | |
| const initialValue = getter(); | |
| fn(); | |
| const finalValue = getter(); | |
| if (finalValue === initialValue) return; | |
| throw new AssertionError({ | |
| message: message || `Expected value to remain as ${initialValue}, not to change to ${finalValue}.`, | |
| stackStartFunction: assert.constant, | |
| }); | |
| }; | |
| assert.sets = function (getter, value, fn, message) { | |
| assert.notEqual(getter(), value, `Function was prematurely equal to ${value}.`); | |
| fn(); | |
| const finalValue = getter(); | |
| if (finalValue === value) return; | |
| throw new AssertionError({ | |
| actual: finalValue, | |
| expected: value, | |
| operator: '===', | |
| message, | |
| stackStartFunction: assert.sets, | |
| }); | |
| }; | |
| // .throws() does not currently work with Promises. | |
| assert.throwsAsync = async function (fn, message) { | |
| try { | |
| await fn(); | |
| } catch { | |
| return; // threw | |
| } | |
| throw new AssertionError({ | |
| message: message || `Expected function to throw an error.`, | |
| stackStartFunction: assert.throwsAsync, | |
| }); | |
| }; | |
| assert.doesNotThrowAsync = async function (fn, message) { | |
| try { | |
| await fn(); | |
| } catch (e) { | |
| throw new AssertionError({ | |
| message: message || `Expected function not to throw an error (threw ${e}).`, | |
| stackStartFunction: assert.doesNotThrowAsync, | |
| }); | |
| } | |
| }; | |
| assert.strictEqual = () => { | |
| throw new Error(`This API is deprecated; please use assert.equal()`); | |
| }; | |
| assert.deepStrictEqual = () => { | |
| throw new Error(`This API is deprecated; please use assert.deepEqual()`); | |
| }; | |
| assert.notStrictEqual = () => { | |
| throw new Error(`This API is deprecated; please use assert.notEqual()`); | |
| }; | |
| assert.notDeepStrictEqual = () => { | |
| throw new Error(`This API is deprecated; please use assert.notDeepEqual()`); | |
| }; | |
| assert.ok = () => { | |
| throw new Error(`This API is deprecated; please use assert()`); | |
| }; | |
| for (const fn in legacyAssert) { | |
| if (fn !== 'strict' && typeof legacyAssert[fn] === 'function') { | |
| legacyAssert[fn] = () => { | |
| throw new Error(`This API is deprecated; please use assert.strict`); | |
| }; | |
| } | |
| } | |
| const assertMethods = Object.getOwnPropertyNames(assert).filter(methodName => ( | |
| methodName !== 'constructor' && methodName !== 'AssertionError' && typeof assert[methodName] === 'function' | |
| )); | |
| assert.false = function (value, message) { | |
| if (!value) return; | |
| throw new AssertionError({ | |
| actual: `!${value}`, | |
| expected: true, | |
| operator: '===', | |
| message, | |
| stackStartFunction: assert.false, | |
| }); | |
| }; | |
| for (const methodName of assertMethods) { | |
| const lastArgIndex = assert[methodName].length - 1; | |
| assert.false[methodName] = function (...args) { | |
| try { | |
| assert[methodName].apply(null, args); | |
| } catch { | |
| return; | |
| } | |
| throw new AssertionError({ | |
| message: lastArgIndex < args.length ? args[lastArgIndex] : `Expected '${methodName}' assertion to fail.`, | |
| stackStartFunction: assert.false[methodName], | |
| }); | |
| }; | |
| } | |
| module.exports = assert; | |