test dependencies: lodash and qunit (not by choice)
/*
* This file is a ported version of
* http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/jtreg/util/concurrent/TimeUnit/Basic.java?view=co
* which contained the following header:
*/
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 5057341 6363898
* @summary Basic tests for TimeUnit
* @author Martin Buchholz
*/
import TimeUnit from "../../../time-unit";
import {
module,
test
} from "qunit";
module("unit:time-unit (GNU compliance)");
test("TimeUnit (Java Source)", assert => {
const values = Object.keys(TimeUnit)
.sort((a, b) => TimeUnit[a].ordinal - TimeUnit[b].ordinal)
.map(key => TimeUnit[key]);
values.forEach(u => {
assert.strictEqual(42, u.convert(42, u));
values.forEach(v => {
if (u.convert(42, v) >= 42) {
assert.strictEqual(42, v.convert(u.convert(42, v), u));
}
});
});
assert.strictEqual(24, TimeUnit.HOURS.convert(1, TimeUnit.DAYS));
assert.strictEqual(60, TimeUnit.MINUTES.convert(1, TimeUnit.HOURS));
assert.strictEqual(60, TimeUnit.SECONDS.convert(1, TimeUnit.MINUTES));
assert.strictEqual(1000, TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS));
assert.strictEqual(1000, TimeUnit.MICROSECONDS.convert(1, TimeUnit.MILLISECONDS));
assert.strictEqual(1000, TimeUnit.NANOSECONDS.convert(1, TimeUnit.MICROSECONDS));
assert.strictEqual(24, TimeUnit.DAYS.toHours(1));
assert.strictEqual(60, TimeUnit.HOURS.toMinutes(1));
assert.strictEqual(60, TimeUnit.MINUTES.toSeconds(1));
assert.strictEqual(1000, TimeUnit.SECONDS.toMillis(1));
assert.strictEqual(1000, TimeUnit.MILLISECONDS.toMicros(1));
assert.strictEqual(1000, TimeUnit.MICROSECONDS.toNanos(1));
});
import TimeUnit from "../../../time-unit";
import {
gcd,
AVAILABLE_TIME_UNITS
} from "../../../time-unit";
import {
module,
test
} from "qunit";
module("unit:time-unit");
test("TimeUnit", assert => {
assert.ok(_.isObject(TimeUnit), "should TimeUnit should be the default export and exported as object");
const values = Object.keys(TimeUnit).sort((a, b) => TimeUnit[a].ordinal - TimeUnit[b].ordinal),
expectedProperties = [
"name",
"ordinal"
].sort(),
expectedMethods = [
"toNanos",
"toMicros",
"toMillis",
"toSeconds",
"toMinutes",
"toHours",
"toDays",
"convert"
].sort();
_.reduce(values, (current, next) => {
const currentTime = TimeUnit[current],
nextTime = TimeUnit[next],
methods = _.functions(currentTime).sort(),
properties = _.keys(_.pick(currentTime, _.negate(_.isFunction))).sort();
// test each 'enum' while we're at it
assert.deepEqual(properties, expectedProperties, `${current}: should have the same properties`);
assert.deepEqual(methods, expectedMethods, `${current}: should have conversion method names`);
assert.ok(currentTime.ordinal < nextTime.ordinal, `${current}: should be less than ${next}`);
return next;
});
});
test("gcd", assert => {
function testGCD(value, unit, expectedValue, expectedUnit) {
const factor = gcd(value, unit),
actual = factor.convert(value, unit),
message = `should calculate ${value} ${unit.name} for ${expectedValue} ${expectedUnit.name}`;
assert.ok(actual === expectedValue && factor === expectedUnit, message.toLowerCase());
}
assert.ok(_.isFunction(gcd), "should be exported as a function");
testGCD(72, TimeUnit.HOURS, 3, TimeUnit.DAYS);
testGCD(73, TimeUnit.HOURS, 73, TimeUnit.HOURS);
testGCD(60, TimeUnit.MINUTES, 1, TimeUnit.HOURS);
testGCD(86400, TimeUnit.SECONDS, 1, TimeUnit.DAYS);
testGCD(86400, TimeUnit.MINUTES, 60, TimeUnit.DAYS);
testGCD(86401, TimeUnit.MINUTES, 86401, TimeUnit.MINUTES);
});
test("AVAILABLE_TIME_UNITS", assert => {
assert.ok(_.isArray(AVAILABLE_TIME_UNITS), "should exported as an array");
const values = Object.keys(TimeUnit).sort((a, b) => TimeUnit[a].ordinal - TimeUnit[b].ordinal);
assert.deepEqual(values, AVAILABLE_TIME_UNITS, "should be sorted in ascending order");
});
/*
* This file is a ported version of
* http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/TimeUnit.java
* which contained the following notice:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const MIN = -9007199254740992;
const MAX = 9007199254740992;
const C0 = 1;
const C1 = C0 * 1000;
const C2 = C1 * 1000;
const C3 = C2 * 1000;
const C4 = C3 * 60;
const C5 = C4 * 60;
const C6 = C5 * 24;
function x(d, m, over) {
if (d > over) {
return MAX;
}
if (d < -over) {
return MIN;
}
return d * m;
}
/**
* <code>
* TimeUnit.DAYS.toHours(1); // 24
* TimeUnit.HOURS.convert(1, TimeUnit.DAYS); // 24
* </code>
*/
const TimeUnit = {
// emulate Java enum
NANOSECONDS: {
get name() { return "NANOSECONDS"; },
get ordinal() { return 0; },
toNanos(d) { return d; },
toMicros(d) { return d/(C1/C0); },
toMillis(d) { return d/(C2/C0); },
toSeconds(d) { return d/(C3/C0); },
toMinutes(d) { return d/(C4/C0); },
toHours(d) { return d/(C5/C0); },
toDays(d) { return d/(C6/C0); },
convert(d, unit) { return unit.toNanos(d); }
},
MICROSECONDS: {
get name() { return "MICROSECONDS"; },
get ordinal() { return 1; },
toNanos(d) { return x(d, C1/C0, MAX/(C1/C0)); },
toMicros(d) { return d; },
toMillis(d) { return d/(C2/C1); },
toSeconds(d) { return d/(C3/C1); },
toMinutes(d) { return d/(C4/C1); },
toHours(d) { return d/(C5/C1); },
toDays(d) { return d/(C6/C1); },
convert(d, unit) { return unit.toMicros(d); }
},
MILLISECONDS: {
get name() { return "MILLISECONDS"; },
get ordinal() { return 2; },
toNanos(d) { return x(d, C2/C0, MAX/(C2/C0)); },
toMicros(d) { return x(d, C2/C1, MAX/(C2/C1)); },
toMillis(d) { return d; },
toSeconds(d) { return d/(C3/C2); },
toMinutes(d) { return d/(C4/C2); },
toHours(d) { return d/(C5/C2); },
toDays(d) { return d/(C6/C2); },
convert(d, unit) { return unit.toMillis(d); }
},
SECONDS: {
get name() { return "SECONDS"; },
get ordinal() { return 3; },
toNanos(d) { return x(d, C3/C0, MAX/(C3/C0)); },
toMicros(d) { return x(d, C3/C1, MAX/(C3/C1)); },
toMillis(d) { return x(d, C3/C2, MAX/(C3/C2)); },
toSeconds(d) { return d; },
toMinutes(d) { return d/(C4/C3); },
toHours(d) { return d/(C5/C3); },
toDays(d) { return d/(C6/C3); },
convert(d, unit) { return unit.toSeconds(d); }
},
MINUTES: {
get name() { return "MINUTES"; },
get ordinal() { return 4; },
toNanos(d) { return x(d, C4/C0, MAX/(C4/C0)); },
toMicros(d) { return x(d, C4/C1, MAX/(C4/C1)); },
toMillis(d) { return x(d, C4/C2, MAX/(C4/C2)); },
toSeconds(d) { return x(d, C4/C3, MAX/(C4/C3)); },
toMinutes(d) { return d; },
toHours(d) { return d/(C5/C4); },
toDays(d) { return d/(C6/C4); },
convert(d, unit) { return unit.toMinutes(d); }
},
HOURS: {
get name() { return "HOURS"; },
get ordinal() { return 5; },
toNanos(d) { return x(d, C5/C0, MAX/(C5/C0)); },
toMicros(d) { return x(d, C5/C1, MAX/(C5/C1)); },
toMillis(d) { return x(d, C5/C2, MAX/(C5/C2)); },
toSeconds(d) { return x(d, C5/C3, MAX/(C5/C3)); },
toMinutes(d) { return x(d, C5/C4, MAX/(C5/C4)); },
toHours(d) { return d; },
toDays(d) { return d/(C6/C5); },
convert(d, unit) { return unit.toHours(d); }
},
DAYS: {
get name() { return "DAYS"; },
get ordinal() { return 6; },
toNanos(d) { return x(d, C6/C0, MAX/(C6/C0)); },
toMicros(d) { return x(d, C6/C1, MAX/(C6/C1)); },
toMillis(d) { return x(d, C6/C2, MAX/(C6/C2)); },
toSeconds(d) { return x(d, C6/C3, MAX/(C6/C3)); },
toMinutes(d) { return x(d, C6/C4, MAX/(C6/C4)); },
toHours(d) { return x(d, C6/C5, MAX/(C6/C5)); },
toDays(d) { return d; },
convert(d, unit) { return unit.toDays(d); }
}
};
export const AVAILABLE_TIME_UNITS = Object.keys(TimeUnit)
.sort((a, b) => TimeUnit[a].ordinal - TimeUnit[b].ordinal);
const DESCENDING_TIME_UNITS = AVAILABLE_TIME_UNITS.slice().reverse();
// convert as "hours" "HOURS" "TimeUnit.HOURS" => TimeUnit.HOURS
export function asTimeUnit(unit) {
if (_.isString(unit)) {
unit = unit.toUpperCase();
}
let timeunit = _.find(TimeUnit, u => u === unit || u.name === unit);
if (!timeunit) {
Ember.assert(`Invalid '${unit}'. Available: ${AVAILABLE_TIME_UNITS.join(", ")}`);
}
return timeunit;
}
/**
* <code>
* gcd(72, TimeUnit.HOURS); // TimeUnit.DAY
* gcd(73, TimeUnit.HOURS); // TimeUnit.HOURS
* </code>
*/
export function gcd(value, unit) {
Ember.assert("Value cannot be negative", value >= 0);
Ember.assert(`Time unit must be one of the following ${AVAILABLE_TIME_UNITS.join(", ")}`,
_.contains(AVAILABLE_TIME_UNITS, _.has(unit, "name") ? unit.name : null));
let nanoseconds = TimeUnit.NANOSECONDS.convert(value, unit),
result;
// babel v5.1.5
result = _.find(DESCENDING_TIME_UNITS, unit => {
let timeunit = asTimeUnit(unit),
conversion = timeunit.convert(nanoseconds, TimeUnit.NANOSECONDS);
return conversion < MAX && Math.floor(conversion) === conversion;
});
return result ? asTimeUnit(result) : unit;
// babel v5.8.24
// for (let unit of timeunits) {
// let timeunit = asTimeUnit(result),
// conversion = timeunit.convert(nanoseconds, TimeUnit.NANOSECONDS);
//
// if (conversion < MAX && Math.floor(conversion) === conversion) {
// return timeunit;
// }
// }
// return base;
}
export default TimeUnit;