import { TestBed } from '@angular/core/testing';
+import { DimlessBinaryPipe } from '../pipes/dimless-binary.pipe';
import { FormatterService } from './formatter.service';
describe('FormatterService', () => {
let service: FormatterService;
+ let dimlessBinaryPipe: DimlessBinaryPipe;
+
+ const convertToBytesAndBack = (value: string, newValue?: string) => {
+ expect(dimlessBinaryPipe.transform(service.toBytes(value))).toBe(newValue || value);
+ };
+
beforeEach(() => {
TestBed.configureTestingModule({
- providers: [FormatterService]
+ providers: [FormatterService, DimlessBinaryPipe]
});
service = new FormatterService();
+ dimlessBinaryPipe = new DimlessBinaryPipe(service);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
- it('should not convert 10xyz to bytes (failure)', () => {
- const bytes = service.toBytes('10xyz');
- expect(bytes).toBeNull();
- });
+ describe('truncate', () => {
+ it('should do test integer values', () => {
+ expect(service.truncate('1234', 8)).toBe('1234');
+ expect(service.truncate(1234, 8)).toBe('1234');
+ });
- it('should not convert 1.1.1KiB to bytes (failure)', () => {
- const bytes = service.toBytes('1.1.1KiB');
- expect(bytes).toBeNull();
+ it('should do test floating values', () => {
+ const value = '1234.567899000';
+ expect(service.truncate(value, 0)).toBe('1235');
+ expect(service.truncate(value, 1)).toBe('1234.6');
+ expect(service.truncate(value, 3)).toBe('1234.568');
+ expect(service.truncate(value, 4)).toBe('1234.5679');
+ expect(service.truncate(value, 5)).toBe('1234.5679');
+ expect(service.truncate(value, 6)).toBe('1234.567899');
+ expect(service.truncate(value, 7)).toBe('1234.567899');
+ expect(service.truncate(value, 10)).toBe('1234.567899');
+ expect(service.truncate(100.00, 4)).toBe('100');
+ });
});
- it('should convert 4815162342 to bytes', () => {
- const bytes = service.toBytes('4815162342');
- expect(bytes).toEqual(jasmine.any(Number));
- expect(bytes).toBe(4815162342);
- });
+ describe('format_number', () => {
+ const formats = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
- it('should convert 100M to bytes', () => {
- const bytes = service.toBytes('100M');
- expect(bytes).toEqual(jasmine.any(Number));
- expect(bytes).toBe(104857600);
- });
+ it('should return minus for unsupported values', () => {
+ expect(service.format_number(service, 1024, formats)).toBe('-');
+ expect(service.format_number(undefined, 1024, formats)).toBe('-');
+ expect(service.format_number(null, 1024, formats)).toBe('-');
+ expect(service.format_number('0', 1024, formats)).toBe('-');
+ });
- it('should convert 1.532KiB to bytes', () => {
- const bytes = service.toBytes('1.532KiB');
- expect(bytes).toEqual(jasmine.any(Number));
- expect(bytes).toBe(Math.floor(1.532 * 1024));
+ it('should test some values', () => {
+ expect(service.format_number('1', 1024, formats)).toBe('1B');
+ expect(service.format_number('1024', 1024, formats)).toBe('1KiB');
+ expect(service.format_number(23.45678 * Math.pow(1024, 3), 1024, formats)).toBe('23.4568GiB');
+ });
});
- it('should convert 0.000000000001TiB to bytes', () => {
- const bytes = service.toBytes('0.000000000001TiB');
- expect(bytes).toEqual(jasmine.any(Number));
- expect(bytes).toBe(1);
+ describe('toBytes', () => {
+ it('should not convert wrong values', () => {
+ expect(service.toBytes('10xyz')).toBeNull();
+ expect(service.toBytes('1.1.1KiB')).toBeNull();
+ expect(service.toBytes('1.1 KiloByte')).toBeNull();
+ expect(service.toBytes('1.1 kib')).toBeNull();
+ expect(service.toBytes('1.kib')).toBeNull();
+ expect(service.toBytes('1 ki')).toBeNull();
+ });
+
+ it('should convert values to bytes', () => {
+ expect(service.toBytes('4815162342')).toBe(4815162342);
+ expect(service.toBytes('100M')).toBe(104857600);
+ expect(service.toBytes('100 M')).toBe(104857600);
+ expect(service.toBytes('100 mIb')).toBe(104857600);
+ expect(service.toBytes('100 mb')).toBe(104857600);
+ expect(service.toBytes('100MIB')).toBe(104857600);
+ expect(service.toBytes('1.532KiB')).toBe(Math.round(1.532 * 1024));
+ expect(service.toBytes('0.000000000001TiB')).toBe(1);
+ });
+
+ it('should convert values to human readable again', () => {
+ convertToBytesAndBack('1.1MiB');
+ convertToBytesAndBack('1.0MiB', '1MiB');
+ convertToBytesAndBack('8.9GiB');
+ convertToBytesAndBack('123.456EiB');
+ });
});
});
export class FormatterService {
constructor() {}
- truncate(n, maxWidth) {
- const stringized = n.toString();
- const parts = stringized.split('.');
+ truncate(n: number | string, decimals: number): string {
+ const value = n.toString();
+ const parts = value.split('.');
if (parts.length === 1) {
- // Just an int
- return stringized;
+ return value; // integer
} else {
- const fractionalDigits = maxWidth - parts[0].length - 1;
- if (fractionalDigits <= 0) {
- // No width available for the fractional part, drop
- // it and the decimal point
- return parts[0];
- } else {
- return stringized.substring(0, maxWidth);
- }
+ return Number.parseFloat(value).toPrecision(decimals + parts[0].length)
+ .toString().replace(/0+$/, '');
}
}
- format_number(n, divisor, units) {
- const width = 4;
- let unit = 0;
-
- if (n == null) {
- // People shouldn't really be passing null, but let's
- // do something sensible instead of barfing.
- return '-';
- }
-
- while (Math.floor(n / divisor ** unit).toString().length > width - 1) {
- unit = unit + 1;
+ format_number(n: any, divisor: number, units: string[], decimals: number = 4): string {
+ if (_.isString(n)) {
+ n = Number(n);
}
-
- let truncatedFloat;
- if (unit > 0) {
- truncatedFloat = this.truncate(
- (n / Math.pow(divisor, unit)).toString(),
- width
- );
- } else {
- truncatedFloat = this.truncate(n, width);
+ if (!(_.isNumber(n)) || n === 0) {
+ return '-';
}
-
+ const unit = Math.floor(Math.log(n) / Math.log(divisor));
+ const truncatedFloat = this.truncate((n / Math.pow(divisor, unit)), decimals);
return truncatedFloat === '' ? '-' : (truncatedFloat + units[unit]);
}
*/
toBytes(value: string): number | null {
const base = 1024;
- const units = {
- 'b': 1,
- 'k': Math.pow(base, 1),
- 'kb': Math.pow(base, 1),
- 'kib': Math.pow(base, 1),
- 'm': Math.pow(base, 2),
- 'mb': Math.pow(base, 2),
- 'mib': Math.pow(base, 2),
- 'g': Math.pow(base, 3),
- 'gb': Math.pow(base, 3),
- 'gib': Math.pow(base, 3),
- 't': Math.pow(base, 4),
- 'tb': Math.pow(base, 4),
- 'tib': Math.pow(base, 4),
- 'p': Math.pow(base, 5),
- 'pb': Math.pow(base, 5),
- 'pib': Math.pow(base, 5),
- 'e': Math.pow(base, 6),
- 'eb': Math.pow(base, 6),
- 'eib': Math.pow(base, 6),
- 'z': Math.pow(base, 7),
- 'zb': Math.pow(base, 7),
- 'zib': Math.pow(base, 7),
- 'y': Math.pow(base, 8),
- 'yb': Math.pow(base, 8),
- 'yib': Math.pow(base, 8)
- };
- const m = RegExp('^(\\d+(\.\\d+)?)\\s*(B|K(B|iB)?|M(B|iB)?|G(B|iB)?|T(B|iB)?|P(B|iB)?|' +
- 'E(B|iB)?|Z(B|iB)?|Y(B|iB)?)?$', 'i').exec(value);
+ const units = ['b', 'k', 'm', 'g', 't', 'p', 'e', 'z', 'y'];
+ const m = RegExp('^(\\d+(\.\\d+)?) ?(\[' + units.join('') + '\](b|ib)?)?$', 'i').exec(value);
if (m === null) {
return null;
}
let bytes = parseFloat(m[1]);
if (_.isString(m[3])) {
- bytes = bytes * units[m[3].toLowerCase()];
+ bytes = bytes * Math.pow(base, units.indexOf(m[3].toLowerCase()[0]));
}
- return Math.floor(bytes);
+ return Math.round(bytes);
}
}