Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kgilpin committed Apr 1, 2024
1 parent a0f32b0 commit 7de7272
Show file tree
Hide file tree
Showing 2 changed files with 284 additions and 54 deletions.
5 changes: 2 additions & 3 deletions src/tree/appMapTreeDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ const LABEL_NO_NAME = 'Untitled AppMap';
export interface IAppMapTreeItem {
appmap: AppMapLoader | undefined;

parent: IAppMapTreeItem | undefined;
parent: (vscode.TreeItem & IAppMapTreeItem) | undefined;

children: IAppMapTreeItem[];
children: (vscode.TreeItem & IAppMapTreeItem)[];
}

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

return new FolderTreeItem(workspaceTreeItem, folderContent.folder, folderContent.appmaps);
Expand Down
333 changes: 282 additions & 51 deletions test/unit/tree/appMapTreeDataProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,78 +5,309 @@ import { expect } from 'chai';

import { AppMapTreeDataProvider, IAppMapTreeItem } from '../../../src/tree/appMapTreeDataProvider';
import AppMapCollection from '../../../src/services/appmapCollection';
import { AppmapUptodateService } from '../../../src/services/appmapUptodateService';
import AppMapLoader from '../../../src/services/appmapLoader';
import { build } from 'tsup';

Check warning on line 9 in test/unit/tree/appMapTreeDataProvider.test.ts

View workflow job for this annotation

GitHub Actions / prepare

'build' is defined but never used

describe('AppMapTreeDataProvider', () => {
let sinon: SinonSandbox;
let appmaps: AppMapCollection;
let provider: AppMapTreeDataProvider;

const APPMAPS: AppMapLoader[] = [
{
descriptor: {
metadata: {
language: { name: 'ruby', version: '2.7.2' },
recorder: {
type: 'tests',
name: 'rspec',
beforeEach(() => (sinon = Sinon.createSandbox()));
afterEach(() => sinon.restore());

function findProject(label: string) {
return provider
.getChildren(undefined)
.find((treeItem) => treeItem.label === label) as IAppMapTreeItem & vscode.TreeItem;
}

function getProjectA() {
return findProject('project-a');
}

function getProjectB() {
return findProject('project-b');
}

function buildSingleProjectWorkspace(appmaps: AppMapLoader[]): () => void {
return function () {
sinon.stub(vscode.workspace, 'workspaceFolders').value([
{
index: 0,
name: 'project-a',
uri: vscode.Uri.file('/path/to/project-a'),
},
]);

const appmapCollection = {
appMaps: Sinon.stub().returns(appmaps),
onUpdated: Sinon.stub(),
} as unknown as AppMapCollection;
provider = new AppMapTreeDataProvider(appmapCollection);
};
}

describe('in a single project workspace', () => {
const appmaps: AppMapLoader[] = [
{
descriptor: {
metadata: {
name: 'appmap_1',
language: { name: 'ruby', version: '2.7.2' },
recorder: {
type: 'tests',
name: 'rspec',
},
},
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_1.json'),
},
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_1.json'),
},
} as AppMapLoader,
{
descriptor: {
metadata: {
language: { name: 'ruby', version: '2.7.2' },
recorder: {
type: 'requests',
} as AppMapLoader,
{
descriptor: {
metadata: {
name: 'appmap_2',
language: { name: 'ruby', version: '2.7.2' },
recorder: {
type: 'requests',
},
},
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_2.json'),
},
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_2.json'),
},
} as AppMapLoader,
];
} as AppMapLoader,
];

beforeEach(() => (sinon = Sinon.createSandbox()));
afterEach(() => sinon.restore());
beforeEach(buildSingleProjectWorkspace(appmaps));

beforeEach(() => {
sinon.stub(vscode.workspace, 'workspaceFolders').value([
{
index: 0,
name: 'project-a',
uri: vscode.Uri.file('/path/to/project-a'),
},
]);

appmaps = {
appMaps: Sinon.stub().returns(APPMAPS),
onUpdated: Sinon.stub(),
} as unknown as AppMapCollection;
provider = new AppMapTreeDataProvider(appmaps);
describe('getRootElements', () => {
it('returns the single workspace', async () => {
const roots = provider.getChildren(undefined);
expect(roots.map((item) => item.label)).to.deep.equal(['project-a']);
});
});

describe('appmap folders', () => {
it('exist for each recording type', () => {
const project = getProjectA();
const folderItems = provider.getChildren(project);
expect(folderItems.map((item) => item.label)).to.deep.equal([
'Requests (ruby)',
'Tests (ruby + rspec)',
]);
});

describe('for request recordings', () => {
it('are sorted by timestamp', () => {});

Check failure on line 99 in test/unit/tree/appMapTreeDataProvider.test.ts

View workflow job for this annotation

GitHub Actions / prepare

Unexpected empty arrow function
});

describe('for test recordings', () => {
it('are sorted by name', () => {});

Check failure on line 103 in test/unit/tree/appMapTreeDataProvider.test.ts

View workflow job for this annotation

GitHub Actions / prepare

Unexpected empty arrow function
});
});

describe('AppMap items', () => {
function getFolderItem(label: string) {
return getProjectA().children.find((folder) => folder.label === label);
}

it('exist for each AppMap', () => {
{
const folderItem = getFolderItem('Tests (ruby + rspec)');
const appmapItems = provider.getChildren(folderItem);
expect(appmapItems.map((item) => item.label)).to.deep.equal(['appmap_1']);
}
{
const folderItem = getFolderItem('Requests (ruby)');
const appmapItems = provider.getChildren(folderItem);
expect(appmapItems.map((item) => item.label)).to.deep.equal(['appmap_2']);
}
});
});
});

describe('getRootElement', () => {
it('returns the root element', async () => {
const roots = provider.getChildren(undefined);
expect(roots.map((item) => item.label)).to.deep.equal(['project-a']);
describe('requests recordings', () => {
function requestRecording(name: string, timestamp: number): AppMapLoader {
return {
descriptor: {
metadata: {
name,
timestamp,
language: { name: 'ruby', version: '2.7.2' },
recorder: {
type: 'requests',
},
},
timestamp,
resourceUri: vscode.Uri.file(`/path/to/project-a/tmp/appmap/${name}.json`),
},
} as unknown as AppMapLoader;
}

const appmaps: AppMapLoader[] = [
requestRecording('appmap_1', 1),
requestRecording('appmap_2', 3),
requestRecording('appmap_3', 5),
requestRecording('appmap_4', 6),
requestRecording('appmap_5', 4),
requestRecording('appmap_6', 2),
];

beforeEach(buildSingleProjectWorkspace(appmaps));

it('are sorted by timestamp with most recent first', () => {
const project = getProjectA();
const folderItems = provider.getChildren(project);
const appmapItems = provider.getChildren(folderItems[0]);
expect(appmapItems.map((item) => item.label)).to.deep.equal([
'appmap_4',
'appmap_3',
'appmap_5',
'appmap_2',
'appmap_6',
'appmap_1',
]);
});
});

describe('Project folder items', () => {
function getProject() {
return provider.getChildren(undefined)[0] as IAppMapTreeItem & vscode.TreeItem;
describe('tests recordings', () => {
function testRecording(name: string, timestamp: number): AppMapLoader {
return {
descriptor: {
metadata: {
name,
timestamp,
language: { name: 'ruby', version: '2.7.2' },
recorder: {
type: 'tests',
name: 'rspec',
},
},
timestamp,
resourceUri: vscode.Uri.file(`/path/to/project-a/tmp/appmap/${name}.json`),
},
} as unknown as AppMapLoader;
}

it('exist for each recording type', () => {
const project = getProject();
const appmaps: AppMapLoader[] = [
testRecording('appmap_4', 6),
testRecording('appmap_1', 1),
testRecording('appmap_5', 4),
testRecording('appmap_2', 3),
testRecording('appmap_3', 5),
testRecording('appmap_6', 2),
];

beforeEach(buildSingleProjectWorkspace(appmaps));

it('are sorted alphabetically by label', () => {
const project = getProjectA();
const folderItems = provider.getChildren(project);
const appmapItems = provider.getChildren(folderItems[0]);
expect(appmapItems.map((item) => item.label)).to.deep.equal([
'appmap_1',
'appmap_2',
'appmap_3',
'appmap_4',
'appmap_5',
'appmap_6',
]);
});
});

describe('missing appmap metadata', () => {
const appmaps: AppMapLoader[] = [
{
descriptor: {
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_1.json'),
},
} as AppMapLoader,
{
descriptor: {
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_2.json'),
},
} as AppMapLoader,
];

beforeEach(buildSingleProjectWorkspace(appmaps));

it('is replaced with suitable defaults', () => {
const project = getProjectA();
const folderItems = provider.getChildren(project);
expect(folderItems.map((item) => item.label)).to.deep.equal([
'Requests (ruby)',
'Tests (ruby + rspec)',
expect(folderItems.map((item) => item.label)).to.deep.equal(['unspecified language']);
const appmapItems = provider.getChildren(folderItems[0]);
expect(appmapItems.map((item) => item.label)).to.deep.equal([
'Untitled AppMap',
'Untitled AppMap',
]);
});
});

describe('in a multi-project workspace', () => {
const appmaps: AppMapLoader[] = [
{
descriptor: {
metadata: {
name: 'appmap_1',
language: { name: 'ruby', version: '2.7.2' },
recorder: {
type: 'tests',
name: 'rspec',
},
},
resourceUri: vscode.Uri.file('/path/to/project-a/tmp/appmap/appmap_1.json'),
},
} as AppMapLoader,
{
descriptor: {
metadata: {
name: 'appmap_2',
language: { name: 'ruby', version: '2.7.2' },
recorder: {
type: 'requests',
},
},
resourceUri: vscode.Uri.file('/path/to/project-b/tmp/appmap/appmap_2.json'),
},
} as AppMapLoader,
];

beforeEach(() => {
sinon.stub(vscode.workspace, 'workspaceFolders').value([
{
index: 0,
name: 'project-a',
uri: vscode.Uri.file('/path/to/project-a'),
},
{
index: 1,
name: 'project-b',
uri: vscode.Uri.file('/path/to/project-b'),
},
]);

const appmapCollection = {
appMaps: Sinon.stub().returns(appmaps),
onUpdated: Sinon.stub(),
} as unknown as AppMapCollection;
provider = new AppMapTreeDataProvider(appmapCollection);
});

describe('appmap folders', () => {
it('are placed in the proper projects', () => {
{
const project = getProjectA();
const folderItems = provider.getChildren(project);
expect(folderItems.map((item) => item.label)).to.deep.equal(['Tests (ruby + rspec)']);
const appmapItems = provider.getChildren(folderItems[0]);
expect(appmapItems.map((item) => item.label)).to.deep.equal(['appmap_1']);
}
{
const project = getProjectB();
const folderItems = provider.getChildren(project);
expect(folderItems.map((item) => item.label)).to.deep.equal(['Requests (ruby)']);
const appmapItems = provider.getChildren(folderItems[0]);
expect(appmapItems.map((item) => item.label)).to.deep.equal(['appmap_2']);
}
});
});
});
});

0 comments on commit 7de7272

Please sign in to comment.