You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					247 lines
				
				7.4 KiB
			
		
		
			
		
	
	
					247 lines
				
				7.4 KiB
			| 
											3 years ago
										 | var Sinon = require("sinon") | ||
|  | var stringify = require("..") | ||
|  | function jsonify(obj) { return JSON.stringify(obj, null, 2) } | ||
|  | 
 | ||
|  | describe("Stringify", function() { | ||
|  |   it("must stringify circular objects", function() { | ||
|  |     var obj = {name: "Alice"} | ||
|  |     obj.self = obj | ||
|  |     var json = stringify(obj, null, 2) | ||
|  |     json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"})) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must stringify circular objects with intermediaries", function() { | ||
|  |     var obj = {name: "Alice"} | ||
|  |     obj.identity = {self: obj} | ||
|  |     var json = stringify(obj, null, 2) | ||
|  |     json.must.eql(jsonify({name: "Alice", identity: {self: "[Circular ~]"}})) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must stringify circular objects deeper", function() { | ||
|  |     var obj = {name: "Alice", child: {name: "Bob"}} | ||
|  |     obj.child.self = obj.child | ||
|  | 
 | ||
|  |     stringify(obj, null, 2).must.eql(jsonify({ | ||
|  |       name: "Alice", | ||
|  |       child: {name: "Bob", self: "[Circular ~.child]"} | ||
|  |     })) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must stringify circular objects deeper with intermediaries", function() { | ||
|  |     var obj = {name: "Alice", child: {name: "Bob"}} | ||
|  |     obj.child.identity = {self: obj.child} | ||
|  | 
 | ||
|  |     stringify(obj, null, 2).must.eql(jsonify({ | ||
|  |       name: "Alice", | ||
|  |       child: {name: "Bob", identity: {self: "[Circular ~.child]"}} | ||
|  |     })) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must stringify circular objects in an array", function() { | ||
|  |     var obj = {name: "Alice"} | ||
|  |     obj.self = [obj, obj] | ||
|  | 
 | ||
|  |     stringify(obj, null, 2).must.eql(jsonify({ | ||
|  |       name: "Alice", self: ["[Circular ~]", "[Circular ~]"] | ||
|  |     })) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must stringify circular objects deeper in an array", function() { | ||
|  |     var obj = {name: "Alice", children: [{name: "Bob"}, {name: "Eve"}]} | ||
|  |     obj.children[0].self = obj.children[0] | ||
|  |     obj.children[1].self = obj.children[1] | ||
|  | 
 | ||
|  |     stringify(obj, null, 2).must.eql(jsonify({ | ||
|  |       name: "Alice", | ||
|  |       children: [ | ||
|  |         {name: "Bob", self: "[Circular ~.children.0]"}, | ||
|  |         {name: "Eve", self: "[Circular ~.children.1]"} | ||
|  |       ] | ||
|  |     })) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must stringify circular arrays", function() { | ||
|  |     var obj = [] | ||
|  |     obj.push(obj) | ||
|  |     obj.push(obj) | ||
|  |     var json = stringify(obj, null, 2) | ||
|  |     json.must.eql(jsonify(["[Circular ~]", "[Circular ~]"])) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must stringify circular arrays with intermediaries", function() { | ||
|  |     var obj = [] | ||
|  |     obj.push({name: "Alice", self: obj}) | ||
|  |     obj.push({name: "Bob", self: obj}) | ||
|  | 
 | ||
|  |     stringify(obj, null, 2).must.eql(jsonify([ | ||
|  |       {name: "Alice", self: "[Circular ~]"}, | ||
|  |       {name: "Bob", self: "[Circular ~]"} | ||
|  |     ])) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must stringify repeated objects in objects", function() { | ||
|  |     var obj = {} | ||
|  |     var alice = {name: "Alice"} | ||
|  |     obj.alice1 = alice | ||
|  |     obj.alice2 = alice | ||
|  | 
 | ||
|  |     stringify(obj, null, 2).must.eql(jsonify({ | ||
|  |       alice1: {name: "Alice"}, | ||
|  |       alice2: {name: "Alice"} | ||
|  |     })) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must stringify repeated objects in arrays", function() { | ||
|  |     var alice = {name: "Alice"} | ||
|  |     var obj = [alice, alice] | ||
|  |     var json = stringify(obj, null, 2) | ||
|  |     json.must.eql(jsonify([{name: "Alice"}, {name: "Alice"}])) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must call given decycler and use its output", function() { | ||
|  |     var obj = {} | ||
|  |     obj.a = obj | ||
|  |     obj.b = obj | ||
|  | 
 | ||
|  |     var decycle = Sinon.spy(function() { return decycle.callCount }) | ||
|  |     var json = stringify(obj, null, 2, decycle) | ||
|  |     json.must.eql(jsonify({a: 1, b: 2}, null, 2)) | ||
|  | 
 | ||
|  |     decycle.callCount.must.equal(2) | ||
|  |     decycle.thisValues[0].must.equal(obj) | ||
|  |     decycle.args[0][0].must.equal("a") | ||
|  |     decycle.args[0][1].must.equal(obj) | ||
|  |     decycle.thisValues[1].must.equal(obj) | ||
|  |     decycle.args[1][0].must.equal("b") | ||
|  |     decycle.args[1][1].must.equal(obj) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must call replacer and use its output", function() { | ||
|  |     var obj = {name: "Alice", child: {name: "Bob"}} | ||
|  | 
 | ||
|  |     var replacer = Sinon.spy(bangString) | ||
|  |     var json = stringify(obj, replacer, 2) | ||
|  |     json.must.eql(jsonify({name: "Alice!", child: {name: "Bob!"}})) | ||
|  | 
 | ||
|  |     replacer.callCount.must.equal(4) | ||
|  |     replacer.args[0][0].must.equal("") | ||
|  |     replacer.args[0][1].must.equal(obj) | ||
|  |     replacer.thisValues[1].must.equal(obj) | ||
|  |     replacer.args[1][0].must.equal("name") | ||
|  |     replacer.args[1][1].must.equal("Alice") | ||
|  |     replacer.thisValues[2].must.equal(obj) | ||
|  |     replacer.args[2][0].must.equal("child") | ||
|  |     replacer.args[2][1].must.equal(obj.child) | ||
|  |     replacer.thisValues[3].must.equal(obj.child) | ||
|  |     replacer.args[3][0].must.equal("name") | ||
|  |     replacer.args[3][1].must.equal("Bob") | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must call replacer after describing circular references", function() { | ||
|  |     var obj = {name: "Alice"} | ||
|  |     obj.self = obj | ||
|  | 
 | ||
|  |     var replacer = Sinon.spy(bangString) | ||
|  |     var json = stringify(obj, replacer, 2) | ||
|  |     json.must.eql(jsonify({name: "Alice!", self: "[Circular ~]!"})) | ||
|  | 
 | ||
|  |     replacer.callCount.must.equal(3) | ||
|  |     replacer.args[0][0].must.equal("") | ||
|  |     replacer.args[0][1].must.equal(obj) | ||
|  |     replacer.thisValues[1].must.equal(obj) | ||
|  |     replacer.args[1][0].must.equal("name") | ||
|  |     replacer.args[1][1].must.equal("Alice") | ||
|  |     replacer.thisValues[2].must.equal(obj) | ||
|  |     replacer.args[2][0].must.equal("self") | ||
|  |     replacer.args[2][1].must.equal("[Circular ~]") | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must call given decycler and use its output for nested objects", | ||
|  |     function() { | ||
|  |     var obj = {} | ||
|  |     obj.a = obj | ||
|  |     obj.b = {self: obj} | ||
|  | 
 | ||
|  |     var decycle = Sinon.spy(function() { return decycle.callCount }) | ||
|  |     var json = stringify(obj, null, 2, decycle) | ||
|  |     json.must.eql(jsonify({a: 1, b: {self: 2}})) | ||
|  | 
 | ||
|  |     decycle.callCount.must.equal(2) | ||
|  |     decycle.args[0][0].must.equal("a") | ||
|  |     decycle.args[0][1].must.equal(obj) | ||
|  |     decycle.args[1][0].must.equal("self") | ||
|  |     decycle.args[1][1].must.equal(obj) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must use decycler's output when it returned null", function() { | ||
|  |     var obj = {a: "b"} | ||
|  |     obj.self = obj | ||
|  |     obj.selves = [obj, obj] | ||
|  | 
 | ||
|  |     function decycle() { return null } | ||
|  |     stringify(obj, null, 2, decycle).must.eql(jsonify({ | ||
|  |       a: "b", | ||
|  |       self: null, | ||
|  |       selves: [null, null] | ||
|  |     })) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must use decycler's output when it returned undefined", function() { | ||
|  |     var obj = {a: "b"} | ||
|  |     obj.self = obj | ||
|  |     obj.selves = [obj, obj] | ||
|  | 
 | ||
|  |     function decycle() {} | ||
|  |     stringify(obj, null, 2, decycle).must.eql(jsonify({ | ||
|  |       a: "b", | ||
|  |       selves: [null, null] | ||
|  |     })) | ||
|  |   }) | ||
|  | 
 | ||
|  |   it("must throw given a decycler that returns a cycle", function() { | ||
|  |     var obj = {} | ||
|  |     obj.self = obj | ||
|  |     var err | ||
|  |     function identity(key, value) { return value } | ||
|  |     try { stringify(obj, null, 2, identity) } catch (ex) { err = ex } | ||
|  |     err.must.be.an.instanceof(TypeError) | ||
|  |   }) | ||
|  | 
 | ||
|  |   describe(".getSerialize", function() { | ||
|  |     it("must stringify circular objects", function() { | ||
|  |       var obj = {a: "b"} | ||
|  |       obj.circularRef = obj | ||
|  |       obj.list = [obj, obj] | ||
|  | 
 | ||
|  |       var json = JSON.stringify(obj, stringify.getSerialize(), 2) | ||
|  |       json.must.eql(jsonify({ | ||
|  |         "a": "b", | ||
|  |         "circularRef": "[Circular ~]", | ||
|  |         "list": ["[Circular ~]", "[Circular ~]"] | ||
|  |       })) | ||
|  |     }) | ||
|  | 
 | ||
|  |     // This is the behavior as of Mar 3, 2015.
 | ||
|  |     // The serializer function keeps state inside the returned function and
 | ||
|  |     // so far I'm not sure how to not do that. JSON.stringify's replacer is not
 | ||
|  |     // called _after_ serialization.
 | ||
|  |     xit("must return a function that could be called twice", function() { | ||
|  |       var obj = {name: "Alice"} | ||
|  |       obj.self = obj | ||
|  | 
 | ||
|  |       var json | ||
|  |       var serializer = stringify.getSerialize() | ||
|  | 
 | ||
|  |       json = JSON.stringify(obj, serializer, 2) | ||
|  |       json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"})) | ||
|  | 
 | ||
|  |       json = JSON.stringify(obj, serializer, 2) | ||
|  |       json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"})) | ||
|  |     }) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | function bangString(key, value) { | ||
|  |   return typeof value == "string" ? value + "!" : value | ||
|  | } |