Skip to content

Commit 7de7272

Browse files
committed
wip
1 parent a0f32b0 commit 7de7272

File tree

2 files changed

+284
-54
lines changed

2 files changed

+284
-54
lines changed

src/tree/appMapTreeDataProvider.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ const LABEL_NO_NAME = 'Untitled AppMap';
1414
export interface IAppMapTreeItem {
1515
appmap: AppMapLoader | undefined;
1616

17-
parent: IAppMapTreeItem | undefined;
17+
parent: (vscode.TreeItem & IAppMapTreeItem) | undefined;
1818

19-
children: IAppMapTreeItem[];
19+
children: (vscode.TreeItem & IAppMapTreeItem)[];
2020
}
2121

2222
class AppMapFolder {
@@ -139,7 +139,6 @@ class FolderTreeItem extends vscode.TreeItem implements IAppMapTreeItem {
139139
let { recorderType } = folderContent.folder;
140140
if (!recorderType) recorderType = 'unknown recorder type';
141141
const sortFunction = FolderTreeItem.SortMethod[recorderType] || FolderTreeItem.sortByName;
142-
warn(`Sorting ${appmaps.length} appmaps by ${recorderType}`); // TODO: Remove
143142
folderContent.appmaps.sort(sortFunction);
144143

145144
return new FolderTreeItem(workspaceTreeItem, folderContent.folder, folderContent.appmaps);

test/unit/tree/appMapTreeDataProvider.test.ts

Lines changed: 282 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,78 +5,309 @@ import { expect } from 'chai';
55

66
import { AppMapTreeDataProvider, IAppMapTreeItem } from '../../../src/tree/appMapTreeDataProvider';
77
import AppMapCollection from '../../../src/services/appmapCollection';
8-
import { AppmapUptodateService } from '../../../src/services/appmapUptodateService';
98
import AppMapLoader from '../../../src/services/appmapLoader';
9+
import { build } from 'tsup';
1010

1111
describe('AppMapTreeDataProvider', () => {
1212
let sinon: SinonSandbox;
13-
let appmaps: AppMapCollection;
1413
let provider: AppMapTreeDataProvider;
1514

16-
const APPMAPS: AppMapLoader[] = [
17-
{
18-
descriptor: {
19-
metadata: {
20-
language: { name: 'ruby', version: '2.7.2' },
21-
recorder: {
22-
type: 'tests',
23-
name: 'rspec',
15+
beforeEach(() => (sinon = Sinon.createSandbox()));
16+
afterEach(() => sinon.restore());
17+
18+
function findProject(label: string) {
19+
return provider
20+
.getChildren(undefined)
21+
.find((treeItem) => treeItem.label === label) as IAppMapTreeItem & vscode.TreeItem;
22+
}
23+
24+
function getProjectA() {
25+
return findProject('project-a');
26+
}
27+
28+
function getProjectB() {
29+
return findProject('project-b');
30+
}
31+
32+
function buildSingleProjectWorkspace(appmaps: AppMapLoader[]): () => void {
33+
return function () {
34+
sinon.stub(vscode.workspace, 'workspaceFolders').value([
35+
{
36+
index: 0,
37+
name: 'project-a',
38+
uri: vscode.Uri.file('/path/to/project-a'),
39+
},
40+
]);
41+
42+
const appmapCollection = {
43+
appMaps: Sinon.stub().returns(appmaps),
44+
onUpdated: Sinon.stub(),
45+
} as unknown as AppMapCollection;
46+
provider = new AppMapTreeDataProvider(appmapCollection);
47+
};
48+
}
49+
50+
describe('in a single project workspace', () => {
51+
const appmaps: AppMapLoader[] = [
52+
{
53+
descriptor: {
54+
metadata: {
55+
name: 'appmap_1',
56+
language: { name: 'ruby', version: '2.7.2' },
57+
recorder: {
58+
type: 'tests',
59+
name: 'rspec',
60+
},
2461
},
62+
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_1.json'),
2563
},
26-
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_1.json'),
27-
},
28-
} as AppMapLoader,
29-
{
30-
descriptor: {
31-
metadata: {
32-
language: { name: 'ruby', version: '2.7.2' },
33-
recorder: {
34-
type: 'requests',
64+
} as AppMapLoader,
65+
{
66+
descriptor: {
67+
metadata: {
68+
name: 'appmap_2',
69+
language: { name: 'ruby', version: '2.7.2' },
70+
recorder: {
71+
type: 'requests',
72+
},
3573
},
74+
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_2.json'),
3675
},
37-
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_2.json'),
38-
},
39-
} as AppMapLoader,
40-
];
76+
} as AppMapLoader,
77+
];
4178

42-
beforeEach(() => (sinon = Sinon.createSandbox()));
43-
afterEach(() => sinon.restore());
79+
beforeEach(buildSingleProjectWorkspace(appmaps));
4480

45-
beforeEach(() => {
46-
sinon.stub(vscode.workspace, 'workspaceFolders').value([
47-
{
48-
index: 0,
49-
name: 'project-a',
50-
uri: vscode.Uri.file('/path/to/project-a'),
51-
},
52-
]);
53-
54-
appmaps = {
55-
appMaps: Sinon.stub().returns(APPMAPS),
56-
onUpdated: Sinon.stub(),
57-
} as unknown as AppMapCollection;
58-
provider = new AppMapTreeDataProvider(appmaps);
81+
describe('getRootElements', () => {
82+
it('returns the single workspace', async () => {
83+
const roots = provider.getChildren(undefined);
84+
expect(roots.map((item) => item.label)).to.deep.equal(['project-a']);
85+
});
86+
});
87+
88+
describe('appmap folders', () => {
89+
it('exist for each recording type', () => {
90+
const project = getProjectA();
91+
const folderItems = provider.getChildren(project);
92+
expect(folderItems.map((item) => item.label)).to.deep.equal([
93+
'Requests (ruby)',
94+
'Tests (ruby + rspec)',
95+
]);
96+
});
97+
98+
describe('for request recordings', () => {
99+
it('are sorted by timestamp', () => {});
100+
});
101+
102+
describe('for test recordings', () => {
103+
it('are sorted by name', () => {});
104+
});
105+
});
106+
107+
describe('AppMap items', () => {
108+
function getFolderItem(label: string) {
109+
return getProjectA().children.find((folder) => folder.label === label);
110+
}
111+
112+
it('exist for each AppMap', () => {
113+
{
114+
const folderItem = getFolderItem('Tests (ruby + rspec)');
115+
const appmapItems = provider.getChildren(folderItem);
116+
expect(appmapItems.map((item) => item.label)).to.deep.equal(['appmap_1']);
117+
}
118+
{
119+
const folderItem = getFolderItem('Requests (ruby)');
120+
const appmapItems = provider.getChildren(folderItem);
121+
expect(appmapItems.map((item) => item.label)).to.deep.equal(['appmap_2']);
122+
}
123+
});
124+
});
59125
});
60126

61-
describe('getRootElement', () => {
62-
it('returns the root element', async () => {
63-
const roots = provider.getChildren(undefined);
64-
expect(roots.map((item) => item.label)).to.deep.equal(['project-a']);
127+
describe('requests recordings', () => {
128+
function requestRecording(name: string, timestamp: number): AppMapLoader {
129+
return {
130+
descriptor: {
131+
metadata: {
132+
name,
133+
timestamp,
134+
language: { name: 'ruby', version: '2.7.2' },
135+
recorder: {
136+
type: 'requests',
137+
},
138+
},
139+
timestamp,
140+
resourceUri: vscode.Uri.file(`/path/to/project-a/tmp/appmap/${name}.json`),
141+
},
142+
} as unknown as AppMapLoader;
143+
}
144+
145+
const appmaps: AppMapLoader[] = [
146+
requestRecording('appmap_1', 1),
147+
requestRecording('appmap_2', 3),
148+
requestRecording('appmap_3', 5),
149+
requestRecording('appmap_4', 6),
150+
requestRecording('appmap_5', 4),
151+
requestRecording('appmap_6', 2),
152+
];
153+
154+
beforeEach(buildSingleProjectWorkspace(appmaps));
155+
156+
it('are sorted by timestamp with most recent first', () => {
157+
const project = getProjectA();
158+
const folderItems = provider.getChildren(project);
159+
const appmapItems = provider.getChildren(folderItems[0]);
160+
expect(appmapItems.map((item) => item.label)).to.deep.equal([
161+
'appmap_4',
162+
'appmap_3',
163+
'appmap_5',
164+
'appmap_2',
165+
'appmap_6',
166+
'appmap_1',
167+
]);
65168
});
66169
});
67170

68-
describe('Project folder items', () => {
69-
function getProject() {
70-
return provider.getChildren(undefined)[0] as IAppMapTreeItem & vscode.TreeItem;
171+
describe('tests recordings', () => {
172+
function testRecording(name: string, timestamp: number): AppMapLoader {
173+
return {
174+
descriptor: {
175+
metadata: {
176+
name,
177+
timestamp,
178+
language: { name: 'ruby', version: '2.7.2' },
179+
recorder: {
180+
type: 'tests',
181+
name: 'rspec',
182+
},
183+
},
184+
timestamp,
185+
resourceUri: vscode.Uri.file(`/path/to/project-a/tmp/appmap/${name}.json`),
186+
},
187+
} as unknown as AppMapLoader;
71188
}
72189

73-
it('exist for each recording type', () => {
74-
const project = getProject();
190+
const appmaps: AppMapLoader[] = [
191+
testRecording('appmap_4', 6),
192+
testRecording('appmap_1', 1),
193+
testRecording('appmap_5', 4),
194+
testRecording('appmap_2', 3),
195+
testRecording('appmap_3', 5),
196+
testRecording('appmap_6', 2),
197+
];
198+
199+
beforeEach(buildSingleProjectWorkspace(appmaps));
200+
201+
it('are sorted alphabetically by label', () => {
202+
const project = getProjectA();
203+
const folderItems = provider.getChildren(project);
204+
const appmapItems = provider.getChildren(folderItems[0]);
205+
expect(appmapItems.map((item) => item.label)).to.deep.equal([
206+
'appmap_1',
207+
'appmap_2',
208+
'appmap_3',
209+
'appmap_4',
210+
'appmap_5',
211+
'appmap_6',
212+
]);
213+
});
214+
});
215+
216+
describe('missing appmap metadata', () => {
217+
const appmaps: AppMapLoader[] = [
218+
{
219+
descriptor: {
220+
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_1.json'),
221+
},
222+
} as AppMapLoader,
223+
{
224+
descriptor: {
225+
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_2.json'),
226+
},
227+
} as AppMapLoader,
228+
];
229+
230+
beforeEach(buildSingleProjectWorkspace(appmaps));
231+
232+
it('is replaced with suitable defaults', () => {
233+
const project = getProjectA();
75234
const folderItems = provider.getChildren(project);
76-
expect(folderItems.map((item) => item.label)).to.deep.equal([
77-
'Requests (ruby)',
78-
'Tests (ruby + rspec)',
235+
expect(folderItems.map((item) => item.label)).to.deep.equal(['unspecified language']);
236+
const appmapItems = provider.getChildren(folderItems[0]);
237+
expect(appmapItems.map((item) => item.label)).to.deep.equal([
238+
'Untitled AppMap',
239+
'Untitled AppMap',
79240
]);
80241
});
81242
});
243+
244+
describe('in a multi-project workspace', () => {
245+
const appmaps: AppMapLoader[] = [
246+
{
247+
descriptor: {
248+
metadata: {
249+
name: 'appmap_1',
250+
language: { name: 'ruby', version: '2.7.2' },
251+
recorder: {
252+
type: 'tests',
253+
name: 'rspec',
254+
},
255+
},
256+
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_1.json'),
257+
},
258+
} as AppMapLoader,
259+
{
260+
descriptor: {
261+
metadata: {
262+
name: 'appmap_2',
263+
language: { name: 'ruby', version: '2.7.2' },
264+
recorder: {
265+
type: 'requests',
266+
},
267+
},
268+
resourceUri: vscode.Uri.file('/path/to/project-b/tmp/appmap/appmap_2.json'),
269+
},
270+
} as AppMapLoader,
271+
];
272+
273+
beforeEach(() => {
274+
sinon.stub(vscode.workspace, 'workspaceFolders').value([
275+
{
276+
index: 0,
277+
name: 'project-a',
278+
uri: vscode.Uri.file('/path/to/project-a'),
279+
},
280+
{
281+
index: 1,
282+
name: 'project-b',
283+
uri: vscode.Uri.file('/path/to/project-b'),
284+
},
285+
]);
286+
287+
const appmapCollection = {
288+
appMaps: Sinon.stub().returns(appmaps),
289+
onUpdated: Sinon.stub(),
290+
} as unknown as AppMapCollection;
291+
provider = new AppMapTreeDataProvider(appmapCollection);
292+
});
293+
294+
describe('appmap folders', () => {
295+
it('are placed in the proper projects', () => {
296+
{
297+
const project = getProjectA();
298+
const folderItems = provider.getChildren(project);
299+
expect(folderItems.map((item) => item.label)).to.deep.equal(['Tests (ruby + rspec)']);
300+
const appmapItems = provider.getChildren(folderItems[0]);
301+
expect(appmapItems.map((item) => item.label)).to.deep.equal(['appmap_1']);
302+
}
303+
{
304+
const project = getProjectB();
305+
const folderItems = provider.getChildren(project);
306+
expect(folderItems.map((item) => item.label)).to.deep.equal(['Requests (ruby)']);
307+
const appmapItems = provider.getChildren(folderItems[0]);
308+
expect(appmapItems.map((item) => item.label)).to.deep.equal(['appmap_2']);
309+
}
310+
});
311+
});
312+
});
82313
});

0 commit comments

Comments
 (0)