github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/src/views/cluster/containers/dataDistribution/tree.spec.ts (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  import { assert } from "chai";
    12  
    13  import {
    14    flatten, layoutTreeHorizontal, sumValuesUnderPaths, TreePath, LayoutCell,
    15  } from "./tree";
    16  
    17  describe("tree", () => {
    18  
    19    describe("layoutTreeHorizontal", () => {
    20  
    21      it("lays out a simple tree", () => {
    22        const tree = {
    23          name: "a", data: "a",
    24          children: [
    25            { name: "b", data: "b" },
    26            { name: "c", data: "c" },
    27          ],
    28        };
    29  
    30        // |   a   |
    31        // | b | c |
    32        const expectedLayout: LayoutCell<string>[][] = [
    33          [ { width: 2, data: "a", path: [], isCollapsed: false, isPlaceholder: false, isLeaf: false } ],
    34          [
    35            { width: 1, path: ["b"], data: "b", isCollapsed: false, isPlaceholder: false, isLeaf: true },
    36            { width: 1, path: ["c"], data: "c", isCollapsed: false, isPlaceholder: false, isLeaf: true },
    37          ],
    38        ];
    39        assert.deepEqual(layoutTreeHorizontal(tree, []), expectedLayout);
    40      });
    41  
    42      it("lays out a tree of inconsistent depth, inserting a placeholder", () => {
    43        const tree = {
    44          name: "a", data: "a",
    45          children: [
    46            { name: "b", data: "b" },
    47            {
    48              name: "c", data: "c",
    49              children: [
    50                { name: "d", data: "d" },
    51                { name: "e", data: "e" },
    52              ],
    53            },
    54          ],
    55        };
    56  
    57        // |      a      |
    58        // | <P> |   c   |
    59        // |  b  | d | e |
    60        const expectedLayout = [
    61          [ { width: 3, data: "a", path: [], isCollapsed: false, isPlaceholder: false, isLeaf: false } ],
    62          [ { width: 1, path: ["b"], data: "b", isCollapsed: false, isPlaceholder: true, isLeaf: false },
    63            { width: 2, data: "c", path: ["c" ], isCollapsed: false, isPlaceholder: false, isLeaf: false },
    64          ],
    65          [ { width: 1, path: ["b"], data: "b", isCollapsed: false, isPlaceholder: false, isLeaf: true },
    66            { width: 1, path: ["c", "d"], data: "d", isCollapsed: false, isPlaceholder: false, isLeaf: true },
    67            { width: 1, path: ["c", "e"], data: "e", isCollapsed: false, isPlaceholder: false, isLeaf: true },
    68          ],
    69        ];
    70        const actualLayout = layoutTreeHorizontal(tree, []);
    71        assert.deepEqual(actualLayout, expectedLayout);
    72      });
    73  
    74      it("inserts placeholders under a collapsed node, if other subtrees are deeper", () => {
    75        const tree = {
    76          name: "a", data: "a",
    77          children: [
    78            { name: "b", data: "b",
    79              children: [
    80                { name: "c", data: "c" },
    81                { name: "d", data: "d" },
    82              ],
    83            },
    84            {
    85              name: "e", data: "e",
    86              children: [
    87                { name: "f", data: "f" },
    88                { name: "g", data: "g" },
    89              ],
    90            },
    91          ],
    92        };
    93  
    94        // Without anything collapsed:
    95        // |       a       |
    96        // |   b   |   e   |
    97        // | c | d | f | g |
    98        const expectedLayout = [
    99          [ { width: 4, data: "a", path: [], isCollapsed: false, isPlaceholder: false, isLeaf: false } ],
   100          [ { width: 2, path: ["b"], data: "b", isCollapsed: false, isPlaceholder: false, isLeaf: false },
   101            { width: 2, path: ["e"], data: "e", isCollapsed: false, isPlaceholder: false, isLeaf: false },
   102          ],
   103          [ { width: 1, path: ["b", "c"], data: "c", isCollapsed: false, isPlaceholder: false, isLeaf: true },
   104            { width: 1, path: ["b", "d"], data: "d", isCollapsed: false, isPlaceholder: false, isLeaf: true },
   105            { width: 1, path: ["e", "f"], data: "f", isCollapsed: false, isPlaceholder: false, isLeaf: true },
   106            { width: 1, path: ["e", "g"], data: "g", isCollapsed: false, isPlaceholder: false, isLeaf: true },
   107          ],
   108        ];
   109        const actualLayout = layoutTreeHorizontal(tree, []);
   110        assert.deepEqual(actualLayout, expectedLayout);
   111  
   112        // Collapse e:
   113        // |      a      |
   114        // |   b   |  e  |
   115        // | c | d | <P> |
   116        const expectedLayoutCollapseE = [
   117          [ { width: 3, data: "a", path: [], isCollapsed: false, isPlaceholder: false, isLeaf: false } ],
   118          [ { width: 2, path: ["b"], data: "b", isCollapsed: false, isPlaceholder: false, isLeaf: false },
   119            { width: 1, path: ["e"], data: "e", isCollapsed: true, isPlaceholder: false, isLeaf: false },
   120          ],
   121          [ { width: 1, path: ["b", "c"], data: "c", isCollapsed: false, isPlaceholder: false, isLeaf: true },
   122            { width: 1, path: ["b", "d"], data: "d", isCollapsed: false, isPlaceholder: false, isLeaf: true },
   123            { width: 1, path: ["e"], data: "e", isCollapsed: false, isPlaceholder: true, isLeaf: false },
   124          ],
   125        ];
   126        const actualLayoutCollapseE = layoutTreeHorizontal(tree, [["e"]]);
   127        assert.deepEqual(actualLayoutCollapseE, expectedLayoutCollapseE);
   128  
   129        // Collapse e and b:
   130        // |     a     |
   131        // |  b  |  e  |
   132        const expectedLayoutCollapseBE: LayoutCell<string>[][] = [
   133          [ { width: 2, data: "a", path: [], isCollapsed: false, isPlaceholder: false, isLeaf: false } ],
   134          [ { width: 1, path: ["b"], data: "b", isCollapsed: true, isPlaceholder: false, isLeaf: false },
   135            { width: 1, path: ["e"], data: "e", isCollapsed: true, isPlaceholder: false, isLeaf: false },
   136          ],
   137        ];
   138        const actualLayoutCollapseBE = layoutTreeHorizontal(tree, [["b"], ["e"]]);
   139        assert.deepEqual(actualLayoutCollapseBE, expectedLayoutCollapseBE);
   140  
   141      });
   142  
   143    });
   144  
   145    describe("flatten", () => {
   146  
   147      const tree = {
   148        name: "a", data: "a",
   149        children: [
   150          { name: "b", data: "b",
   151            children: [
   152              { name: "c", data: "c" },
   153              { name: "d", data: "d" },
   154            ],
   155          },
   156          {
   157            name: "e", data: "e",
   158            children: [
   159              { name: "f", data: "f" },
   160              { name: "g", data: "g" },
   161            ],
   162          },
   163        ],
   164      };
   165  
   166      describe("with includeNodes = true", () => {
   167  
   168        it("lays out a tree with nothing collapsed", () => {
   169          const actualFlattened = flatten(tree, [], true);
   170          const expectedFlattened = [
   171            { depth: 0, isLeaf: false, isCollapsed: false, data: "a", path: [] },
   172            { depth: 1, isLeaf: false, isCollapsed: false, data: "b", path: ["b"] },
   173            { depth: 2, isLeaf: true, isCollapsed: false, data: "c", path: ["b", "c"] },
   174            { depth: 2, isLeaf: true, isCollapsed: false, data: "d", path: ["b", "d"] },
   175            { depth: 1, isLeaf: false, isCollapsed: false, data: "e", path: ["e"] },
   176            { depth: 2, isLeaf: true, isCollapsed: false, data: "f", path: ["e", "f"] },
   177            { depth: 2, isLeaf: true, isCollapsed: false, data: "g", path: ["e", "g"] },
   178          ];
   179  
   180          assert.deepEqual(actualFlattened, expectedFlattened);
   181        });
   182  
   183        it("lays out a tree with a node collapsed", () => {
   184          const actualFlattened = flatten(tree, [["b"]], true);
   185          const expectedFlattened = [
   186            { depth: 0, isLeaf: false, isCollapsed: false, data: "a", path: [] },
   187            { depth: 1, isLeaf: false, isCollapsed: true, data: "b", path: ["b"] },
   188            { depth: 1, isLeaf: false, isCollapsed: false, data: "e", path: ["e"] },
   189            { depth: 2, isLeaf: true, isCollapsed: false, data: "f", path: ["e", "f"] },
   190            { depth: 2, isLeaf: true, isCollapsed: false, data: "g", path: ["e", "g"] },
   191          ];
   192  
   193          assert.deepEqual(actualFlattened, expectedFlattened);
   194        });
   195  
   196      });
   197  
   198      describe("with includeNodes = false", () => {
   199  
   200        it("lays out a tree with nothing collapsed", () => {
   201          const actualFlattened = flatten(tree, [], false);
   202          const expectedFlattened = [
   203            { depth: 2, isLeaf: true, isCollapsed: false, data: "c", path: ["b", "c"] },
   204            { depth: 2, isLeaf: true, isCollapsed: false, data: "d", path: ["b", "d"] },
   205            { depth: 2, isLeaf: true, isCollapsed: false, data: "f", path: ["e", "f"] },
   206            { depth: 2, isLeaf: true, isCollapsed: false, data: "g", path: ["e", "g"] },
   207          ];
   208  
   209          assert.deepEqual(actualFlattened, expectedFlattened);
   210        });
   211  
   212        it("lays out a tree with a node collapsed", () => {
   213          const actualFlattened = flatten(tree, [["b"]], false);
   214          const expectedFlattened = [
   215            { depth: 1, isLeaf: false, isCollapsed: true, data: "b", path: ["b"] },
   216            { depth: 2, isLeaf: true, isCollapsed: false, data: "f", path: ["e", "f"] },
   217            { depth: 2, isLeaf: true, isCollapsed: false, data: "g", path: ["e", "g"] },
   218          ];
   219  
   220          assert.deepEqual(actualFlattened, expectedFlattened);
   221        });
   222  
   223      });
   224  
   225    });
   226  
   227    describe("sumValuesUnderPaths", () => {
   228  
   229      // |       |    C_1    |
   230      // |       | C_2 | C_3 |
   231      // |-------|-----|-----|
   232      // | R_a   |     |     |
   233      // |   R_b |  1  |  2  |
   234      // |   R_c |  3  |  4  |
   235  
   236      const rowTree = {
   237        name: "a",
   238        children: [
   239          { name: "b" },
   240          { name: "c" },
   241        ],
   242      };
   243      const colTree = {
   244        name: "1",
   245        children: [
   246          { name: "2" },
   247          { name: "3" },
   248        ],
   249      };
   250      // by row, then col.
   251      const values: {[name: string]: {[name: string]: number}} = {
   252        "b": {"2": 1, "3": 2},
   253        "c": {"2": 3, "3": 4},
   254      };
   255      function getValue(rowPath: TreePath, colPath: TreePath): number {
   256        return values[rowPath[0]][colPath[0]];
   257      }
   258  
   259      it("computes a sum for the roots of both trees", () => {
   260        const actualSum = sumValuesUnderPaths(rowTree, colTree, [], [], getValue);
   261        const expectedSum = 1 + 2 + 3 + 4;
   262        assert.equal(actualSum, expectedSum);
   263      });
   264  
   265      it("computes a sum for the root of one tree and the leaf of another", () => {
   266        const actualSum = sumValuesUnderPaths(rowTree, colTree, ["b"], [], getValue);
   267        const expectedSum = 1 + 2;
   268        assert.equal(actualSum, expectedSum);
   269      });
   270  
   271      it("computes a sum for a single cell (two leaves)", () => {
   272        const actualSum = sumValuesUnderPaths(rowTree, colTree, ["b"], ["3"], getValue);
   273        const expectedSum = 2;
   274        assert.equal(actualSum, expectedSum);
   275      });
   276  
   277    });
   278  
   279  });