Skip to content

Commit

Permalink
Improve code coverage while fixing an edge case
Browse files Browse the repository at this point in the history
  • Loading branch information
gustavohenke committed Mar 24, 2024
1 parent 6d757e4 commit 67ad002
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 26 deletions.
3 changes: 2 additions & 1 deletion src/completion-listener.spec.ts
Expand Up @@ -47,7 +47,8 @@ describe('listen', () => {

it('completes when abort signal is received and command is stopped, returns nothing', async () => {
const abortCtrl = new AbortController();
const result = createController('all').listen([new FakeCommand()], abortCtrl.signal);
// Use success condition = first to test index access when there are no close events
const result = createController('first').listen([new FakeCommand()], abortCtrl.signal);

abortCtrl.abort();
scheduler.flush();
Expand Down
52 changes: 27 additions & 25 deletions src/completion-listener.ts
Expand Up @@ -47,34 +47,42 @@ export class CompletionListener {
this.scheduler = scheduler;
}

private isSuccess(events: (CloseEvent | undefined)[]) {
private isSuccess(events: CloseEvent[]) {
if (!events.length) {
// When every command was aborted, consider a success.
return true;
}

if (this.successCondition === 'first') {
return isSuccess(events[0]);
return events[0].exitCode === 0;
} else if (this.successCondition === 'last') {
return isSuccess(events[events.length - 1]);
return events[events.length - 1].exitCode === 0;
}

const commandSyntaxMatch = this.successCondition.match(/^!?command-(.+)$/);
if (commandSyntaxMatch == null) {
// If not a `command-` syntax, then it's an 'all' condition or it's treated as such.
return events.every(isSuccess);
return events.every(({ exitCode }) => exitCode === 0);
}

// Check `command-` syntax condition.
// Note that a command's `name` is not necessarily unique,
// in which case all of them must meet the success condition.
const nameOrIndex = commandSyntaxMatch[1];
const targetCommandsEvents = events.filter(
(event) => event?.command.name === nameOrIndex || event?.index === Number(nameOrIndex),
({ command, index }) => command.name === nameOrIndex || index === Number(nameOrIndex),
);
if (this.successCondition.startsWith('!')) {
// All commands except the specified ones must exit successfully
return events.every(
(event) => targetCommandsEvents.includes(event) || isSuccess(event),
(event) => targetCommandsEvents.includes(event) || event.exitCode === 0,
);
}
// Only the specified commands must exit succesfully
return targetCommandsEvents.length > 0 && targetCommandsEvents.every(isSuccess);
return (
targetCommandsEvents.length > 0 &&
targetCommandsEvents.every((event) => event.exitCode === 0)
);
}

/**
Expand Down Expand Up @@ -108,22 +116,20 @@ export class CompletionListener {
(command, i) => command.state !== 'started' || events[i] === undefined,
),
),
map((exitInfos) =>
exitInfos.sort((first, second) => {
if (!first || !second) {
return 0;
}
return first.timings.endDate.getTime() - second.timings.endDate.getTime();
}),
map((events) =>
events
// Filter out aborts, since they cannot be sorted and are considered success condition anyways
.filter((event): event is CloseEvent => event != null)
// Sort according to exit time
.sort(
(first, second) =>
first.timings.endDate.getTime() - second.timings.endDate.getTime(),
),
),
switchMap((events) => {
const success = this.isSuccess(events);
const filteredEvents = events.filter(
(event): event is CloseEvent => event != null,
);
return success
? this.emitWithScheduler(Rx.of(filteredEvents))
: this.emitWithScheduler(Rx.throwError(() => filteredEvents));
return this.isSuccess(events)
? this.emitWithScheduler(Rx.of(events))
: this.emitWithScheduler(Rx.throwError(() => events));
}),
take(1),
),
Expand All @@ -134,7 +140,3 @@ export class CompletionListener {
return this.scheduler ? input.pipe(Rx.observeOn(this.scheduler)) : input;
}
}

function isSuccess(event: CloseEvent | undefined) {
return event == null || event.exitCode === 0;
}

0 comments on commit 67ad002

Please sign in to comment.