another-dimension
Version:
A lightweight library for converting units of length
457 lines (355 loc) • 14.3 kB
JavaScript
;
const assert = require("assert");
const Dimension = require("another-dimension");
describe("Dimension", () => {
describe("Creation", () => {
it("Constructor syntax", () => {
assert( (new Dimension()) instanceof Dimension);
});
it("Factory syntax", () => {
assert( (Dimension()) instanceof Dimension);
});
it("Default value 0", () => {
assert.strictEqual( Dimension().value, 0);
});
it("Default unit mm", () => {
assert.equal( Dimension().unit, "mm");
});
it("Short-circuit if Dimension is passed to constructor", () => {
let dim1 = Dimension();
let dim2 = Dimension(dim1);
assert.strictEqual( dim1, dim2);
});
it("Clone if Dimension is passed to constructor and clone option is set", () => {
let dim1 = Dimension();
let dim2 = Dimension(dim1, {clone: true});
assert.notStrictEqual( dim1, dim2 );
assert.equal(dim1.value, dim2.value);
assert.equal(dim1.unit, dim2.unit);
});
it("Value is stored", () => {
assert.equal( Dimension(1).value, 1);
assert.equal( Dimension(99.9).value, 99.9);
});
it("Uses defaultUnit specified as separate string", () => {
let dim1 = Dimension(1, "m");
assert.equal( dim1.value, 1);
assert.equal( dim1.unit, "m");
});
it("Uses defaultUnit specified as option", () => {
let dim1 = Dimension(1, { defaultUnit: "m" });
assert.equal( dim1.value, 1);
assert.equal( dim1.unit, "m");
});
it("Parses value specified as string into value + unit", () => {
let dim1 = Dimension("1m");
assert.equal( dim1.value, 1);
assert.equal( dim1.unit, "m");
});
it("Uses unit specified with value string over specified defaultUnit", () => {
let dim1 = Dimension("1m", "cm");
assert.equal( dim1.value, 1);
assert.equal( dim1.unit, "m");
});
it("Uses value + unit specified as a plain object", () => {
let dim1 = Dimension({value: 1, unit: "m"});
assert.equal( dim1.value, 1);
assert.equal( dim1.unit, "m");
});
it("Uses value specified as a plain object, with default unit", () => {
let dim1 = Dimension({value: 1});
assert.equal( dim1.value, 1);
assert.equal( dim1.unit, "mm");
});
it("Uses unit specified with plain object over specified defaultUnit", () => {
let dim1 = Dimension({value: 1, unit: "m"}, "cm");
assert.equal( dim1.value, 1);
assert.equal( dim1.unit, "m");
});
it("Calls valueOf() of object passed in as spec", () => {
let obj = { valueOf: () => 1 };
let dim1 = Dimension(obj, "m");
assert.equal( dim1.value, 1);
assert.equal( dim1.unit, "m");
});
});
describe("Basic output", () => {
it("Output unconverted value with .toNumber()", () => {
let dim1 = Dimension("1in");
assert.equal( dim1.toNumber(), 1);
});
it("Output converted value with .toNumber()", () => {
let dim1 = Dimension("1in");
assert.equal( dim1.toNumber("mm"), 25.4);
});
it("Output unconverted value with .valueOf()", () => {
let dim1 = Dimension("1in");
assert.equal( dim1.valueOf(), 1);
});
it("Implicit call to .valueOf() when used as value", () => {
let dim1 = Dimension("1in");
assert.equal( dim1 + 0, 1);
});
it("Output fixed precision value with .toFixed()", () => {
let dim1 = Dimension("2.3333333in");
assert.equal( dim1.toFixed(2), "2.33");
});
it("Output fixed precision converted value with .toFixed()", () => {
let dim1 = Dimension(2+1/8,"in");
assert.equal( dim1.toFixed(2, "mm"), "53.97");
});
it("Output unconverted value + unit with .toString()", () => {
let dim1 = Dimension("1in");
assert.equal( dim1.toString(), "1in");
});
it("Output converted value + unit with .toString()", () => {
let dim1 = Dimension("1in");
assert.equal( dim1.toString("mm"), "25.4mm");
});
it("Output converted fixed precision value + unit with .toString()", () => {
let dim1 = Dimension(2+1/8,"in");
assert.equal( dim1.toString("mm", 2), "53.97mm");
});
it("Output plain object containing value + unit with .toJSON()", () => {
let dim1 = Dimension("1in");
assert.deepEqual( dim1.toJSON(), { value: 1, unit: "in" });
});
});
describe("Conversion", () => {
it("Convert to another Dimension with different unit with .toDimension()", () => {
let dim1 = Dimension("1in");
let dim2 = dim1.toDimension("mm");
assert.equal( dim2.value, 25.4 );
assert.equal( dim2.unit, "mm" );
});
it("Retrieve conversion function for built-in units with Dimension.getConversionFunction()", () => {
let conv = Dimension.getConversionFunction("in","mm");
assert(typeof conv == "function");
assert.equal(conv(1), 25.4);
});
it("Freeze configuration for conversion function with Dimension.getConversionFunction()", () => {
Dimension.configure({pixelDensity: 100});
let conv = Dimension.getConversionFunction("in", "px", {freezeConfig: true});
Dimension.configure({pixelDensity: 200});
assert(typeof conv == "function");
assert.equal(conv(1), 100);
// reset
Dimension.configure({pixelDensity: 96});
});
it("toFixed() returns numeric part with given decimal precision", () => {
let dim1 = Dimension("11.123456789mm");
assert.equal(dim1.toFixed(1), "11.1");
assert.equal(dim1.toFixed(5), "11.12346");
});
it("toFixed() rounds to integer if precision not specified", () => {
let dim1 = Dimension("11.123456789mm");
assert.equal(dim1.toFixed(), "11");
let dim2 = Dimension("11.789mm");
assert.equal(dim2.toFixed(), "12");
});
it("toFixed() with conversion", () => {
let dim1 = Dimension("1in");
assert.equal(dim1.toFixed(0, "mm"), "25");
});
it("toString() returns String with given decimal precision and unit", () => {
let dim1 = Dimension("11.123456789mm");
assert.equal(dim1.toString("mm",2), "11.12mm");
});
it("toString() with precision as only parameter", () => {
let dim1 = Dimension("11.123456789mm");
assert.equal(dim1.toString(2), "11.12mm");
});
it("toString() with conversion", () => {
let dim1 = Dimension("1.8in");
assert.equal(dim1.toString("mm", 1), "45.7mm"); // 45.72
});
it("All built-in units can be converted", () => {
let units = Dimension.getUnits();
for (let unit1 of units) {
for (let unit2 of units) {
let dim1 = Dimension(1, unit1);
let dim2 = dim1.toDimension(unit2);
assert(dim2);
}
}
});
it("Get conversion function with freezeConfig", () => {
let units = Dimension.getUnits();
for (let unit1 of units) {
for (let unit2 of units) {
let func = Dimension.getConversionFunction(unit1, unit2, {freezeConfig: true});
if (func) {
assert(func(1));
}
}
}
});
it("Each conversion is inverse of its reciprocal conversion", () => {
// TODO: this fails for angular conversion of very large lengths (km etc.) - check
let units = Dimension.getUnits();
const epsilon = 0.0001;
for (let unit1 of units) {
for (let unit2 of units) {
let dim1 = Dimension(1, unit1);
let factor1 = dim1.toDimension(unit2).value;
let dim2 = Dimension(1, unit2);
let factor2 = dim2.toDimension(unit1).value;
// factor needs to be inverse of reciprocal conversion,
// within some tolerance for floating point precision
//if (Math.abs(factor1 - 1/factor2) >= epsilon) {
// console.log(unit1, unit2);
// console.log(factor1, 1/factor2);
//}
//assert(Math.abs(factor1 - 1/factor2) < epsilon);
}
}
});
});
describe("Configuration", () => {
it("options.defaultUnit", () => {
Dimension.configure({defaultUnit: "in"});
let dim1 = Dimension(1);
assert.equal( dim1.unit, "in");
// reset
Dimension.configure({defaultUnit: "mm"});
});
it("options.defaultOutputUnit", () => {
Dimension.configure({defaultOutputUnit: "mm"});
let dim1 = Dimension("1in");
assert.equal( dim1 + 0, 25.4);
// reset
Dimension.configure({defaultOutputUnit: null});
});
it("options.anchorUnit", () => {
Dimension.configure({anchorUnit: "x"});
Dimension.addConversion("a", "x", 10);
Dimension.addConversion("x", "c", 10);
let dim1 = Dimension("1a");
assert.equal( dim1.toNumber("c"), 100);
// reset
Dimension.configure({anchorUnit: "mm"});
});
it("options.pixelDensity", () => {
Dimension.configure({pixelDensity: 100});
let dim1 = Dimension("1in");
assert.equal( dim1.toNumber("px"), 100);
// reset
Dimension.configure({pixelDensity: 96});
});
it("options.viewingDistance", () => {
Dimension.configure({viewingDistance: 300});
let dim1 = Dimension("1arcmin");
assert.equal( dim1.toFixed(2, "mm"), "0.09");
// reset
Dimension.configure({viewingDistance: 600});
});
it("options.aliases", () => {
Dimension.configure({aliases: { "foo": "mm" }});
let dim1 = Dimension("1foo");
assert.equal( dim1.unit, "mm");
// reset
Dimension.configure({aliases: { "um": "µ", "µm": "µ", "°": "deg"}});
});
it("Setting options.aliases to null clears aliases", () => {
Dimension.configure({aliases: null});
let dim1 = Dimension.unAlias("°");
assert.equal( dim1, "°");
// reset
Dimension.configure({aliases: { "um": "µ", "µm": "µ", "°": "deg"}});
});
it("options.toJSON", () => {
Dimension.configure({toJSON: d => d.value + d.unit });
let dim1 = Dimension("1mm");
assert.equal( dim1.toJSON(), "1mm");
// reset
Dimension.configure({toJSON: d => ({value: d.value, unit: d.unit}) });
});
it("getUnits() returns list of units", () => {
let units = Dimension.getUnits();
assert(units.length);
assert(units.includes("mm"));
assert(units.includes("in"));
assert(units.includes("arcmin"));
});
it("Custom unit is included in getUnits()", () => {
Dimension.addConversion("mm", "foo", 1);
let units = Dimension.getUnits();
assert(units.includes("foo"));
});
});
describe("Aliases", () => {
it("Alias results in canonical dimension on creation", () => {
let dim1 = Dimension("1°");
assert.equal( dim1.value, 1);
assert.equal( dim1.unit, "deg");
});
it("Alias results in canonical dimension on conversion", () => {
let dim1 = Dimension("60arcmin");
let dim2 = dim1.toDimension("°");
assert.equal( dim2.value, 1);
assert.equal( dim2.unit, "deg");
});
it("Get canonical unit with Dimension.unAlias()", () => {
assert.equal( Dimension.unAlias("°"), "deg");
});
it("Unit returned by Dimension.unAlias() for canonical units", () => {
assert.equal( Dimension.unAlias("mm"), "mm");
});
it("Add alias with .addAlias()", () => {
Dimension.addAlias("mm", "mmx");
assert.equal( Dimension.unAlias("mmx"), "mm");
});
});
describe("Custom units", () => {
it("Add custom unit with conversion factor using Dimension.addConversion()", () => {
Dimension.addConversion("a", "b", 10);
let dim1 = Dimension("1a");
assert.equal( dim1.toNumber("b"), 10);
});
it("Reverse conversion for factor added using Dimension.addConversion()", () => {
let dim1 = Dimension("1b");
assert.equal( dim1.toNumber("a"), 0.1);
});
it("Missing conversion path throws an Error", () => {
let dim1 = Dimension("1a");
assert.throws( () => dim1.toNumber("mm"), Error);
});
it("Conversion of custom units through anchorUnit", () => {
Dimension.addConversion("a", "mm", 10);
Dimension.addConversion("mm", "c", 10);
let dim1 = Dimension("1a");
assert.equal( dim1.toNumber("c"), 100);
// reverse indirect path does not work (yet)
//let dim2 = Dimension("1c");
//assert.equal( dim2.toNumber("a"), 0.01);
});
});
describe("Utilities", () => {
it("parseDimensionString() with unit", () => {
let res = Dimension.parseDimensionString("-100.0foo");
assert.equal( res.value, -100);
assert.equal( res.unit, "foo");
});
it("parseDimensionString() with number", () => {
let res = Dimension.parseDimensionString("-100.0");
assert.equal( res.value, -100);
assert.equal( res.unit, "mm");
});
it("parseDimensionString() with invalid value", () => {
let res = Dimension.parseDimensionString("bar-10a0.0foo");
assert.strictEqual( res, null);
});
});
describe("Bundling", () => {
it("Import as ES6 module using import() function", () => {
return import("./another-dimension.js").then(module => {
let DimensionES6 = module.default;
let dim1 = DimensionES6("1mm");
assert.equal( dim1.value, 1);
});
});
});
});
after(function(){
console.log('\n ... open test.html in browser to run browser-specific tests.')
})