Skip to content

Commit 2b6049a

Browse files
timreichenkt3k
andauthored
fix(cli/unstable): clamp ratio (#6690)
Co-authored-by: Yoshiya Hinosawa <[email protected]>
1 parent 7c3b502 commit 2b6049a

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

cli/unstable_progress_bar.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ function defaultFormatter(x: ProgressBarFormatter) {
121121
return `[${x.styledTime}] [${x.progressBar}] [${x.styledData()}]`;
122122
}
123123

124+
function clamp(value: number, min: number, max: number) {
125+
return Math.min(Math.max(value, min), max);
126+
}
127+
124128
/**
125129
* `ProgressBar` is a customisable class that reports updates to a
126130
* {@link WritableStream} on a 1s interval. Progress is communicated by using
@@ -265,7 +269,8 @@ export class ProgressBar {
265269
#createFormatterObject() {
266270
const time = Date.now() - this.#startTime;
267271

268-
const size = this.value / this.max * this.#barLength | 0;
272+
const ratio = clamp(this.value / this.max, 0, 1);
273+
const size = Math.trunc(ratio * this.#barLength);
269274
const fillChars = this.#fillChar.repeat(size);
270275
const emptyChars = this.#emptyChar.repeat(this.#barLength - size);
271276

cli/unstable_progress_bar_test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,60 @@ Deno.test("ProgressBar() does not leak resources when immediately stopped", asyn
139139
const progressBar = new ProgressBar({ max: 10 });
140140
await progressBar.stop();
141141
});
142+
143+
Deno.test("ProgressBar() handles value < 0", async () => {
144+
using _fakeTime = new FakeTime();
145+
const { readable, writable } = new TransformStream();
146+
const bar = new ProgressBar({ writable, max: 2 ** 10, value: -1 });
147+
bar.stop().then(() => writable.close());
148+
149+
const expected = [
150+
"\r\x1b[K[00:00] [--------------------------------------------------] [-0.00/1.00 KiB]",
151+
"\r\x1b[K[00:00] [--------------------------------------------------] [-0.00/1.00 KiB]",
152+
"\n",
153+
];
154+
155+
const actual: string[] = [];
156+
for await (const buffer of readable) {
157+
actual.push(decoder.decode(buffer));
158+
}
159+
assertEquals(actual, expected);
160+
});
161+
162+
Deno.test("ProgressBar() handles max < 0", async () => {
163+
using _fakeTime = new FakeTime();
164+
const { readable, writable } = new TransformStream();
165+
const bar = new ProgressBar({ writable, max: -1 });
166+
bar.stop().then(() => writable.close());
167+
168+
const expected = [
169+
"\r\x1b[K[00:00] [--------------------------------------------------] [0.00/-0.00 KiB]",
170+
"\r\x1b[K[00:00] [--------------------------------------------------] [0.00/-0.00 KiB]",
171+
"\n",
172+
];
173+
174+
const actual: string[] = [];
175+
for await (const buffer of readable) {
176+
actual.push(decoder.decode(buffer));
177+
}
178+
assertEquals(actual, expected);
179+
});
180+
181+
Deno.test("ProgressBar() handles value > max", async () => {
182+
using _fakeTime = new FakeTime();
183+
const { readable, writable } = new TransformStream();
184+
const bar = new ProgressBar({ writable, max: 2 ** 10, value: 2 ** 10 + 1 });
185+
bar.stop().then(() => writable.close());
186+
187+
const expected = [
188+
"\r\x1b[K[00:00] [##################################################] [1.00/1.00 KiB]",
189+
"\r\x1b[K[00:00] [##################################################] [1.00/1.00 KiB]",
190+
"\n",
191+
];
192+
193+
const actual: string[] = [];
194+
for await (const buffer of readable) {
195+
actual.push(decoder.decode(buffer));
196+
}
197+
assertEquals(actual, expected);
198+
});

0 commit comments

Comments
 (0)