aboutsummaryrefslogtreecommitdiff
path: root/tests/unit/utils/assert.test.ts
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-04-22 06:51:57 +0530
committerBobby <[email protected]>2026-04-22 06:51:57 +0530
commit4dfbf7a13120b3b64521fce6de7d5d3f76cd2084 (patch)
tree351d2ab064442e29e76a74c7b4fa53c1048fb66b /tests/unit/utils/assert.test.ts
parent4383213a23e27903e1fed270f1dbcc116644c7fc (diff)
downloadhollowdark-4dfbf7a13120b3b64521fce6de7d5d3f76cd2084.tar.xz
hollowdark-4dfbf7a13120b3b64521fce6de7d5d3f76cd2084.zip
Add shared utilities: Result, assert, deepEqual, common types, log
Foundational helpers referenced by most subsequent code. Small, pure, no dependencies on anything in the project. utils/result.ts Result<T, E> = Ok<T> | Err<E> for recoverable failures at system boundaries (save/load, manifest fetch, content validation). Internal pure logic still uses throw for programmer errors. ok / err / isOk / isErr / mapResult / mapErr / unwrap / unwrapOr. utils/assert.ts assert (with type-narrowing asserts), assertNever for exhaustive-switch termination, assertDefined for narrowing T | null | undefined → T. utils/equal.ts Structural deepEqual for tests comparing simulation snapshots. Handles plain objects, arrays, Map, Set, Date, primitives. Does not handle cyclic graphs (simulation state is a tree). utils/types.ts Common type aliases: NonEmptyArray, JsonValue, ElementOf, DeepReadonly, Brand<T, B> for nominal / branded types (PersonId vs RelationshipId). utils/log.ts Structured logging wrapping console. Developer- facing only; the game ships with no runtime telemetry. utils/index.ts Public re-exports. 40 unit tests in tests/unit/utils/ cover Result constructors and combinators, assert variants, and deepEqual's primitive / array / object / Map / Set / Date paths plus a realistic simulation-snapshot comparison.
Diffstat (limited to 'tests/unit/utils/assert.test.ts')
-rw-r--r--tests/unit/utils/assert.test.ts46
1 files changed, 46 insertions, 0 deletions
diff --git a/tests/unit/utils/assert.test.ts b/tests/unit/utils/assert.test.ts
new file mode 100644
index 0000000..c1fc02d
--- /dev/null
+++ b/tests/unit/utils/assert.test.ts
@@ -0,0 +1,46 @@
+import { describe, expect, test } from 'vitest'
+import { assert, assertDefined, assertNever } from 'utils/assert'
+
+describe('assert', () => {
+ test('passes on truthy condition', () => {
+ expect(() => assert(true)).not.toThrow()
+ expect(() => assert(1)).not.toThrow()
+ expect(() => assert('non-empty')).not.toThrow()
+ })
+
+ test('throws on falsy condition', () => {
+ expect(() => assert(false)).toThrow(/Assertion failed/)
+ expect(() => assert(0)).toThrow()
+ expect(() => assert(null)).toThrow()
+ expect(() => assert(undefined)).toThrow()
+ expect(() => assert('')).toThrow()
+ })
+
+ test('uses supplied message', () => {
+ expect(() => assert(false, 'custom reason')).toThrow(/custom reason/)
+ })
+})
+
+describe('assertDefined', () => {
+ test('returns the value when defined', () => {
+ expect(assertDefined(5)).toBe(5)
+ expect(assertDefined('')).toBe('')
+ expect(assertDefined(false)).toBe(false)
+ expect(assertDefined(0)).toBe(0)
+ })
+
+ test('throws on null / undefined', () => {
+ expect(() => assertDefined(null)).toThrow()
+ expect(() => assertDefined(undefined)).toThrow()
+ })
+
+ test('uses supplied message', () => {
+ expect(() => assertDefined(null, 'nope')).toThrow(/nope/)
+ })
+})
+
+describe('assertNever', () => {
+ test('always throws', () => {
+ expect(() => assertNever('x' as never)).toThrow()
+ })
+})