mirror of
				https://github.com/1disk/edp445.git
				synced 2024-08-14 22:47:02 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			397 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			397 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const test = require('tap').test
 | |
| const fss = require('./')
 | |
| const clone = require('clone')
 | |
| const s = JSON.stringify
 | |
| const stream = require('stream')
 | |
| 
 | |
| test('circular reference to root', function (assert) {
 | |
|   const fixture = { name: 'Tywin Lannister' }
 | |
|   fixture.circle = fixture
 | |
|   const expected = s({ name: 'Tywin Lannister', circle: '[Circular]' })
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('circular getter reference to root', function (assert) {
 | |
|   const fixture = {
 | |
|     name: 'Tywin Lannister',
 | |
|     get circle () {
 | |
|       return fixture
 | |
|     }
 | |
|   }
 | |
|   const expected = s({ name: 'Tywin Lannister', circle: '[Circular]' })
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('nested circular reference to root', function (assert) {
 | |
|   const fixture = { name: 'Tywin Lannister' }
 | |
|   fixture.id = { circle: fixture }
 | |
|   const expected = s({ name: 'Tywin Lannister', id: { circle: '[Circular]' } })
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('child circular reference', function (assert) {
 | |
|   const fixture = {
 | |
|     name: 'Tywin Lannister',
 | |
|     child: { name: 'Tyrion Lannister' }
 | |
|   }
 | |
|   fixture.child.dinklage = fixture.child
 | |
|   const expected = s({
 | |
|     name: 'Tywin Lannister',
 | |
|     child: {
 | |
|       name: 'Tyrion Lannister',
 | |
|       dinklage: '[Circular]'
 | |
|     }
 | |
|   })
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('nested child circular reference', function (assert) {
 | |
|   const fixture = {
 | |
|     name: 'Tywin Lannister',
 | |
|     child: { name: 'Tyrion Lannister' }
 | |
|   }
 | |
|   fixture.child.actor = { dinklage: fixture.child }
 | |
|   const expected = s({
 | |
|     name: 'Tywin Lannister',
 | |
|     child: {
 | |
|       name: 'Tyrion Lannister',
 | |
|       actor: { dinklage: '[Circular]' }
 | |
|     }
 | |
|   })
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('circular objects in an array', function (assert) {
 | |
|   const fixture = { name: 'Tywin Lannister' }
 | |
|   fixture.hand = [fixture, fixture]
 | |
|   const expected = s({
 | |
|     name: 'Tywin Lannister',
 | |
|     hand: ['[Circular]', '[Circular]']
 | |
|   })
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('nested circular references in an array', function (assert) {
 | |
|   const fixture = {
 | |
|     name: 'Tywin Lannister',
 | |
|     offspring: [{ name: 'Tyrion Lannister' }, { name: 'Cersei Lannister' }]
 | |
|   }
 | |
|   fixture.offspring[0].dinklage = fixture.offspring[0]
 | |
|   fixture.offspring[1].headey = fixture.offspring[1]
 | |
| 
 | |
|   const expected = s({
 | |
|     name: 'Tywin Lannister',
 | |
|     offspring: [
 | |
|       { name: 'Tyrion Lannister', dinklage: '[Circular]' },
 | |
|       { name: 'Cersei Lannister', headey: '[Circular]' }
 | |
|     ]
 | |
|   })
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('circular arrays', function (assert) {
 | |
|   const fixture = []
 | |
|   fixture.push(fixture, fixture)
 | |
|   const expected = s(['[Circular]', '[Circular]'])
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('nested circular arrays', function (assert) {
 | |
|   const fixture = []
 | |
|   fixture.push(
 | |
|     { name: 'Jon Snow', bastards: fixture },
 | |
|     { name: 'Ramsay Bolton', bastards: fixture }
 | |
|   )
 | |
|   const expected = s([
 | |
|     { name: 'Jon Snow', bastards: '[Circular]' },
 | |
|     { name: 'Ramsay Bolton', bastards: '[Circular]' }
 | |
|   ])
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('repeated non-circular references in objects', function (assert) {
 | |
|   const daenerys = { name: 'Daenerys Targaryen' }
 | |
|   const fixture = {
 | |
|     motherOfDragons: daenerys,
 | |
|     queenOfMeereen: daenerys
 | |
|   }
 | |
|   const expected = s(fixture)
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('repeated non-circular references in arrays', function (assert) {
 | |
|   const daenerys = { name: 'Daenerys Targaryen' }
 | |
|   const fixture = [daenerys, daenerys]
 | |
|   const expected = s(fixture)
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('double child circular reference', function (assert) {
 | |
|   // create circular reference
 | |
|   const child = { name: 'Tyrion Lannister' }
 | |
|   child.dinklage = child
 | |
| 
 | |
|   // include it twice in the fixture
 | |
|   const fixture = { name: 'Tywin Lannister', childA: child, childB: child }
 | |
|   const cloned = clone(fixture)
 | |
|   const expected = s({
 | |
|     name: 'Tywin Lannister',
 | |
|     childA: {
 | |
|       name: 'Tyrion Lannister',
 | |
|       dinklage: '[Circular]'
 | |
|     },
 | |
|     childB: {
 | |
|       name: 'Tyrion Lannister',
 | |
|       dinklage: '[Circular]'
 | |
|     }
 | |
|   })
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
| 
 | |
|   // check if the fixture has not been modified
 | |
|   assert.same(fixture, cloned)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('child circular reference with toJSON', function (assert) {
 | |
|   // Create a test object that has an overridden `toJSON` property
 | |
|   TestObject.prototype.toJSON = function () {
 | |
|     return { special: 'case' }
 | |
|   }
 | |
|   function TestObject (content) {}
 | |
| 
 | |
|   // Creating a simple circular object structure
 | |
|   const parentObject = {}
 | |
|   parentObject.childObject = new TestObject()
 | |
|   parentObject.childObject.parentObject = parentObject
 | |
| 
 | |
|   // Creating a simple circular object structure
 | |
|   const otherParentObject = new TestObject()
 | |
|   otherParentObject.otherChildObject = {}
 | |
|   otherParentObject.otherChildObject.otherParentObject = otherParentObject
 | |
| 
 | |
|   // Making sure our original tests work
 | |
|   assert.same(parentObject.childObject.parentObject, parentObject)
 | |
|   assert.same(
 | |
|     otherParentObject.otherChildObject.otherParentObject,
 | |
|     otherParentObject
 | |
|   )
 | |
| 
 | |
|   // Should both be idempotent
 | |
|   assert.equal(fss(parentObject), '{"childObject":{"special":"case"}}')
 | |
|   assert.equal(fss(otherParentObject), '{"special":"case"}')
 | |
| 
 | |
|   // Therefore the following assertion should be `true`
 | |
|   assert.same(parentObject.childObject.parentObject, parentObject)
 | |
|   assert.same(
 | |
|     otherParentObject.otherChildObject.otherParentObject,
 | |
|     otherParentObject
 | |
|   )
 | |
| 
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('null object', function (assert) {
 | |
|   const expected = s(null)
 | |
|   const actual = fss(null)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('null property', function (assert) {
 | |
|   const expected = s({ f: null })
 | |
|   const actual = fss({ f: null })
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('nested child circular reference in toJSON', function (assert) {
 | |
|   const circle = { some: 'data' }
 | |
|   circle.circle = circle
 | |
|   const a = {
 | |
|     b: {
 | |
|       toJSON: function () {
 | |
|         a.b = 2
 | |
|         return '[Redacted]'
 | |
|       }
 | |
|     },
 | |
|     baz: {
 | |
|       circle,
 | |
|       toJSON: function () {
 | |
|         a.baz = circle
 | |
|         return '[Redacted]'
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   const o = {
 | |
|     a,
 | |
|     bar: a
 | |
|   }
 | |
| 
 | |
|   const expected = s({
 | |
|     a: {
 | |
|       b: '[Redacted]',
 | |
|       baz: '[Redacted]'
 | |
|     },
 | |
|     bar: {
 | |
|       b: 2,
 | |
|       baz: {
 | |
|         some: 'data',
 | |
|         circle: '[Circular]'
 | |
|       }
 | |
|     }
 | |
|   })
 | |
|   const actual = fss(o)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('circular getters are restored when stringified', function (assert) {
 | |
|   const fixture = {
 | |
|     name: 'Tywin Lannister',
 | |
|     get circle () {
 | |
|       return fixture
 | |
|     }
 | |
|   }
 | |
|   fss(fixture)
 | |
| 
 | |
|   assert.equal(fixture.circle, fixture)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('non-configurable circular getters use a replacer instead of markers', function (assert) {
 | |
|   const fixture = { name: 'Tywin Lannister' }
 | |
|   Object.defineProperty(fixture, 'circle', {
 | |
|     configurable: false,
 | |
|     get: function () {
 | |
|       return fixture
 | |
|     },
 | |
|     enumerable: true
 | |
|   })
 | |
| 
 | |
|   fss(fixture)
 | |
| 
 | |
|   assert.equal(fixture.circle, fixture)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('getter child circular reference are replaced instead of marked', function (assert) {
 | |
|   const fixture = {
 | |
|     name: 'Tywin Lannister',
 | |
|     child: {
 | |
|       name: 'Tyrion Lannister',
 | |
|       get dinklage () {
 | |
|         return fixture.child
 | |
|       }
 | |
|     },
 | |
|     get self () {
 | |
|       return fixture
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   const expected = s({
 | |
|     name: 'Tywin Lannister',
 | |
|     child: {
 | |
|       name: 'Tyrion Lannister',
 | |
|       dinklage: '[Circular]'
 | |
|     },
 | |
|     self: '[Circular]'
 | |
|   })
 | |
|   const actual = fss(fixture)
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('Proxy throwing', function (assert) {
 | |
|   assert.plan(1)
 | |
|   const s = new stream.PassThrough()
 | |
|   s.resume()
 | |
|   s.write('', () => {
 | |
|     assert.end()
 | |
|   })
 | |
|   const actual = fss({ s, p: new Proxy({}, { get () { throw new Error('kaboom') } }) })
 | |
|   assert.equal(actual, '"[unable to serialize, circular reference is too complex to analyze]"')
 | |
| })
 | |
| 
 | |
| test('depthLimit option - will replace deep objects', function (assert) {
 | |
|   const fixture = {
 | |
|     name: 'Tywin Lannister',
 | |
|     child: {
 | |
|       name: 'Tyrion Lannister'
 | |
|     },
 | |
|     get self () {
 | |
|       return fixture
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   const expected = s({
 | |
|     name: 'Tywin Lannister',
 | |
|     child: '[...]',
 | |
|     self: '[Circular]'
 | |
|   })
 | |
|   const actual = fss(fixture, undefined, undefined, {
 | |
|     depthLimit: 1,
 | |
|     edgesLimit: 1
 | |
|   })
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 | |
| 
 | |
| test('edgesLimit option - will replace deep objects', function (assert) {
 | |
|   const fixture = {
 | |
|     object: {
 | |
|       1: { test: 'test' },
 | |
|       2: { test: 'test' },
 | |
|       3: { test: 'test' },
 | |
|       4: { test: 'test' }
 | |
|     },
 | |
|     array: [
 | |
|       { test: 'test' },
 | |
|       { test: 'test' },
 | |
|       { test: 'test' },
 | |
|       { test: 'test' }
 | |
|     ],
 | |
|     get self () {
 | |
|       return fixture
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   const expected = s({
 | |
|     object: {
 | |
|       1: { test: 'test' },
 | |
|       2: { test: 'test' },
 | |
|       3: { test: 'test' },
 | |
|       4: '[...]'
 | |
|     },
 | |
|     array: [{ test: 'test' }, { test: 'test' }, { test: 'test' }, '[...]'],
 | |
|     self: '[Circular]'
 | |
|   })
 | |
|   const actual = fss(fixture, undefined, undefined, {
 | |
|     depthLimit: 3,
 | |
|     edgesLimit: 3
 | |
|   })
 | |
|   assert.equal(actual, expected)
 | |
|   assert.end()
 | |
| })
 |