54 lines
2.1 KiB
TypeScript
54 lines
2.1 KiB
TypeScript
|
|
/**
|
||
|
|
* @module tests/unit/db/stableEqual
|
||
|
|
* @description Unit proof for the key-order-insensitive deep-equal that
|
||
|
|
* {@link Brainy.diff} uses to decide whether an id present at both endpoints
|
||
|
|
* actually changed. The risk it guards: a naive JSON.stringify comparison is
|
||
|
|
* key-order-sensitive and would report a no-op re-write as `modified`.
|
||
|
|
*/
|
||
|
|
import { describe, it, expect } from 'vitest'
|
||
|
|
import { stableDeepEqual } from '../../../src/db/stableEqual.js'
|
||
|
|
|
||
|
|
describe('stableDeepEqual', () => {
|
||
|
|
it('ignores object key order (the core diff requirement)', () => {
|
||
|
|
expect(stableDeepEqual({ a: 1, b: 2 }, { b: 2, a: 1 })).toBe(true)
|
||
|
|
expect(stableDeepEqual({ a: 1, b: 2, c: { x: 1, y: 2 } }, { c: { y: 2, x: 1 }, b: 2, a: 1 })).toBe(true)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('honors array order (arrays are order-significant)', () => {
|
||
|
|
expect(stableDeepEqual([1, 2, 3], [1, 2, 3])).toBe(true)
|
||
|
|
expect(stableDeepEqual([1, 2, 3], [3, 2, 1])).toBe(false)
|
||
|
|
expect(stableDeepEqual([1, 2], [1, 2, 3])).toBe(false)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('recurses into nested objects and arrays', () => {
|
||
|
|
expect(
|
||
|
|
stableDeepEqual(
|
||
|
|
{ tags: ['a', 'b'], meta: { n: 1, deep: { z: [1, { q: 2 }] } } },
|
||
|
|
{ meta: { deep: { z: [1, { q: 2 }] }, n: 1 }, tags: ['a', 'b'] }
|
||
|
|
)
|
||
|
|
).toBe(true)
|
||
|
|
expect(
|
||
|
|
stableDeepEqual({ meta: { deep: { z: [1, { q: 2 }] } } }, { meta: { deep: { z: [1, { q: 3 }] } } })
|
||
|
|
).toBe(false)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('distinguishes primitives, null, and types', () => {
|
||
|
|
expect(stableDeepEqual(1, 1)).toBe(true)
|
||
|
|
expect(stableDeepEqual(1, '1')).toBe(false)
|
||
|
|
expect(stableDeepEqual(null, null)).toBe(true)
|
||
|
|
expect(stableDeepEqual(null, {})).toBe(false)
|
||
|
|
expect(stableDeepEqual({ a: 1 }, { a: 1, b: undefined })).toBe(false) // extra key
|
||
|
|
expect(stableDeepEqual(true, false)).toBe(false)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('treats NaN as equal to NaN (stable value comparison)', () => {
|
||
|
|
expect(stableDeepEqual(NaN, NaN)).toBe(true)
|
||
|
|
expect(stableDeepEqual({ x: NaN }, { x: NaN })).toBe(true)
|
||
|
|
expect(stableDeepEqual(NaN, 0)).toBe(false)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('an object and an array of the same length are not equal', () => {
|
||
|
|
expect(stableDeepEqual({ 0: 'a', 1: 'b' }, ['a', 'b'])).toBe(false)
|
||
|
|
})
|
||
|
|
})
|