twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

stringify_test.js (7550B)


      1 var Sinon = require("sinon")
      2 var stringify = require("..")
      3 function jsonify(obj) { return JSON.stringify(obj, null, 2) }
      4 
      5 describe("Stringify", function() {
      6   it("must stringify circular objects", function() {
      7     var obj = {name: "Alice"}
      8     obj.self = obj
      9     var json = stringify(obj, null, 2)
     10     json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"}))
     11   })
     12 
     13   it("must stringify circular objects with intermediaries", function() {
     14     var obj = {name: "Alice"}
     15     obj.identity = {self: obj}
     16     var json = stringify(obj, null, 2)
     17     json.must.eql(jsonify({name: "Alice", identity: {self: "[Circular ~]"}}))
     18   })
     19 
     20   it("must stringify circular objects deeper", function() {
     21     var obj = {name: "Alice", child: {name: "Bob"}}
     22     obj.child.self = obj.child
     23 
     24     stringify(obj, null, 2).must.eql(jsonify({
     25       name: "Alice",
     26       child: {name: "Bob", self: "[Circular ~.child]"}
     27     }))
     28   })
     29 
     30   it("must stringify circular objects deeper with intermediaries", function() {
     31     var obj = {name: "Alice", child: {name: "Bob"}}
     32     obj.child.identity = {self: obj.child}
     33 
     34     stringify(obj, null, 2).must.eql(jsonify({
     35       name: "Alice",
     36       child: {name: "Bob", identity: {self: "[Circular ~.child]"}}
     37     }))
     38   })
     39 
     40   it("must stringify circular objects in an array", function() {
     41     var obj = {name: "Alice"}
     42     obj.self = [obj, obj]
     43 
     44     stringify(obj, null, 2).must.eql(jsonify({
     45       name: "Alice", self: ["[Circular ~]", "[Circular ~]"]
     46     }))
     47   })
     48 
     49   it("must stringify circular objects deeper in an array", function() {
     50     var obj = {name: "Alice", children: [{name: "Bob"}, {name: "Eve"}]}
     51     obj.children[0].self = obj.children[0]
     52     obj.children[1].self = obj.children[1]
     53 
     54     stringify(obj, null, 2).must.eql(jsonify({
     55       name: "Alice",
     56       children: [
     57         {name: "Bob", self: "[Circular ~.children.0]"},
     58         {name: "Eve", self: "[Circular ~.children.1]"}
     59       ]
     60     }))
     61   })
     62 
     63   it("must stringify circular arrays", function() {
     64     var obj = []
     65     obj.push(obj)
     66     obj.push(obj)
     67     var json = stringify(obj, null, 2)
     68     json.must.eql(jsonify(["[Circular ~]", "[Circular ~]"]))
     69   })
     70 
     71   it("must stringify circular arrays with intermediaries", function() {
     72     var obj = []
     73     obj.push({name: "Alice", self: obj})
     74     obj.push({name: "Bob", self: obj})
     75 
     76     stringify(obj, null, 2).must.eql(jsonify([
     77       {name: "Alice", self: "[Circular ~]"},
     78       {name: "Bob", self: "[Circular ~]"}
     79     ]))
     80   })
     81 
     82   it("must stringify repeated objects in objects", function() {
     83     var obj = {}
     84     var alice = {name: "Alice"}
     85     obj.alice1 = alice
     86     obj.alice2 = alice
     87 
     88     stringify(obj, null, 2).must.eql(jsonify({
     89       alice1: {name: "Alice"},
     90       alice2: {name: "Alice"}
     91     }))
     92   })
     93 
     94   it("must stringify repeated objects in arrays", function() {
     95     var alice = {name: "Alice"}
     96     var obj = [alice, alice]
     97     var json = stringify(obj, null, 2)
     98     json.must.eql(jsonify([{name: "Alice"}, {name: "Alice"}]))
     99   })
    100 
    101   it("must call given decycler and use its output", function() {
    102     var obj = {}
    103     obj.a = obj
    104     obj.b = obj
    105 
    106     var decycle = Sinon.spy(function() { return decycle.callCount })
    107     var json = stringify(obj, null, 2, decycle)
    108     json.must.eql(jsonify({a: 1, b: 2}, null, 2))
    109 
    110     decycle.callCount.must.equal(2)
    111     decycle.thisValues[0].must.equal(obj)
    112     decycle.args[0][0].must.equal("a")
    113     decycle.args[0][1].must.equal(obj)
    114     decycle.thisValues[1].must.equal(obj)
    115     decycle.args[1][0].must.equal("b")
    116     decycle.args[1][1].must.equal(obj)
    117   })
    118 
    119   it("must call replacer and use its output", function() {
    120     var obj = {name: "Alice", child: {name: "Bob"}}
    121 
    122     var replacer = Sinon.spy(bangString)
    123     var json = stringify(obj, replacer, 2)
    124     json.must.eql(jsonify({name: "Alice!", child: {name: "Bob!"}}))
    125 
    126     replacer.callCount.must.equal(4)
    127     replacer.args[0][0].must.equal("")
    128     replacer.args[0][1].must.equal(obj)
    129     replacer.thisValues[1].must.equal(obj)
    130     replacer.args[1][0].must.equal("name")
    131     replacer.args[1][1].must.equal("Alice")
    132     replacer.thisValues[2].must.equal(obj)
    133     replacer.args[2][0].must.equal("child")
    134     replacer.args[2][1].must.equal(obj.child)
    135     replacer.thisValues[3].must.equal(obj.child)
    136     replacer.args[3][0].must.equal("name")
    137     replacer.args[3][1].must.equal("Bob")
    138   })
    139 
    140   it("must call replacer after describing circular references", function() {
    141     var obj = {name: "Alice"}
    142     obj.self = obj
    143 
    144     var replacer = Sinon.spy(bangString)
    145     var json = stringify(obj, replacer, 2)
    146     json.must.eql(jsonify({name: "Alice!", self: "[Circular ~]!"}))
    147 
    148     replacer.callCount.must.equal(3)
    149     replacer.args[0][0].must.equal("")
    150     replacer.args[0][1].must.equal(obj)
    151     replacer.thisValues[1].must.equal(obj)
    152     replacer.args[1][0].must.equal("name")
    153     replacer.args[1][1].must.equal("Alice")
    154     replacer.thisValues[2].must.equal(obj)
    155     replacer.args[2][0].must.equal("self")
    156     replacer.args[2][1].must.equal("[Circular ~]")
    157   })
    158 
    159   it("must call given decycler and use its output for nested objects",
    160     function() {
    161     var obj = {}
    162     obj.a = obj
    163     obj.b = {self: obj}
    164 
    165     var decycle = Sinon.spy(function() { return decycle.callCount })
    166     var json = stringify(obj, null, 2, decycle)
    167     json.must.eql(jsonify({a: 1, b: {self: 2}}))
    168 
    169     decycle.callCount.must.equal(2)
    170     decycle.args[0][0].must.equal("a")
    171     decycle.args[0][1].must.equal(obj)
    172     decycle.args[1][0].must.equal("self")
    173     decycle.args[1][1].must.equal(obj)
    174   })
    175 
    176   it("must use decycler's output when it returned null", function() {
    177     var obj = {a: "b"}
    178     obj.self = obj
    179     obj.selves = [obj, obj]
    180 
    181     function decycle() { return null }
    182     stringify(obj, null, 2, decycle).must.eql(jsonify({
    183       a: "b",
    184       self: null,
    185       selves: [null, null]
    186     }))
    187   })
    188 
    189   it("must use decycler's output when it returned undefined", function() {
    190     var obj = {a: "b"}
    191     obj.self = obj
    192     obj.selves = [obj, obj]
    193 
    194     function decycle() {}
    195     stringify(obj, null, 2, decycle).must.eql(jsonify({
    196       a: "b",
    197       selves: [null, null]
    198     }))
    199   })
    200 
    201   it("must throw given a decycler that returns a cycle", function() {
    202     var obj = {}
    203     obj.self = obj
    204     var err
    205     function identity(key, value) { return value }
    206     try { stringify(obj, null, 2, identity) } catch (ex) { err = ex }
    207     err.must.be.an.instanceof(TypeError)
    208   })
    209 
    210   describe(".getSerialize", function() {
    211     it("must stringify circular objects", function() {
    212       var obj = {a: "b"}
    213       obj.circularRef = obj
    214       obj.list = [obj, obj]
    215 
    216       var json = JSON.stringify(obj, stringify.getSerialize(), 2)
    217       json.must.eql(jsonify({
    218         "a": "b",
    219         "circularRef": "[Circular ~]",
    220         "list": ["[Circular ~]", "[Circular ~]"]
    221       }))
    222     })
    223 
    224     // This is the behavior as of Mar 3, 2015.
    225     // The serializer function keeps state inside the returned function and
    226     // so far I'm not sure how to not do that. JSON.stringify's replacer is not
    227     // called _after_ serialization.
    228     xit("must return a function that could be called twice", function() {
    229       var obj = {name: "Alice"}
    230       obj.self = obj
    231 
    232       var json
    233       var serializer = stringify.getSerialize()
    234 
    235       json = JSON.stringify(obj, serializer, 2)
    236       json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"}))
    237 
    238       json = JSON.stringify(obj, serializer, 2)
    239       json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"}))
    240     })
    241   })
    242 })
    243 
    244 function bangString(key, value) {
    245   return typeof value == "string" ? value + "!" : value
    246 }