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