Skip to content

Commit

Permalink
fix: board list labels
Browse files Browse the repository at this point in the history
  • Loading branch information
Akos Kitta committed Aug 14, 2023
1 parent 42b8175 commit db6a68e
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 12 deletions.
38 changes: 26 additions & 12 deletions arduino-ide-extension/src/common/protocol/board-list.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { nls } from '@theia/core/lib/common/nls';
import type { Mutable } from '@theia/core/lib/common/types';
import type { Defined } from '../types';
import { naturalCompare } from '../utils';
Expand All @@ -20,6 +19,8 @@ import {
selectBoard,
unconfirmedBoard,
unknownBoard,
notConnected,
boardIdentifierLabel,
} from './boards-service';

/**
Expand Down Expand Up @@ -257,23 +258,32 @@ export interface BoardListLabels {

function createBoardListLabels(
boardsConfig: BoardsConfig,
allPorts: readonly DetectedPort[],
selectedItem: BoardListItem | undefined
): BoardListLabels {
const { selectedBoard, selectedPort } = boardsConfig;
const boardLabel = selectedBoard?.name || selectBoard;
const boardFqbn = selectedBoard?.fqbn;
let tooltip = `${boardLabel}${boardFqbn ? ` (${boardFqbn})` : ''}${
selectedPort ? `\n${selectedPort.address}` : ''
}`;
if (selectedPort && !selectedItem) {
tooltip += ` ${nls.localize(
'arduino/common/notConnected',
'[not connected]'
)}`;
let tooltip = '';
if (!selectedBoard && !selectedPort) {
tooltip = selectBoard;
} else {
if (selectedBoard) {
tooltip += boardIdentifierLabel(selectedBoard);
}
if (selectedPort) {
if (tooltip) {
tooltip += '\n';
}
tooltip += selectedPort.address;
const index = findMatchingPortIndex(selectedPort, allPorts);
if (index < 0) {
tooltip += ` ${notConnected}`;
}
}
}
return {
boardLabel,
portProtocol: selectedPort?.protocol,
portProtocol: selectedBoard ? selectedPort?.protocol : undefined,
tooltip,
selected: Boolean(selectedItem),
};
Expand Down Expand Up @@ -407,9 +417,13 @@ export function createBoardList(
}
items.sort(boardListItemComparator);
const selectedIndex = findSelectedIndex(boardsConfig, items);
const labels = createBoardListLabels(boardsConfig, items[selectedIndex]);
const boards = collectBoards(items);
const allPorts = collectPorts(items, detectedPorts);
const labels = createBoardListLabels(
boardsConfig,
allPorts,
items[selectedIndex]
);
return {
labels,
items,
Expand Down
4 changes: 4 additions & 0 deletions arduino-ide-extension/src/common/protocol/boards-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,10 @@ export const selectBoard = nls.localize(
'arduino/board/selectBoard',
'Select Board'
);
export const notConnected = nls.localize(
'arduino/common/notConnected',
'[not connected]'
);

/**
* The returned promise resolves to a `BoardInfo` if available to show in the UI or an info message explaining why showing the board info is not possible.
Expand Down
147 changes: 147 additions & 0 deletions arduino-ide-extension/src/test/common/board-list.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect } from 'chai';
import {
BoardListLabels,
createBoardList,
EditBoardsConfigActionParams,
isInferredBoardListItem,
Expand All @@ -8,6 +9,8 @@ import {
} from '../../common/protocol/board-list';
import {
emptyBoardsConfig,
notConnected,
selectBoard,
unconfirmedBoard,
} from '../../common/protocol/boards-service';
import {
Expand All @@ -22,6 +25,7 @@ import {
esp32S3DevModule,
history,
mkr1000,
mkr1000NetworkPort,
mkr1000SerialPort,
nanoEsp32DetectsMultipleEsp32BoardsSerialPort,
nanoEsp32SerialPort,
Expand All @@ -32,6 +36,149 @@ import {
} from './fixtures';

describe('board-list', () => {
describe('boardList#labels', () => {
it('should handle no selected board+port', () => {
const { labels } = createBoardList({});
const expected: BoardListLabels = {
boardLabel: selectBoard,
portProtocol: undefined,
selected: false,
tooltip: selectBoard,
};
expect(labels).to.be.deep.equal(expected);
});

it('should handle port selected (port discovered)', () => {
const { labels } = createBoardList(
{
...detectedPort(unoSerialPort, uno),
},
{ selectedBoard: undefined, selectedPort: unoSerialPort }
);
const expected: BoardListLabels = {
boardLabel: selectBoard,
portProtocol: undefined,
selected: false,
tooltip: unoSerialPort.address,
};
expect(labels).to.be.deep.equal(expected);
});

it('should handle port selected (port not discovered)', () => {
const { labels } = createBoardList(
{
...detectedPort(mkr1000SerialPort, mkr1000),
},
{ selectedBoard: undefined, selectedPort: unoSerialPort }
);
const expected: BoardListLabels = {
boardLabel: selectBoard,
portProtocol: undefined,
selected: false,
tooltip: `${unoSerialPort.address} ${notConnected}`,
};
expect(labels).to.be.deep.equal(expected);
});

it('should handle board selected (with FQBN)', () => {
const { labels } = createBoardList(
{},
{ selectedBoard: uno, selectedPort: undefined }
);
const expected: BoardListLabels = {
boardLabel: uno.name,
portProtocol: undefined,
selected: false,
tooltip: `${uno.name} (${uno.fqbn})`,
};
expect(labels).to.be.deep.equal(expected);
});

it('should handle board selected (no FQBN)', () => {
const { labels } = createBoardList(
{},
{
selectedBoard: { name: 'my board', fqbn: undefined },
selectedPort: undefined,
}
);
const expected: BoardListLabels = {
boardLabel: 'my board',
portProtocol: undefined,
selected: false,
tooltip: 'my board',
};
expect(labels).to.be.deep.equal(expected);
});

it('should handle both selected (port not detected)', () => {
const { labels } = createBoardList(
{
...detectedPort(mkr1000SerialPort, mkr1000),
},
{ selectedBoard: mkr1000, selectedPort: unoSerialPort }
);
const expected: BoardListLabels = {
boardLabel: mkr1000.name,
portProtocol: 'serial',
selected: false,
tooltip: `${mkr1000.name} (${mkr1000.fqbn})\n${unoSerialPort.address} ${notConnected}`,
};
expect(labels).to.be.deep.equal(expected);
});

it('should handle both selected (board not discovered)', () => {
const { labels } = createBoardList(
{
...detectedPort(unoSerialPort, uno),
},
{ selectedBoard: mkr1000, selectedPort: unoSerialPort }
);
const expected: BoardListLabels = {
boardLabel: mkr1000.name,
portProtocol: 'serial',
selected: false,
tooltip: `${mkr1000.name} (${mkr1000.fqbn})\n${unoSerialPort.address}`,
};
expect(labels).to.be.deep.equal(expected);
});

it('should handle both selected (no FQBN)', () => {
const { labels } = createBoardList(
{
...detectedPort(unoSerialPort, { name: 'my board', fqbn: undefined }),
},
{
selectedBoard: { name: 'my board', fqbn: undefined },
selectedPort: unoSerialPort,
}
);
const expected: BoardListLabels = {
boardLabel: 'my board',
portProtocol: 'serial',
selected: true,
tooltip: `my board\n${unoSerialPort.address}`,
};
expect(labels).to.be.deep.equal(expected);
});

it('should handle both selected', () => {
const { labels } = createBoardList(
{
...detectedPort(mkr1000NetworkPort, mkr1000),
},
{ selectedBoard: mkr1000, selectedPort: mkr1000NetworkPort }
);
const expected: BoardListLabels = {
boardLabel: mkr1000.name,
portProtocol: 'network',
selected: true,
tooltip: `${mkr1000.name} (${mkr1000.fqbn})\n${mkr1000NetworkPort.address}`,
};
expect(labels).to.be.deep.equal(expected);
});
});

describe('createBoardList', () => {
it('should sort the items deterministically', () => {
const { items } = createBoardList(detectedPorts);
Expand Down
108 changes: 108 additions & 0 deletions arduino-ide-extension/src/test/common/boards-service.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { Mutable } from '@theia/core/lib/common/types';
import { expect } from 'chai';
import {
boardIdentifierEquals,
boardIdentifierComparator,
BoardInfo,
getBoardInfo,
noNativeSerialPort,
Expand All @@ -13,6 +15,112 @@ import { createBoardList } from '../../common/protocol/board-list';
import { firstToUpperCase } from '../../common/utils';

describe('boards-service', () => {
describe('boardIdentifierEquals', () => {
it('should not be equal when the names equal but the FQBNs are different', () => {
const actual = boardIdentifierEquals(
{ name: 'a', fqbn: 'a:b:c' },
{ name: 'a', fqbn: 'x:y:z' }
);
expect(actual).to.be.false;
});

it('should not be equal when the names equal but the FQBNs are different (undefined)', () => {
const actual = boardIdentifierEquals(
{ name: 'a', fqbn: 'a:b:c' },
{ name: 'a', fqbn: undefined }
);
expect(actual).to.be.false;
});

it("should be equal when the names do not match but the FQBNs are the same (it's something IDE2 assumes to be handled by the platform or CLI)", () => {
const actual = boardIdentifierEquals(
{ name: 'a', fqbn: 'a:b:c' },
{ name: 'b', fqbn: 'a:b:c' }
);
expect(actual).to.be.true;
});

it('should be equal when the names equal and the FQBNs are missing', () => {
const actual = boardIdentifierEquals(
{ name: 'a', fqbn: undefined },
{ name: 'a', fqbn: undefined }
);
expect(actual).to.be.true;
});

it('should be equal when both the name and FQBN are the same, but one of the FQBN has board config options', () => {
const actual = boardIdentifierEquals(
{ name: 'a', fqbn: 'a:b:c:menu_1=value' },
{ name: 'a', fqbn: 'a:b:c' }
);
expect(actual).to.be.true;
});

it('should not be equal when both the name and FQBN are the same, but one of the FQBN has board config options (looseFqbn: false)', () => {
const actual = boardIdentifierEquals(
{ name: 'a', fqbn: 'a:b:c:menu_1=value' },
{ name: 'a', fqbn: 'a:b:c' },
{ looseFqbn: false }
);
expect(actual).to.be.false;
});
});

describe('boardIdentifierComparator', () => {
it('should sort items before falsy', () =>
expect(
boardIdentifierComparator({ name: 'a', fqbn: 'a:b:c' }, undefined)
).to.be.equal(-1));

it("should sort 'arduino' boards before others", () =>
expect(
boardIdentifierComparator(
{ name: 'b', fqbn: 'arduino:b:c' },
{ name: 'a', fqbn: 'x:y:z' }
)
).to.be.equal(-1));

it("should sort 'arduino' boards before others (other is falsy)", () =>
expect(
boardIdentifierComparator(
{ name: 'b', fqbn: 'arduino:b:c' },
{ name: 'a', fqbn: undefined }
)
).to.be.equal(-1));

it("should sort boards by 'name' (with FQBNs)", () =>
expect(
boardIdentifierComparator(
{ name: 'b', fqbn: 'a:b:c' },
{ name: 'a', fqbn: 'x:y:z' }
)
).to.be.equal(1));

it("should sort boards by 'name' (no FQBNs)", () =>
expect(
boardIdentifierComparator(
{ name: 'b', fqbn: undefined },
{ name: 'a', fqbn: undefined }
)
).to.be.equal(1));

it("should sort boards by 'name' (one FQBN)", () =>
expect(
boardIdentifierComparator(
{ name: 'b', fqbn: 'a:b:c' },
{ name: 'a', fqbn: undefined }
)
).to.be.equal(1));

it("should sort boards by 'name' (both 'arduino' vendor)", () =>
expect(
boardIdentifierComparator(
{ name: 'b', fqbn: 'arduino:b:c' },
{ name: 'a', fqbn: 'arduino:y:z' }
)
).to.be.equal(1));
});

describe('getBoardInfo', () => {
const vid = '0x0';
const pid = '0x1';
Expand Down

0 comments on commit db6a68e

Please sign in to comment.