5.5 KB204 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {UseUncommittedSelection} from '../partialSelection';
9import type {PathTree} from '../pathTree';
10
11import {buildPathTree, calculateTreeSelectionStates} from '../pathTree';
12
13type FakeData = {name: string};
14describe('pathTree', () => {
15 it('constructs tree', () => {
16 const tree = buildPathTree<FakeData>({
17 'a/b/file1.txt': {name: 'file1.txt'},
18 'a/b/file2.txt': {name: 'file2.txt'},
19 'a/file3.txt': {name: 'file3.txt'},
20 'a/d/e/f/file4.txt': {name: 'file4.txt'},
21 'q/file5.txt': {name: 'file5.txt'},
22 'file6.txt': {name: 'file5.txt'},
23 });
24
25 expect(tree).toEqual(
26 testTree([
27 [
28 'a',
29 [
30 [
31 'b',
32 [
33 ['file1.txt', {name: 'file1.txt'}],
34 ['file2.txt', {name: 'file2.txt'}],
35 ],
36 ],
37 ['file3.txt', {name: 'file3.txt'}],
38 ['d/e/f', [['file4.txt', {name: 'file4.txt'}]]],
39 ],
40 ],
41 ['q', [['file5.txt', {name: 'file5.txt'}]]],
42 ['file6.txt', {name: 'file5.txt'}],
43 ]),
44 );
45 });
46
47 it('groups out of order elements tree', () => {
48 const tree = buildPathTree<FakeData>({
49 'a/b/file1.txt': {name: 'file1.txt'},
50 'file6.txt': {name: 'file5.txt'},
51 'a/file3.txt': {name: 'file3.txt'},
52 'a/d/e/f/file4.txt': {name: 'file4.txt'},
53 'q/file5.txt': {name: 'file5.txt'},
54 'a/b/file2.txt': {name: 'file2.txt'},
55 });
56
57 expect(tree).toEqual(
58 testTree([
59 [
60 'a',
61 [
62 [
63 'b',
64 [
65 ['file1.txt', {name: 'file1.txt'}],
66 ['file2.txt', {name: 'file2.txt'}],
67 ],
68 ],
69 ['file3.txt', {name: 'file3.txt'}],
70 ['d/e/f', [['file4.txt', {name: 'file4.txt'}]]],
71 ],
72 ],
73 ['q', [['file5.txt', {name: 'file5.txt'}]]],
74 ['file6.txt', {name: 'file5.txt'}],
75 ]),
76 );
77 });
78
79 it('groups with condensed prefixes', () => {
80 const tree = buildPathTree<FakeData>({
81 'a/b/file1.txt': {name: 'file1.txt'},
82 'a/b/file2.txt': {name: 'file2.txt'},
83 'a/b/c/d/e/file3.txt': {name: 'file3.txt'},
84 'a/b/c/d/e/file4.txt': {name: 'file4.txt'},
85 });
86
87 expect(tree).toEqual(
88 testTree([
89 [
90 'a/b',
91 [
92 ['file1.txt', {name: 'file1.txt'}],
93 ['file2.txt', {name: 'file2.txt'}],
94 [
95 'c/d/e',
96 [
97 ['file3.txt', {name: 'file3.txt'}],
98 ['file4.txt', {name: 'file4.txt'}],
99 ],
100 ],
101 ],
102 ],
103 ]),
104 );
105 });
106
107 it('testtree util works', () => {
108 expect(
109 testTree([
110 [
111 'a',
112 [
113 [
114 'b',
115 [
116 ['file1.txt', {name: 'file1.txt'}],
117 ['file2.txt', {name: 'file2.txt'}],
118 ],
119 ],
120 ['file3.txt', {name: 'file3.txt'}],
121 ],
122 ],
123 ['file4.txt', {name: 'file4.txt'}],
124 ]),
125 ).toEqual(
126 new Map<string, FakeData | Map<string, FakeData | Map<string, FakeData>>>([
127 [
128 'a',
129 new Map<string, FakeData | Map<string, FakeData>>([
130 [
131 'b',
132 new Map([
133 ['file1.txt', {name: 'file1.txt'}],
134 ['file2.txt', {name: 'file2.txt'}],
135 ]),
136 ],
137 ['file3.txt', {name: 'file3.txt'}],
138 ]),
139 ],
140 ['file4.txt', {name: 'file4.txt'}],
141 ]),
142 );
143 });
144});
145
146type Data = Array<[string, Data | FakeData]>;
147// make testing slightly easier so we don't need to construct maps in expected result
148function testTree(data: Data): PathTree<FakeData> {
149 return new Map(
150 data.map(([k, v]): [string, FakeData | PathTree<FakeData>] =>
151 Array.isArray(v) ? [k, testTree(v)] : [k, v],
152 ),
153 );
154}
155
156describe('calculateTreeSelectionStates', () => {
157 it('computes selection states', () => {
158 const selection = {
159 isFullySelected: (path: string) => {
160 switch (path) {
161 case 'file1.txt':
162 case 'file2.txt':
163 case 'file3.txt':
164 case 'file5.txt':
165 return true;
166 default:
167 return false;
168 }
169 },
170 isFullyOrPartiallySelected: (path: string) => {
171 switch (path) {
172 case 'file1.txt':
173 case 'file2.txt':
174 case 'file3.txt':
175 case 'file6.txt':
176 return true;
177 default:
178 return false;
179 }
180 },
181 } as UseUncommittedSelection;
182 const tree = buildPathTree<{path: string}>({
183 'a/b/file1.txt': {path: 'file1.txt'}, // checked
184 'a/b/file2.txt': {path: 'file2.txt'}, // checked
185 'a/c/file3.txt': {path: 'file3.txt'}, // checked
186 'a/c/file4.txt': {path: 'file4.txt'}, // UNchecked
187 'a/d/file5.txt': {path: 'file5.txt'}, // checked
188 'a/d/file6.txt': {path: 'file6.txt'}, // partially checked
189 'q/file7.txt': {path: 'file7.txt'}, // UNchecked
190 });
191
192 expect(calculateTreeSelectionStates(tree, selection)).toEqual(
193 new Map<string, boolean | 'indeterminate'>([
194 ['', 'indeterminate'],
195 ['/a', 'indeterminate'],
196 ['/a/b', true],
197 ['/a/c', 'indeterminate'],
198 ['/a/d', 'indeterminate'],
199 ['/q', false],
200 ]),
201 );
202 });
203});
204