Keen Yee Liau ac77a5e9ab fix(@schematics/angular): JsonUtils should respect indent
This commit fixes a few issues with json-utils:

1. The implementation is lacking tests
2. The implementation hardcodes indent = 2 in many places and
   does not respect the `indent` parameter passed by users
3. The implementation is buggy when passed an empty object or array
2019-02-21 15:16:19 -08:00

162 lines
5.5 KiB
TypeScript

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { JsonAstArray, JsonAstObject, JsonValue, parseJsonAst } from '@angular-devkit/core';
import { HostTree, UpdateRecorder } from '@angular-devkit/schematics';
import { UnitTestTree } from '@angular-devkit/schematics/testing';
import {
appendPropertyInAstObject,
appendValueInAstArray,
insertPropertyInAstObjectInOrder,
} from './json-utils';
describe('json-utils', () => {
const a = 'a';
const b = 'b';
const m = 'm';
const z = 'z';
const filePath = '/temp';
let tree: UnitTestTree;
function runTest(testFn: Function, obj: JsonValue, indent: number): string {
const content = JSON.stringify(obj, null, indent);
tree.create(filePath, content);
const ast = parseJsonAst(content);
const rec = tree.beginUpdate(filePath);
testFn(rec, ast);
tree.commitUpdate(rec);
const result = tree.readContent(filePath);
// Clean up the tree by deleting the file.
tree.delete(filePath);
return result;
}
beforeEach(() => {
tree = new UnitTestTree(new HostTree());
});
describe('appendPropertyInAstObject', () => {
it('should insert multiple props with different indentations', () => {
const cases: Array<[{}, string, {}, number]> = [
// initial | prop | want | indent
[{}, z, {z}, 0],
[{z}, m, {z, m}, 0],
[{m, z}, a, {m, z, a}, 0],
[{a, m, z}, b, {a, m, z, b}, 0],
[{}, z, {z}, 2],
[{z}, m, {z, m}, 2],
[{m, z}, a, {m, z, a}, 2],
[{a, m, z}, b, {a, m, z, b}, 2],
[{}, z, {z}, 4],
[{z}, m, {z, m}, 4],
[{m, z}, a, {m, z, a}, 4],
[{a, m, z}, b, {a, m, z, b}, 4],
];
for (const c of cases) {
const [initial, prop, want, indent] = c;
const got = runTest((rec: UpdateRecorder, ast: JsonAstObject) => {
expect(ast.kind).toBe('object');
appendPropertyInAstObject(rec, ast, prop, prop, indent);
}, initial, indent);
expect(got).toBe(JSON.stringify(want, null, indent));
expect(JSON.parse(got)).toEqual(want);
}
});
});
describe('insertPropertyInAstObjectInOrder', () => {
it('should insert a first prop', () => {
const indent = 2;
const result = runTest((rec: UpdateRecorder, ast: JsonAstObject) => {
expect(ast.kind).toBe('object');
insertPropertyInAstObjectInOrder(rec, ast, a, a, indent);
}, {m, z}, indent);
expect(result).toBe(JSON.stringify({a, m, z}, null, indent));
expect(JSON.parse(result)).toEqual({a, m, z});
});
it('should insert a middle prop', () => {
const indent = 2;
const result = runTest((rec: UpdateRecorder, ast: JsonAstObject) => {
expect(ast.kind).toBe('object');
insertPropertyInAstObjectInOrder(rec, ast, m, m, indent);
}, {a, z}, indent);
expect(result).toBe(JSON.stringify({a, m, z}, null, indent));
expect(JSON.parse(result)).toEqual({a, m, z});
});
it('should insert a last prop', () => {
const indent = 2;
const result = runTest((rec: UpdateRecorder, ast: JsonAstObject) => {
expect(ast.kind).toBe('object');
insertPropertyInAstObjectInOrder(rec, ast, z, z, indent);
}, {a, m}, indent);
expect(result).toBe(JSON.stringify({a, m, z}, null, indent));
expect(JSON.parse(result)).toEqual({a, m, z});
});
it('should insert multiple props with different indentations', () => {
const cases: Array<[{}, string, {}, number]> = [
// initial | prop | want | indent
[{}, z, {z}, 0],
[{z}, m, {m, z}, 0],
[{m, z}, a, {a, m, z}, 0],
[{a, m, z}, b, {a, b, m, z}, 0],
[{}, z, {z}, 2],
[{z}, m, {m, z}, 2],
[{m, z}, a, {a, m, z}, 2],
[{a, m, z}, b, {a, b, m, z}, 2],
[{}, z, {z}, 4],
[{z}, m, {m, z}, 4],
[{m, z}, a, {a, m, z}, 4],
[{a, m, z}, b, {a, b, m, z}, 4],
];
for (const c of cases) {
const [initial, prop, want, indent] = c;
const got = runTest((rec: UpdateRecorder, ast: JsonAstObject) => {
expect(ast.kind).toBe('object');
insertPropertyInAstObjectInOrder(rec, ast, prop, prop, indent);
}, initial, indent);
expect(got).toBe(JSON.stringify(want, null, indent));
expect(JSON.parse(got)).toEqual(want);
}
});
});
describe('appendValueInAstArray', () => {
it('should insert multiple props with different indentations', () => {
const cases: Array<[string[], string, {}, number]> = [
// initial | value | want | indent
[[], z, [z], 0],
[[z], m, [z, m], 0],
[[m, z], a, [m, z, a], 0],
[[a, m, z], b, [a, m, z, b], 0],
[[], z, [z], 2],
[[z], m, [z, m], 2],
[[m, z], a, [m, z, a], 2],
[[a, m, z], b, [a, m, z, b], 2],
[[], z, [z], 4],
[[z], m, [z, m], 4],
[[m, z], a, [m, z, a], 4],
[[a, m, z], b, [a, m, z, b], 4],
];
for (const c of cases) {
const [initial, value, want, indent] = c;
const got = runTest((rec: UpdateRecorder, ast: JsonAstArray) => {
expect(ast.kind).toBe('array');
appendValueInAstArray(rec, ast, value, indent);
}, initial, indent);
expect(got).toBe(JSON.stringify(want, null, indent));
expect(JSON.parse(got)).toEqual(want);
}
});
});
});