diff --git a/README.md b/README.md index 621085d..0e6624f 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ - Changed my email and website. - Added Google Analytics. - When the version number changes the website reloads itself (without cache). +- Added some unit tests. **Web** - Implemented a fancy loading screen. diff --git a/lib/types.js b/lib/types.js index 312e534..4d6a9e1 100644 --- a/lib/types.js +++ b/lib/types.js @@ -6,11 +6,11 @@ let constants = require('./constants') // Key: the ships display name // Val: the ships server name -const SHIP_TYPES = _.mapKeys(constants.shipTypes, (key) => key.toLowerCase()) +const SHIP_TYPES = _.mapKeys(constants.shipTypes, (value, key) => key.toLowerCase()) // Key: the ships server name // Val: the ships display name -const INVERTED_SHIP_TYPES = _.invert(SHIP_TYPES) +const INVERTED_SHIP_TYPES = _.invert(_.clone(constants.shipTypes)) /** * Translate human-written types into server types @@ -26,6 +26,10 @@ let types = { * @return {string} the new type */ translateShipType (type) { + if (!type) { + return '' + } + let key = type.toLowerCase() if (SHIP_TYPES[key]) { diff --git a/lib/util.js b/lib/util.js index f3a901d..91657eb 100644 --- a/lib/util.js +++ b/lib/util.js @@ -43,6 +43,10 @@ const util = { * @return {string} the number with commas added */ commify (x) { + if (!x) { + return '' + } + // See: http://stackoverflow.com/a/2901298/1978973 return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ', ') }, @@ -54,6 +58,10 @@ const util = { * @return {string} human-readable time in the form `days:hours:minutes:seconds` */ formatMs (ms) { + if (!ms) { + return '' + } + return moment.duration(ms, 'milliseconds').format() }, @@ -64,6 +72,10 @@ const util = { * @return {string} a nicely formatted date */ formatServerDate (date) { + if (!date) { + return '' + } + return moment(date, constants.serverDateFormat).format('dddd, Do MMMM HH:mm:ss ZZ') }, @@ -90,6 +102,10 @@ const util = { * @return {integer} an integer */ int (num) { + if (!num) { + return 0 + } + return parseInt(num, 10) }, @@ -129,6 +145,13 @@ const util = { * @return {number} the mean, rounded to two decimal places */ mean (arr) { + arr = util.array(arr) + + // Avoid illegal divisions by 0 + if (arr.length === 0) { + return 0 + } + return util.round(_.sum(arr) / arr.length, 2) }, @@ -187,6 +210,18 @@ const util = { * @return {string} the singular of plural form of `word` */ handlePlurality (number, word) { + if (number == null && !word) { + return '' + } + + if (number == null) { + return word + } + + if (!word) { + return '' + } + number = util.int(number) return pluralize(word, number) }, diff --git a/test/constants-test.js b/test/constants-test.js new file mode 100644 index 0000000..faff94e --- /dev/null +++ b/test/constants-test.js @@ -0,0 +1,76 @@ +'use strict' + +/* global describe */ +/* global it */ + +let expect = require('chai').expect +let _ = require('lodash') + +let constants = require('../lib/constants') + +describe('constants', () => { + describe('#serverDateFormat', () => { + it('should be correct', () => { + expect(constants.serverDateFormat).to.equal('DD MM YYYY HH:mm:ss ZZ') + }) + }) + + describe('#shipTypes', () => { + it('should be correct', () => { + let shipTypes = { + 'Barge': 'barge', + 'Bleeder': 'bleeder', + 'Cargo Ship': 'cargo_ship', + 'Colony Ship': 'colony_ship', + 'Detonator': 'detonator', + 'Dory': 'dory', + 'Drone': 'drone', + 'Excavator': 'excavator', + 'Fighter': 'fighter', + 'Fissure Sealer': 'fissure_sealer', + 'Freighter': 'freighter', + 'Galleon': 'galleon', + 'Gas Giant Settlement Ship': 'gas_giant_settlement_ship', + 'Hulk': 'hulk', + 'Hulk Fast': 'hulk_fast', + 'Hulk Huge': 'hulk_huge', + 'Mining Platform Ship': 'mining_platform_ship', + 'Observatory Seeker': 'observatory_seeker', + 'Placebo': 'placebo', + 'Placebo II': 'placebo2', + 'Placebo III': 'placebo3', + 'Placebo IV': 'placebo4', + 'Placebo V': 'placebo5', + 'Placebo VI': 'placebo6', + 'Probe': 'probe', + 'Scanner': 'scanner', + 'Scow': 'scow', + 'Scow Fast': 'scow_fast', + 'Scow Large': 'scow_large', + 'Scow Mega': 'scow_mega', + 'Security Ministry Seeker': 'security_ministry_seeker', + 'Short Range Colony Ship': 'short_range_colony_ship', + 'Smuggler Ship': 'smuggler_ship', + 'Snark': 'snark', + 'Snark II': 'snark2', + 'Snark III': 'snark3', + 'Space Station Hull': 'space_station', + 'Spaceport Seeker': 'spaceport_seeker', + 'Spy Pod': 'spy_pod', + 'Spy Shuttle': 'spy_shuttle', + 'Stake': 'stake', + 'Supply Pod': 'supply_pod', + 'Supply Pod II': 'supply_pod2', + 'Supply Pod III': 'supply_pod3', + 'Supply Pod IV': 'supply_pod4', + 'Supply Pod V': 'supply_pod5', + 'Surveyor': 'surveyor', + 'Sweeper': 'sweeper', + 'Terraforming Platform Ship': 'terraforming_platform_ship', + 'Thud': 'thud' + } + + expect(_.isEqual(constants.shipTypes, shipTypes)).to.equal(true) + }) + }) +}) diff --git a/test/types-test.js b/test/types-test.js new file mode 100644 index 0000000..6d7f4dc --- /dev/null +++ b/test/types-test.js @@ -0,0 +1,29 @@ +'use strict' + +/* global describe */ +/* global it */ + +let expect = require('chai').expect + +let types = require('../lib/types') + +describe('types', () => { + describe('#translateShipType', () => { + it('should handle undefined', () => { + expect(types.translateShipType(undefined)).to.equal('') + expect(types.translateShipType(null)).to.equal('') + }) + + it('should translate a human ship name to a server type', () => { + expect(types.translateShipType('Supply Pod II')).to.equal('supply_pod2') + }) + + it('should translate a server ship name to a human type', () => { + expect(types.translateShipType('supply_pod2')).to.equal('Supply Pod II') + }) + + it(`should handle types it doesn't understand`, () => { + expect(types.translateShipType('Unicorn')).to.equal(undefined) + }) + }) +}) diff --git a/test/util-test.js b/test/util-test.js new file mode 100644 index 0000000..9fc4018 --- /dev/null +++ b/test/util-test.js @@ -0,0 +1,167 @@ +'use strict' + +/* global describe */ +/* global it */ + +let expect = require('chai').expect +let _ = require('lodash') + +let util = require('../lib/util') + +describe('util', () => { + describe('#array', () => { + it('should handle undefined', () => { + expect(util.array(undefined)).to.a('array') + expect(util.array(null)).to.a('array') + expect(util.array()).to.a('array') + }) + + it('should make something into an array', () => { + expect(util.array({})).to.be.a('array') + expect(util.array([]).length).to.equal(0) + expect(util.array(10)[0]).to.equal(10) + }) + }) + + describe('#commify', () => { + it('should handle undefined', () => { + expect(util.commify(undefined)).to.equal('') + expect(util.commify(null)).to.equal('') + }) + + it('should commify numbers', () => { + expect(util.commify(111111)).to.equal('111, 111') + }) + }) + + describe('#formatMs', () => { + it('should handle undefined', () => { + expect(util.formatMs(undefined)).to.equal('') + expect(util.formatMs(null)).to.equal('') + }) + + it('should format milliseconds properly', () => { + expect(util.formatMs(60 * 60 * 1000)).to.equal('1h') + expect(util.formatMs((60 * 60 * 1000) + (10 * 1000))).to.equal('1:00:10') + }) + }) + + describe('#formatServerDate', () => { + it('should handle undefined', () => { + expect(util.formatServerDate(undefined)).to.equal('') + expect(util.formatServerDate(null)).to.equal('') + }) + + it('should format server dates', () => { + // We can't actually test the content of the string because it's different for each time zone! + expect(util.formatServerDate('28 01 2016 06:40:45 +0000')).to.be.a('string') + }) + }) + + describe('#int', () => { + it('should handle undefined', () => { + expect(util.int(undefined)).to.equal(0) + expect(util.int(null)).to.equal(0) + }) + + it('should make numbers into integers', () => { + expect(util.int('10')).to.equal(10) + expect(util.int('10.78592340')).to.equal(10) + expect(util.int(10.78592340)).to.equal(10) + }) + }) + + describe('#isCLI', () => { + it('should be correct for the CLI', () => { + // At time of writing, these tests are only run in the command line. + expect(util.isCLI()).to.equal(true) + }) + }) + + describe('#isMultiple', () => { + it('should know math', () => { + expect(util.isMultiple(10, 5)).to.equal(true) + }) + }) + + describe('#isWeb', () => { + it('should be correct for the CLI', () => { + // At time of writing, these tests are only run in the command line. + expect(util.isWeb()).to.equal(false) + }) + }) + + describe('#mean', () => { + it('should handle undefined', () => { + expect(util.mean(undefined)).to.equal(0) + expect(util.mean(null)).to.equal(0) + }) + + it('should be mean to those numbers', () => { + expect(util.mean([1, 2, 3])).to.equal(2) + }) + }) + + // This will be quite tricky to unit test. + describe('#msFromNow', _.noop) + + describe('#objectToArray', () => { + it('should convert an object to an array', () => { + const start = { + 1111: { + foo: 'bar' + }, + 2222: { + spam: 'eggs' + } + } + + const end = [ + { + id: '1111', + foo: 'bar' + }, + { + id: '2222', + spam: 'eggs' + } + ] + + expect(_.isEqual(util.objectToArray(start, 'id'), end)).to.equal(true) + }) + }) + + describe('#handlePlurality', () => { + it('should handle undefined input', () => { + expect(util.handlePlurality(undefined, 'ship')).to.equal('ship') + expect(util.handlePlurality(null, 'ship')).to.equal('ship') + + expect(util.handlePlurality(10, undefined)).to.equal('') + expect(util.handlePlurality(10, null)).to.equal('') + + expect(util.handlePlurality(undefined, undefined)).to.equal('') + expect(util.handlePlurality(null, null)).to.equal('') + }) + it('should make words plural when necessary', () => { + expect(util.handlePlurality(10, 'ship')).to.equal('ships') + expect(util.handlePlurality(10, 'ships')).to.equal('ships') + }) + + it('should make works singular when necessary', () => { + expect(util.handlePlurality(1, 'ship')).to.equal('ship') + expect(util.handlePlurality(1, 'ships')).to.equal('ship') + }) + }) + + describe('#regexMatch', () => { + it('should return true when a regex matches', () => { + expect(util.regexMatch(/fuck shit donkey dick/, 'fuck shit donkey dick')).to.equal(true) + }) + }) + + describe('#round', () => { + it('should round a number', () => { + expect(util.round(10.1178490174892107, 2)).to.equal(10.12) + }) + }) +})