11import { describe , expect , it , vi } from 'vitest'
2- import { stringifyBoundedJson } from '@/lib/core/utils/bounded-json'
2+ import { isJsonWithinByteLimit , stringifyBoundedJson } from '@/lib/core/utils/bounded-json'
33
44describe ( 'bounded JSON' , ( ) => {
55 it . each ( [
@@ -13,11 +13,14 @@ describe('bounded JSON', () => {
1313 const bytes = Buffer . byteLength ( json , 'utf8' )
1414 expect ( stringifyBoundedJson ( value , bytes ) ) . toBe ( json )
1515 expect ( stringifyBoundedJson ( value , bytes - 1 ) ) . toBeUndefined ( )
16+ expect ( isJsonWithinByteLimit ( value , bytes ) ) . toBe ( true )
17+ expect ( isJsonWithinByteLimit ( value , bytes - 1 ) ) . toBe ( false )
1618 } )
1719
1820 it ( 'rejects cycles, excessive depth, and excessive nodes' , ( ) => {
1921 const cyclic : Record < string , unknown > = { }
2022 cyclic . self = cyclic
23+ expect ( isJsonWithinByteLimit ( cyclic , 1024 ) ) . toBe ( false )
2124 let deep : unknown = 'leaf'
2225 for ( let index = 0 ; index < 66 ; index ++ ) deep = { child : deep }
2326 for ( const value of [
@@ -37,6 +40,7 @@ describe('bounded JSON', () => {
3740 const custom = Object . defineProperty ( { } , 'toJSON' , { value : toJSON } )
3841 for ( const value of [ accessor , custom , { output : new Uint8Array ( [ 1 , 2 , 3 ] ) } ] ) {
3942 expect ( stringifyBoundedJson ( value , 1024 ) ) . toBeUndefined ( )
43+ expect ( isJsonWithinByteLimit ( value , 1024 ) ) . toBe ( false )
4044 }
4145 expect ( getter ) . not . toHaveBeenCalled ( )
4246 expect ( toJSON ) . not . toHaveBeenCalled ( )
@@ -47,6 +51,7 @@ describe('bounded JSON', () => {
4751 const serialize = vi . spyOn ( JSON , 'stringify' )
4852 try {
4953 expect ( stringifyBoundedJson ( value , 1024 ) ) . toBeUndefined ( )
54+ expect ( isJsonWithinByteLimit ( value , 1024 ) ) . toBe ( false )
5055 expect ( serialize ) . not . toHaveBeenCalled ( )
5156 } finally {
5257 serialize . mockRestore ( )
@@ -61,6 +66,7 @@ describe('bounded JSON', () => {
6166 const serialize = vi . spyOn ( JSON , 'stringify' )
6267 try {
6368 expect ( stringifyBoundedJson ( value , 1024 ) ) . toBeUndefined ( )
69+ expect ( isJsonWithinByteLimit ( value , 1024 ) ) . toBe ( false )
6470 expect ( serialize ) . not . toHaveBeenCalled ( )
6571 } finally {
6672 serialize . mockRestore ( )
@@ -71,6 +77,7 @@ describe('bounded JSON', () => {
7177 const get = vi . fn ( ( ) => 'UNADMITTED' )
7278 const value = new Proxy ( { text : 'admitted' } , { get } )
7379 expect ( stringifyBoundedJson ( value , 1024 ) ) . toBe ( '{"text":"admitted"}' )
80+ expect ( isJsonWithinByteLimit ( value , 19 ) ) . toBe ( true )
7481 expect ( get ) . not . toHaveBeenCalled ( )
7582 } )
7683
@@ -79,12 +86,21 @@ describe('bounded JSON', () => {
7986 const prototype = Object . create ( Array . prototype , { 0 : { get } } )
8087 const value = Object . setPrototypeOf ( Array ( 1 ) , prototype )
8188 expect ( stringifyBoundedJson ( value , 1024 ) ) . toBe ( '[null]' )
89+ expect ( isJsonWithinByteLimit ( value , 6 ) ) . toBe ( true )
8290 expect ( get ) . not . toHaveBeenCalled ( )
8391 } )
8492
8593 it ( 'allows repeated references without treating them as a cycle' , ( ) => {
8694 const result = { answer : 42 }
8795 const value = { rawResponse : result , modelResponse : result }
8896 expect ( stringifyBoundedJson ( value , 1024 ) ) . toBe ( JSON . stringify ( value ) )
97+ expect ( isJsonWithinByteLimit ( value , Buffer . byteLength ( JSON . stringify ( value ) ) ) ) . toBe ( true )
98+ } )
99+
100+ it ( 'counts an ordinary toJSON data field without invoking custom serialization' , ( ) => {
101+ const value = { toJSON : 'ordinary JSON field' , nested : [ { } , [ ] , { flag : true } ] }
102+ const bytes = Buffer . byteLength ( JSON . stringify ( value ) )
103+ expect ( isJsonWithinByteLimit ( value , bytes ) ) . toBe ( true )
104+ expect ( isJsonWithinByteLimit ( value , bytes - 1 ) ) . toBe ( false )
89105 } )
90106} )
0 commit comments