diff --git a/.istanbul.yml b/.istanbul.yml index 0ef547a..d9e52d8 100644 --- a/.istanbul.yml +++ b/.istanbul.yml @@ -2,7 +2,7 @@ verbose: false instrumentation: root: . includes: - - 'src/**' + - 'src/**/*' default-excludes: true reporting: print: detail diff --git a/src/util/version.js b/src/util/version.js new file mode 100644 index 0000000..3d1e41e --- /dev/null +++ b/src/util/version.js @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016 Hewlett Packard Enterprise Development L.P. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations + * under the License. + */ + +/** + * A simple version parser, able to parse various version strings used in OpenStack into a + * comparable instance. + */ +export default class Version { + + /** + * The name of the service. + * + * @returns {String|*|null} The name of the service, or null. + */ + get service () { + return this._service || null; + } + + /** + * The major version. + * + * @returns {Number} The major version number + */ + get major () { + return this._major || 0; + } + + /** + * The minor version. + * + * @returns {Number} The minor version number + */ + get minor () { + return this._minor || 0; + } + + /** + * The patch version. + * + * @returns {Number} The patch version number. + */ + get patch () { + return this._patch || 0; + } + + /** + * Create a new instance of a service version. + * + * @param {String} service The name of the service. + * @param {String} versionString The version string for this service. + */ + constructor (service, versionString) { + // Sanitize input + if (typeof service !== 'string') { + service = undefined; + } + if (typeof versionString !== 'string') { + versionString = undefined; + } + + if (versionString === undefined) { + versionString = service; + } else { + this._service = service; + } + + // Sanity check before running regex. + if (!versionString || !versionString.match) { + return; + } + + const results = versionString.match(/^(([^ ]+) )?v?(([0-9]+)(\.([0-9]+)(.([0-9]+))?)?)$/); + if (results) { + this._service = results[2] || this._service; // regex takes precedence + this._major = parseInt(results[4], 10); + this._minor = parseInt(results[6], 10); + this._patch = parseInt(results[8], 10); + } + } + + /** + * Compare this instance to another instance or version string. + * + * @param {String|Version} version The version to compare to. + * @returns {boolean} True if they are exactly the same, otherwise false. + */ + equals (version) { + if (!(version instanceof Version)) { + // is it a parseable string? + if (typeof version === 'string') { + version = new Version(version); + } else { + return false; + } + } + + return version.major === this.major && + version.minor === this.minor && + version.patch === this.patch && + version.service === this.service; + } +} diff --git a/test/unit/util/versionTest.js b/test/unit/util/versionTest.js new file mode 100644 index 0000000..64363c9 --- /dev/null +++ b/test/unit/util/versionTest.js @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016 Hewlett Packard Enterprise Development L.P. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations + * under the License. + */ + +import Version from '../../../src/util/version.js'; + +describe('Version', () => { + + it("should parse various header versions", () => { + + const testVersion = function (args, results) { + const v = new Version(...args); + expect(v.service).toBe(results[0]); + expect(v.major).toBe(results[1]); + expect(v.minor).toBe(results[2]); + expect(v.patch).toBe(results[3]); + }; + + testVersion(['identity 1.2'], ['identity', 1, 2, 0]); + testVersion(['identity 0.2'], ['identity', 0, 2, 0]); + testVersion(['compute 2222222.09'], ['compute', 2222222, 9, 0]); + testVersion(['compute 03.09'], ['compute', 3, 9, 0]); + testVersion(['compute 03.0'], ['compute', 3, 0, 0]); + testVersion(['compute 1'], ['compute', 1, 0, 0]); + testVersion(['compute 0'], ['compute', 0, 0, 0]); + testVersion(['v2.1.1'], [null, 2, 1, 1]); + testVersion(['v2.1'], [null, 2, 1, 0]); + testVersion(['v2'], [null, 2, 0, 0]); + testVersion(['v'], [null, 0, 0, 0]); + testVersion(['v0.2'], [null, 0, 2, 0]); + testVersion(['2.1.1'], [null, 2, 1, 1]); + testVersion(['2.1'], [null, 2, 1, 0]); + testVersion(['2'], [null, 2, 0, 0]); + testVersion([''], [null, 0, 0, 0]); + testVersion(['0.2'], [null, 0, 2, 0]); + testVersion(['compute', 'v2.1.1'], ['compute', 2, 1, 1]); + testVersion(['compute', 'v2.1'], ['compute', 2, 1, 0]); + testVersion(['compute', 'v2'], ['compute', 2, 0, 0]); + testVersion(['compute', 'v'], ['compute', 0, 0, 0]); + testVersion(['compute', 'v0.2'], ['compute', 0, 2, 0]); + testVersion(['compute', '2.1.1'], ['compute', 2, 1, 1]); + testVersion(['compute', '2.1'], ['compute', 2, 1, 0]); + testVersion(['compute', '2'], ['compute', 2, 0, 0]); + testVersion(['compute', ''], ['compute', 0, 0, 0]); + testVersion(['compute', '0.2'], ['compute', 0, 2, 0]); + + // Invalid inputs... + testVersion([null, null], [null, 0, 0, 0]); + testVersion([{}, {}], [null, 0, 0, 0]); + testVersion([null, {}], [null, 0, 0, 0]); + testVersion([{}, null], [null, 0, 0, 0]); + }); + + it("should test for correct equality", () => { + const v1 = new Version("compute", "1.0.0"); + + // String tests... + expect(v1.equals("compute 1.0.0")).toBe(true); + expect(v1.equals("compute 1.0.1")).toBe(false); + expect(v1.equals("identity 1.0.0")).toBe(false); + + // Version tests + expect(v1.equals(new Version("compute 1.0.0"))).toBe(true); + expect(v1.equals(new Version("compute 1.0.1"))).toBe(false); + expect(v1.equals(new Version("identity 1.0.0"))).toBe(false); + expect(v1.equals(new Version("1.0.0"))).toBe(false); + + // Other tests... + expect(v1.equals({})).toBe(false); + + const v2 = new Version("1.0.0"); + + // String tests... + expect(v2.equals("compute 1.0.0")).toBe(false); + expect(v2.equals("compute 1.0.1")).toBe(false); + expect(v2.equals("1.0.0")).toBe(true); + + // Version tests + expect(v2.equals(new Version("compute 1.0.0"))).toBe(false); + expect(v2.equals(new Version("compute 1.0.1"))).toBe(false); + expect(v2.equals(new Version("identity 1.0.0"))).toBe(false); + expect(v2.equals(new Version("1.0.0"))).toBe(true); + + // Other tests... + expect(v2.equals({})).toBe(false); + }); +});