Skip to content

Commit

Permalink
meta: add benchmark and placeholder equal
Browse files Browse the repository at this point in the history
  • Loading branch information
chrispuska committed Dec 25, 2024
1 parent bb76a4b commit 07c0ccf
Show file tree
Hide file tree
Showing 7 changed files with 448 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"scripts": {
"build": "pnpm run --filter @heliosgraphics/fractures build",
"test": "NODE_ENV=test vitest run",
"test:bench": "pnpm run --filter @heliosgraphics/benchmark bench",
"test:u": "NODE_ENV=test vitest run --update",
"test:watch": "NODE_ENV=test vitest",
"test:coverage": "NODE_ENV=test vitest run --coverage",
Expand Down
94 changes: 94 additions & 0 deletions packages/benchmarks/__mocks__/objects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
type SimpleObject = {
a: number
b: number
}

type NestedObject = {
a: number
b: string
c: {
d: number
e: Array<string>
f: {
g: boolean
h: number
}
}
}

type ArrayObject = {
numbers: Array<number>
strings: Array<string>
mixed: Array<number | string>
}

export const MOCK_SIMPLE_OBJECTS = {
first: { a: 1, b: 2 },
second: { a: 1, b: 2 },
third: { a: 1, b: 3 },
} satisfies Record<string, SimpleObject>

export const MOCK_NESTED_OBJECTS = {
first: {
a: 1,
b: "test",
c: {
d: 123,
e: ["a", "b", "c"],
f: {
g: true,
h: 456,
},
},
},
second: {
a: 1,
b: "test",
c: {
d: 123,
e: ["a", "b", "c"],
f: {
g: true,
h: 457,
},
},
},
} satisfies Record<string, NestedObject>

export const MOCK_ARRAY_OBJECTS = {
first: {
numbers: [1, 2, 3, 4, 5],
strings: ["a", "b", "c"],
mixed: [1, "two", 3, "four"],
},
second: {
numbers: [1, 2, 3, 4, 5],
strings: ["a", "b", "c"],
mixed: [1, "two", 3, "four"],
},
} satisfies Record<string, ArrayObject>

export const MOCK_LARGE_OBJECTS = {
first: Array.from({ length: 1000 }, (_, i) => ({
id: i,
value: Math.random(),
text: `Item ${i}`,
active: i % 2 === 0,
metadata: {
created: new Date().toISOString(),
modified: new Date().toISOString(),
tags: [`tag${i}`, `category${i % 10}`],
},
})),
second: Array.from({ length: 1000 }, (_, i) => ({
id: i,
value: Math.random(),
text: `Item ${i}`,
active: i % 2 === 0,
metadata: {
created: new Date().toISOString(),
modified: new Date().toISOString(),
tags: [`tag${i}`, `category${i % 10}`],
},
})),
}
78 changes: 78 additions & 0 deletions packages/benchmarks/equals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import benchmark from "benchmark"
import { deepEqual } from "../utils/equals"
import _ from "lodash"
import { MOCK_ARRAY_OBJECTS, MOCK_LARGE_OBJECTS, MOCK_NESTED_OBJECTS, MOCK_SIMPLE_OBJECTS } from "./__mocks__/objects"

type BenchmarkResult = {
"Test Name": string
"Operations/sec": string
Margin: string
Runs: number
}

const suite = new benchmark.Suite()

const testNames: readonly string[] = [
"Simple Objects - Identical (Fractures)",
"Simple Objects - Identical (Lodash)",
"Simple Objects - Different (Fractures)",
"Simple Objects - Different (Lodash)",
"Nested Objects (Fractures)",
"Nested Objects (Lodash)",
"Array Objects (Fractures)",
"Array Objects (Lodash)",
"Large Objects (Fractures)",
"Large Objects (Lodash)",
]

const maxNameLength: number = Math.max(...testNames.map((name) => name.length))
const _padName = (name: string): string => name.padEnd(maxNameLength, " ")
const allResults: BenchmarkResult[] = []

suite
.add("Simple Objects - Identical (Fractures)", () => {
deepEqual(MOCK_SIMPLE_OBJECTS.first, MOCK_SIMPLE_OBJECTS.second)
})
.add("Simple Objects - Identical (Lodash)", () => {
_.isEqual(MOCK_SIMPLE_OBJECTS.first, MOCK_SIMPLE_OBJECTS.second)
})
.add("Simple Objects - Different (Fractures)", () => {
deepEqual(MOCK_SIMPLE_OBJECTS.first, MOCK_SIMPLE_OBJECTS.third)
})
.add("Simple Objects - Different (Lodash)", () => {
_.isEqual(MOCK_SIMPLE_OBJECTS.first, MOCK_SIMPLE_OBJECTS.third)
})
.add("Nested Objects (Fractures)", () => {
deepEqual(MOCK_NESTED_OBJECTS.first, MOCK_NESTED_OBJECTS.second)
})
.add("Nested Objects (Lodash)", () => {
_.isEqual(MOCK_NESTED_OBJECTS.first, MOCK_NESTED_OBJECTS.second)
})
.add("Array Objects (Fractures)", () => {
deepEqual(MOCK_ARRAY_OBJECTS.first, MOCK_ARRAY_OBJECTS.second)
})
.add("Array Objects (Lodash)", () => {
_.isEqual(MOCK_ARRAY_OBJECTS.first, MOCK_ARRAY_OBJECTS.second)
})
.add("Large Objects (Fractures)", () => {
deepEqual(MOCK_LARGE_OBJECTS.first, MOCK_LARGE_OBJECTS.second)
})
.add("Large Objects (Lodash)", () => {
_.isEqual(MOCK_LARGE_OBJECTS.first, MOCK_LARGE_OBJECTS.second)
})
.on("cycle", function (event: { target: benchmark.Target }) {
const benchmark: benchmark.Target = event.target

const result: BenchmarkResult = {
"Test Name": _padName(benchmark?.name || "a mistery function"),
"Operations/sec": Math.floor(benchmark?.hz ?? 0).toLocaleString(),
Margin: ${benchmark?.stats?.rme.toFixed(2)}%`,
Runs: benchmark?.stats?.sample?.length ?? 0,
}

allResults.push(result)
})
.on("complete", function () {
console.table(allResults)
})
.run({ async: true })
22 changes: 22 additions & 0 deletions packages/benchmarks/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@heliosgraphics/benchmark",
"version": "0.0.0",
"type": "module",
"author": "03b8 <[email protected]>",
"license": "MIT",
"private": false,
"description": "benchmark",
"scripts": {
"bench": "bun run *.ts"
},
"engines": {
"node": ">=20.15.0"
},
"devDependencies": {
"@types/uuid": "latest",
"@types/benchmark": "latest",
"@types/lodash": "latest",
"benchmark": "latest",
"lodash": "latest"
}
}
123 changes: 123 additions & 0 deletions packages/utils/equals.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { deepEqual, areSetsEqual } from "./equals"
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"

describe("deepEqual", () => {
it("primitives", () => {
expect(deepEqual(1, 1)).toBe(true)
expect(deepEqual("hello", "hello")).toBe(true)
expect(deepEqual(true, true)).toBe(true)
expect(deepEqual(null, null)).toBe(true)
expect(deepEqual(undefined, undefined)).toBe(true)
expect(deepEqual(1, 2)).toBe(false)
expect(deepEqual("hello", "world")).toBe(false)
expect(deepEqual(true, false)).toBe(false)
expect(deepEqual(null, undefined)).toBe(false)
})

it("arrays", () => {
expect(deepEqual([], [])).toBe(true)
expect(deepEqual([1, 2, 3], [1, 2, 3])).toBe(true)
expect(deepEqual([1, [2, 3]], [1, [2, 3]])).toBe(true)
expect(deepEqual([1, 2], [1, 2, 3])).toBe(false)
expect(deepEqual([1, 2, 3], [1, 3, 2])).toBe(false)
})

it("objects", () => {
expect(deepEqual({}, {})).toBe(true)
expect(deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true)
expect(deepEqual({ a: { b: 2 } }, { a: { b: 2 } })).toBe(true)
expect(deepEqual({ a: 1, b: 2 }, { b: 2, a: 1 })).toBe(true)
expect(deepEqual({ a: 1 }, { a: 1, b: 2 })).toBe(false)
expect(deepEqual({ a: 1 }, { a: 2 })).toBe(false)
})

it("dates", () => {
const date1 = new Date("2024-01-01")
const date2 = new Date("2024-01-01")
const date3 = new Date("2024-01-02")

expect(deepEqual(date1, date2)).toBe(true)
expect(deepEqual(date1, date3)).toBe(false)
})

it("sets", () => {
const set1 = new Set([1, 2, 3])
const set2 = new Set([1, 2, 3])
const set3 = new Set([1, 2, 4])

expect(deepEqual(set1, set2)).toBe(true)
expect(deepEqual(set1, set3)).toBe(false)
})

it("maps", () => {
const map1 = new Map([
["a", 1],
["b", 2],
])
const map2 = new Map([
["a", 1],
["b", 2],
])
const map3 = new Map([
["a", 1],
["b", 3],
])

expect(deepEqual(map1, map2)).toBe(true)
expect(deepEqual(map1, map3)).toBe(false)
})

it("circular references", () => {
const obj1: any = { a: 1 }
const obj2: any = { a: 1 }
obj1.self = obj1
obj2.self = obj2

expect(deepEqual(obj1, obj2)).toBe(true)
})
})

describe("areSetsEqual", () => {
it("simple sets without deep comparison", () => {
const set1 = new Set([1, 2, 3])
const set2 = new Set([1, 2, 3])
const set3 = new Set([1, 2, 4])

expect(areSetsEqual(set1, set2)).toBe(true)
expect(areSetsEqual(set1, set3)).toBe(false)
})

it("sets with objects using deep comparison", () => {
const set1 = new Set([{ a: 1 }, { b: 2 }])
const set2 = new Set([{ a: 1 }, { b: 2 }])
const set3 = new Set([{ a: 1 }, { b: 3 }])

expect(areSetsEqual(set1, set2, true)).toBe(true)
expect(areSetsEqual(set1, set3, true)).toBe(false)
})

it("sets with different sizes", () => {
const set1 = new Set([1, 2, 3])
const set2 = new Set([1, 2])

expect(areSetsEqual(set1, set2)).toBe(false)
expect(areSetsEqual(set1, set2, true)).toBe(false)
})

it("sets with nested structures", () => {
const set1 = new Set([{ a: { b: 2 } }, [1, 2, 3]])
const set2 = new Set([{ a: { b: 2 } }, [1, 2, 3]])
const set3 = new Set([{ a: { b: 3 } }, [1, 2, 3]])

expect(areSetsEqual(set1, set2, true)).toBe(true)
expect(areSetsEqual(set1, set3, true)).toBe(false)
})

it("empty sets", () => {
const set1 = new Set()
const set2 = new Set()

expect(areSetsEqual(set1, set2)).toBe(true)
expect(areSetsEqual(set1, set2, true)).toBe(true)
})
})
Loading

0 comments on commit 07c0ccf

Please sign in to comment.