ThomasR/JSON.sortify

View on GitHub
test/test.js

Summary

Maintainability
A
3 hrs
Test Coverage
if (typeof module !== 'undefined' && module.exports) {
    console.info('Running in NodeJS');
    JSON.sortify = require('../src');
    var expect = require('expect');
} else { // Browser
    console.info('Running in browser');
    //eslint-disable-next-line
    global = window;
    // libs provided via <script>
}

describe('JSON.sortify', function () {
    describe('interface', function () {
        it('should define a function', function () {
            expect(JSON.sortify).toBeA(Function);
        });

        it('should take precisely three arguments', function () {
            expect(JSON.sortify.length).toBe(3);
        });
    });

    describe('compatibility', function () {
        it('should stringify simple values', function () {
            var fixtures = [
                1,
                .234,
                Infinity,
                NaN,
                null,
                true,
                false,
                undefined,
                'undefined',
                '',
                function bar() {},
                /abc/
            ];
            if (typeof global.Symbol !== 'undefined') {
                //eslint-disable-next-line no-undef
                fixtures.push(Symbol());
            }
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify(fixture)).toEqual(JSON.stringify(fixture));
            });

        });

        it('should stringify simple objects', function () {
            var fixtures = [
                {a:1, b:true, c:'ok', d:null},
                {a:.1, b:undefined, c:function () {}}, '{"a":0.1}',
                {' ': '"', 'null': 'null', 'undefined': '\t'},
                {'"\n\t\\:': ''}
            ];
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify(fixture)).toEqual(JSON.stringify(fixture));
            });
        });

        it('should stringify simple arrays', function () {
            var fixtures = [
                [1, true, 'ok', null],
                [.1, undefined, function () {}]
            ];
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify(fixture)).toEqual(JSON.stringify(fixture));
            });
        });

        it('should stringify nested objects', function () {
            var fixtures = [
                {a:{b:2, c:{d:3}}},
                [{a:{b:1}, b:[{a:1}, {b:{c:[2, null]}}]}]
            ];
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify(fixture)).toEqual(JSON.stringify(fixture));
            });
        });

        it('should handle toJSON', function () {
            var fixtures = [
                {toJSON:function () { return 'Banana!'; }},
                {a: 1, b:2, toJSON:function () { return null; }},
                {a: {b:1, toJSON:function () { return 'x'; }}, c:3},
                {a: {b:1, toJSON:function (key) { return 'x' + key + 'y'; }}}
            ];
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify(fixture)).toEqual(JSON.stringify(fixture));
            });
        });

        it('should handle the replacer parameter', function () {
            var fixtures = [
                [{a:{b:2, c:{d:3}}}, ['a']],
                [{a:{b:2, c:{d:3}}}, ['b']],
                [{a:{b:2, c:{d:3}}}, []],
                [{a:{b:2, a:{a:3, c:2}}}, ['a']],
                [{a:1, b:'foo'}, function (key, value) { return typeof value == 'string' ? value + '!!!' : value; }],
                [{a:{b:2, a:{a:3, c:2}}}, function () {}]
            ];
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify(fixture[0], fixture[1])).toEqual(JSON.stringify(fixture[0], fixture[1]));
            });
        });

        it('should handle the indentation parameter', function () {
            var fixtures = [
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, null],
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, 1],
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, 4],
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, 11],
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, -1],
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, '\t'],
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, 'garbage'],
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, 'too long, must be shortened']
            ];
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify(fixture[0], null, fixture[1])).toEqual(JSON.stringify(fixture[0], null, fixture[1]));
            });
        });

        it('should handle three arguments', function () {
            var fixtures = [
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, function (key, value) { return typeof value == 'string' ? value + '!!!' : value; }, 4],
                [{a:{a:2, c:[{d:3}, 4, 'hello']}}, ['a'], '\t'],
                [{a:{b:2, c:[{d:3}, 4, 'hello']}}, function (key, value) { return value; }, 'garbage ']
            ];
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify.apply(JSON, fixture)).toEqual(JSON.stringify.apply(JSON, fixture));
            });
        });

        it('should throw a TypeError on cyclic values', function () {
            var fixtures = [
                {},
                {a:{}},
                [],
                {a:[]},
                {a:[]}
            ];
            fixtures[0].x = fixtures[0];
            fixtures[1].a.b = fixtures[1];
            fixtures[2].push(fixtures[2]);
            fixtures[3].a.push(fixtures[3]);
            fixtures[4].a.push(fixtures[4].a);
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify.bind(JSON, fixture)).toThrow(TypeError);
            });
        });
    });

    describe('sortification', function () {
        it('should sort keys', function () {
            var fixtures = [
                [{c:1, b:2, a:3}, '{"a":3,"b":2,"c":1}'],
                [{c:1, 42:2, a:3, 0:4, '':5, '00':6, 5:7}, '{"0":4,"5":7,"42":2,"":5,"00":6,"a":3,"c":1}'],
                [{c:1, b:2, a:{y:1, z:2, x:3}}, '{"a":{"x":3,"y":1,"z":2},"b":2,"c":1}'],
                [{c:1, b:['foo', 2, {a:{y:1, z:2, x:3}}]}, '{"b":["foo",2,{"a":{"x":3,"y":1,"z":2}}],"c":1}']
            ];
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify(fixture[0])).toEqual(fixture[1]);
            });
        });

        it('should sort keys and handle three arguments', function () {
            var fixtures = [
                [
                    {x:1, b:2, a:3},
                    ['a', 'b', 'c'],
                    2,
                    '{\n  "a": 3,\n  "b": 2\n}'
                ],
                [
                    {x:1, b:{toJSON:function () { return 'b'; }}, a:3},
                    ['a', 'b', 'c'],
                    '••',
                    '{\n••"a": 3,\n••"b": "b"\n}'
                ],
                [
                    {a:undefined, b:function () {}, x:1, c:2, 0:3, 5:5, 11:11, ' d ':5, z:'foo', aa:'a', d:[{f:{h:2, e:1}}, null, '2']},
                    function (key, val) { return typeof val == 'string' ? val + '!!!' : val; },
                    4,
                    '{\n    "0": 3,\n    "5": 5,\n    "11": 11,\n    " d ": 5,\n    "aa": "a!!!",\n    "c": 2,\n    "d": [\n        {\n            "f": {\n                "e": 1,\n                "h": 2\n            }\n        },\n        null,\n        "2!!!"\n    ],\n    "x": 1,\n    "z": "foo!!!"\n}'
                ]
            ];
            fixtures.forEach(function (fixture) {
                expect(JSON.sortify(fixture[0], fixture[1], fixture[2])).toEqual(fixture[3]);
            });

        });
    });

    describe('interoperability / interchangeability', function () {
        var fixtures = [
            1,
            [1, {a: 1, b: 2, c: [1, 2]}],
            {a: {b:1, toJSON:function (key) { return 'x' + key + 'y'; }}}
        ];
        it('should not depend on the “JSON” scope', function () {
            var jsonSortify = JSON.sortify;
            fixtures.forEach(function (fixture) {
                expect(jsonSortify(fixture)).toEqual(JSON.stringify(fixture));
            });
        });
        it('should allow to overwrite “JSON.stringify”', function () {
            var jsonStringifyOriginal = JSON.stringify.bind(JSON);
            JSON.stringify = JSON.sortify;
            fixtures.forEach(function (fixture) {
                expect(JSON.stringify(fixture)).toEqual(jsonStringifyOriginal(fixture));
            });
        });
    });
});