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
							 | 
						||
| 
								 | 
							
								}
							 |