Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
24dc40d
Prepare to rewrite in modern TypeScript
novemberborn Feb 20, 2025
037d59e
Reimplement deep comparison and (de)serialization
novemberborn Feb 21, 2025
b219c6d
Test BoxedPrimiteRepresentation
novemberborn Apr 13, 2025
3df9a40
Pack annotations to enable compression optimizations
novemberborn Apr 13, 2025
fc2094c
fixup! Prepare to rewrite in modern TypeScript
novemberborn Apr 15, 2025
d945880
Test DateRepresentation
novemberborn Apr 15, 2025
27699be
Test ErrorRepresentation
novemberborn Apr 15, 2025
7f54a24
Test FunctionRepresentation
novemberborn Apr 15, 2025
8765028
Test MapRepresentation
novemberborn May 2, 2025
fa277d4
Fix and test ModuleNamespaceObjectRepresentation
novemberborn May 2, 2025
cc5d9ca
fixup! Reimplement deep comparison and (de)serialization
novemberborn May 2, 2025
47b432c
Test PromiseRepresentation
novemberborn May 3, 2025
bb2ad5f
More efficient serialization of string tags that are the same as the …
novemberborn May 3, 2025
88872d3
Test RegExpRepresentation
novemberborn May 3, 2025
a0142ed
fixup! Reimplement deep comparison and (de)serialization
novemberborn May 3, 2025
e200dff
Test SetRepresentation
novemberborn May 3, 2025
e114ae5
Test WeakMapRepresentation
novemberborn May 3, 2025
c3a8e17
Test WeakSetRepresentation
novemberborn May 3, 2025
bd46a0e
Test ExternalRepresentation; improve deserialized comparisons
novemberborn May 5, 2025
aae0641
Further optimize serialization of string tags that are the same as co…
novemberborn May 5, 2025
7380d51
Test CryptoKeyRepresentation
novemberborn May 5, 2025
375af03
Test BytesAccessor
novemberborn May 5, 2025
9e29018
Test ElementAccessor and SparseValueRepresentation
novemberborn May 5, 2025
f2afba0
Test IteratorValueAccessor
novemberborn May 5, 2025
bd9d358
Test MapEntryAccessor
novemberborn May 5, 2025
79fc20e
Test property accessors
novemberborn May 6, 2025
1887afd
Refactor compare() tests focusing on algorithmic accuracy not behavio…
novemberborn May 6, 2025
025055e
Test describe()
novemberborn May 6, 2025
2a65532
Test serialization types
novemberborn May 7, 2025
7f75486
Test serialization
novemberborn May 7, 2025
0a7cdd9
Test deserialization
novemberborn May 16, 2025
78437fb
c8: Exclude *.d.ts files from report
novemberborn May 18, 2025
8d15d93
Split DescriptionContext and isPrimitive/representPrimitive into sepa…
novemberborn May 18, 2025
1377318
Split Encoder into its own file
novemberborn May 19, 2025
45b521d
Use cbor2 directly
novemberborn May 19, 2025
9fee1b3
Target Node.js 24 and update related dependencies & configuration
novemberborn May 19, 2025
8c88547
Support integers larger than int64
novemberborn May 19, 2025
9cf3312
Encode / decode non-wellformed strings
novemberborn May 19, 2025
0fe1c0a
Implement flags to control behavior
novemberborn May 19, 2025
1c444a5
Remove exports test file
novemberborn May 19, 2025
90d0471
Make comparing objects with null prototypes to regular object prototy…
novemberborn May 21, 2025
6526af5
Stop using interfaces
novemberborn May 21, 2025
e07ae2d
Add missing tests for flags getter in context implementations
novemberborn Jun 3, 2025
aa3c0c8
Treat empty constructor names as such
novemberborn May 24, 2025
6f25269
Refactor so property groups are not value representations
novemberborn May 31, 2025
bfb271a
Change BytesAccessor to be shallow
novemberborn May 29, 2025
a1e5fc2
Implement formatting for accessors and values
novemberborn May 21, 2025
d5e2c79
Upgrade XO
novemberborn Jun 9, 2025
fc40ba8
Update dependencies
novemberborn Jun 9, 2025
0d1d49d
Rename concepts
novemberborn Jun 9, 2025
1b2dc8a
Add method to fully (recursively) deserialize a representation
novemberborn Jun 9, 2025
aa46eb4
Change stack iteration to return undefined when done
novemberborn Jun 10, 2025
41ab11d
Simplify symbol property serialization
novemberborn Jun 10, 2025
a569ba5
Move iterator out of stack entry into internal state
novemberborn Jun 15, 2025
f206ec5
Implement Stack#peekNext() to access the next iterated value
novemberborn Jun 15, 2025
a6445fc
Implement Stack#takeWhile() to iterate over values while a condition …
novemberborn Jun 15, 2025
9a97460
Group accessors depending on applied algorithm, not in the context
novemberborn Jun 15, 2025
f2d0c84
Improve comparison logic for Error, RegExp, WeakMap, WeakSet and Cryp…
novemberborn Jun 16, 2025
19d124d
Exclude Error#stack from the iterated properties
novemberborn Jun 18, 2025
6f85dc6
Always include Error#code
novemberborn Jun 18, 2025
94aa64d
Implement fuzzy comparison mode
novemberborn Jun 16, 2025
79570f6
Refactor array-like handling
novemberborn Aug 17, 2025
00e5da1
Clean up unnecessary static is() from mocks
novemberborn Aug 17, 2025
05c8cc5
Give RHS control over being compared
novemberborn Aug 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Test FunctionRepresentation
  • Loading branch information
novemberborn committed Jun 5, 2025
commit 7f54a24ff907865b6cd350e944082e19adf0fca8
225 changes: 225 additions & 0 deletions src/values/objects/test/function.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import test from 'ava'
import { DescriptionContext } from '../../../describe.ts'
import { Encoder } from '../../../serialize.ts'
import { Decoder, DeserializationContext } from '../../../deserialize.ts'
import { FunctionRepresentation } from '../function.ts'
import { comparable, strictlyEqual, unequal } from '../../../comparison.ts'
import { staticTypeTable } from '../../../serialization-types.ts'
import { snapshotEncoded } from '../../test/helpers/snapshot-encoded.ts'
import { NamedPropertyGroup, NamedPropertyAccessor } from '../../../accessors/property.ts'

// Helper functions for testing
function namedFunction() {
return 'result'
}

// Anonymous function
const anonymousFunction = function () {
return 'anonymous'
}

// Arrow function
const arrowFunction = () => 'arrow'

// Deserialize method test
test('deserialize creates a comparable FunctionRepresentation', (t) => {
const originalContext = new DescriptionContext()
const func = namedFunction
const original = originalContext.represent(func) as FunctionRepresentation

const encoder = new Encoder()
original.serialize(encoder)

const decoder = new Decoder(encoder.bytes)
decoder.staticType() // Consume the type
const deserializationContext = new DeserializationContext(decoder)
const deserialized = FunctionRepresentation.deserialize(deserializationContext, decoder)

// The deserialized representation should be comparable to the original
t.is(original.compare(deserialized), comparable)
})

// Compare method tests
test('compare returns strictlyEqual when comparing the same function instance', (t) => {
const context = new DescriptionContext()
const func = namedFunction

const funcRep1 = context.represent(func) as FunctionRepresentation
const funcRep2 = context.represent(func) as FunctionRepresentation

t.is(funcRep1.compare(funcRep2), strictlyEqual)
})

test('compare returns unequal when comparing to non-FunctionRepresentation', (t) => {
const context = new DescriptionContext()
const func = namedFunction
const obj = {}

const funcRep = context.represent(func) as FunctionRepresentation
const objRep = context.represent(obj)

t.is(funcRep.compare(objRep), unequal)
})

test('compare returns unequal when comparing different non-deserialized function instances', (t) => {
const context = new DescriptionContext()

// Two different function instances that do the same thing
function func1() {
return 'result'
}
function func2() {
return 'result'
}

const funcRep1 = context.represent(func1) as FunctionRepresentation
const funcRep2 = context.represent(func2) as FunctionRepresentation

// For non-deserialized functions, comparison is by reference only
t.is(funcRep1.compare(funcRep2), unequal)
})

test('compare returns comparable when at least one function is deserialized', (t) => {
const originalContext = new DescriptionContext()
const func = namedFunction
const original = originalContext.represent(func) as FunctionRepresentation

// Serialize and deserialize the function
const encoder = new Encoder()
original.serialize(encoder)
const decoder = new Decoder(encoder.bytes)
decoder.staticType() // Consume the type
const deserializationContext = new DeserializationContext(decoder)
const deserialized = FunctionRepresentation.deserialize(deserializationContext, decoder)

// Create a new representation of the same function
const newContext = new DescriptionContext()
const sameFunc = namedFunction
const newRep = newContext.represent(sameFunc) as FunctionRepresentation

// When one is deserialized, they should be comparable
t.is(newRep.compare(deserialized), comparable)
})

// iterateArrayLike and iterateIterable tests
test('iterateArrayLike yields no elements for functions', (t) => {
const context = new DescriptionContext()
const func = namedFunction
const funcRep = context.represent(func) as FunctionRepresentation

const elements = [...funcRep.iterateArrayLike()]

t.is(elements.length, 0)
})

test('iterateIterable yields no elements for functions', (t) => {
const context = new DescriptionContext()
const func = namedFunction
const funcRep = context.represent(func) as FunctionRepresentation

const iterables = [...funcRep.iterateIterable()]

t.is(iterables.length, 0)
})

// iterateProperties test
test('iterateProperties yields the name property for functions', (t) => {
const context = new DescriptionContext()
const func = namedFunction
const funcRep = context.represent(func) as FunctionRepresentation

const propertyGroups = [...funcRep.iterateProperties()]

t.is(propertyGroups.length, 1)
const [namedGroup] = propertyGroups
t.true(namedGroup instanceof NamedPropertyGroup)

// We expect just the 'name' property for functions
const properties = [...namedGroup!]
t.is(properties.length, 1)

// Create property accessor for the expected property
const nameValue = context.represent(func.name)
const nameAccessor = new NamedPropertyAccessor('name', nameValue)

// Find the name property
const nameProperty = properties.find((prop) => {
return nameAccessor.compare(prop) === strictlyEqual
})

// Verify that the name property was found
t.truthy(nameProperty, 'name property should be present')
})

// Test different function types (named, anonymous, arrow)
test('iterateProperties works correctly with different function types', (t) => {
const context = new DescriptionContext()

// Named function
const namedRep = context.represent(namedFunction) as FunctionRepresentation
const namedPropertyGroups = [...namedRep.iterateProperties()]
t.is(namedPropertyGroups.length, 1)
const namedProperties = [...namedPropertyGroups[0]!]
t.is(namedProperties.length, 1)

// Create property accessor for the expected property
const namedNameValue = context.represent(namedFunction.name)
const namedNameAccessor = new NamedPropertyAccessor('name', namedNameValue)

// Find and verify the name property for named function
const namedNameProperty = namedProperties.find((prop) => {
return namedNameAccessor.compare(prop) === strictlyEqual
})
t.truthy(namedNameProperty, 'name property should be present for named function')

// Anonymous function
const anonymousRep = context.represent(anonymousFunction) as FunctionRepresentation
const anonymousPropertyGroups = [...anonymousRep.iterateProperties()]
t.is(anonymousPropertyGroups.length, 1)
const anonymousProperties = [...anonymousPropertyGroups[0]!]
t.is(anonymousProperties.length, 1)

// Create property accessor for the expected property
const anonymousNameValue = context.represent(anonymousFunction.name)
const anonymousNameAccessor = new NamedPropertyAccessor('name', anonymousNameValue)

// Find and verify the name property for anonymous function
const anonymousNameProperty = anonymousProperties.find((prop) => {
return anonymousNameAccessor.compare(prop) === strictlyEqual
})
t.truthy(anonymousNameProperty, 'name property should be present for anonymous function')

// Arrow function
const arrowRep = context.represent(arrowFunction) as FunctionRepresentation
const arrowPropertyGroups = [...arrowRep.iterateProperties()]
t.is(arrowPropertyGroups.length, 1)
const arrowProperties = [...arrowPropertyGroups[0]!]
t.is(arrowProperties.length, 1)

// Create property accessor for the expected property
const arrowNameValue = context.represent(arrowFunction.name)
const arrowNameAccessor = new NamedPropertyAccessor('name', arrowNameValue)

// Find and verify the name property for arrow function
const arrowNameProperty = arrowProperties.find((prop) => {
return arrowNameAccessor.compare(prop) === strictlyEqual
})
t.truthy(arrowNameProperty, 'name property should be present for arrow function')
})

// Serialization test
test('serialize uses function static type', (t) => {
const context = new DescriptionContext()
const func = namedFunction
const funcRep = context.represent(func) as FunctionRepresentation

const encoder = new Encoder()
funcRep.serialize(encoder)

// Check the overall structure and type
snapshotEncoded(t, encoder, 'function serialization')

// Verify the static type
const decoder = new Decoder(encoder.bytes)
t.is(decoder.staticType(), staticTypeTable.function)
})
68 changes: 68 additions & 0 deletions src/values/objects/test/snapshots/function.ts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Snapshot report for `src/values/objects/test/function.ts`

The actual snapshot is saved in `function.ts.snap`.

Generated by [AVA](https://avajs.dev).

## serialize uses function static type

> Serialized bytes (function serialization)

Uint8Array [
1825a461 63684675 6e637469 6f6e6161 f5617001 616c00
]

> Decoded bytes (function serialization)

[
[
0,
24,
37,
],
[
5,
4,
4,
],
[
3,
1,
'c',
],
[
3,
8,
'Function',
],
[
3,
1,
'a',
],
[
7,
21,
true,
],
[
3,
1,
'p',
],
[
0,
1,
1,
],
[
3,
1,
'l',
],
[
0,
0,
0,
],
]
Binary file added src/values/objects/test/snapshots/function.ts.snap
Binary file not shown.