From b0a48fad576b3689d152f7c14bdd7b7230baf9c1 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 4 Feb 2021 12:26:15 +0100 Subject: [PATCH] util: Add a GNOME version comparison function Add a function that can compare GNOME versions, including the new naming scheme for GNOME 40 and later. Used in https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3632 Part-of: --- js/misc/util.js | 40 ++++++++++++++++++++++++++- tests/meson.build | 2 +- tests/unit/versionCompare.js | 52 ++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 tests/unit/versionCompare.js diff --git a/js/misc/util.js b/js/misc/util.js index 2da489bbe..572cee7bf 100644 --- a/js/misc/util.js +++ b/js/misc/util.js @@ -1,7 +1,7 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- /* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine, formatTime, formatTimeSpan, createTimeLabel, insertSorted, - ensureActorVisibleInScrollView, wiggle, lerp */ + ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare */ const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi; const Gettext = imports.gettext; @@ -439,3 +439,41 @@ function wiggle(actor, params) { function lerp(start, end, progress) { return start + progress * (end - start); } + +// _GNOMEversionToNumber: +// @version: a GNOME version element +// +// Like Number() but returns sortable values for special-cases +// 'alpha' and 'beta'. Returns NaN for unhandled 'versions'. +function _GNOMEversionToNumber(version) { + let ret = Number(version); + if (!isNaN(ret)) + return ret; + if (version === 'alpha') + return -2; + if (version === 'beta') + return -1; + return ret; +} + +// GNOMEversionCompare: +// @version1: a string containing a GNOME version +// @version2: a string containing another GNOME version +// +// Returns an integer less than, equal to, or greater than +// zero, if version1 is older, equal or newer than version2 +function GNOMEversionCompare(version1, version2) { + const v1Array = version1.split('.'); + const v2Array = version2.split('.'); + + for (let i = 0; i < Math.max(v1Array.length, v2Array.length); i++) { + let elemV1 = _GNOMEversionToNumber(v1Array[i] || '0'); + let elemV2 = _GNOMEversionToNumber(v2Array[i] || '0'); + if (elemV1 < elemV2) + return -1; + if (elemV1 > elemV2) + return 1; + } + + return 0; +} diff --git a/tests/meson.build b/tests/meson.build index 1e84f423c..c0431631f 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -10,7 +10,7 @@ run_test = configure_file( testenv = environment() testenv.set('GSETTINGS_SCHEMA_DIR', join_paths(meson.build_root(), 'data')) -foreach test : ['insertSorted', 'jsParse', 'markup', 'params', 'url'] +foreach test : ['insertSorted', 'jsParse', 'markup', 'params', 'url', 'versionCompare'] test(test, run_test, args: 'unit/@0@.js'.format(test), env: testenv, diff --git a/tests/unit/versionCompare.js b/tests/unit/versionCompare.js new file mode 100644 index 000000000..1997a6c80 --- /dev/null +++ b/tests/unit/versionCompare.js @@ -0,0 +1,52 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +// Test cases for version comparison + +const JsUnit = imports.jsUnit; + +const Environment = imports.ui.environment; +Environment.init(); + +const Util = imports.misc.util; + +const tests = [ + { v1: '40', + v2: '40', + res: 0 }, + { v1: '40', + v2: '42', + res: -1 }, + { v1: '42', + v2: '40', + res: 1 }, + { v1: '3.38.0', + v2: '40', + res: -1 }, + { v1: '40', + v2: '3.38.0', + res: 1 }, + { v1: '40', + v2: '3.38.0', + res: 1 }, + { v1: '40.alpha.1.1', + v2: '40', + res: -1 }, + { v1: '40', + v2: '40.alpha.1.1', + res: 1 }, + { v1: '40.beta', + v2: '40', + res: -1 }, + { v1: '40.1', + v2: '40', + res: 1 }, + { v1: '', + v2: '40.alpha', + res: -1 }, +]; + +for (let i = 0; i < tests.length; i++) { + name = 'Test #' + i + ' v1: ' + tests[i].v1 + ', v2: ' + tests[i].v2; + print(name); + JsUnit.assertEquals(name, Util.GNOMEversionCompare (tests[i].v1, tests[i].v2), tests[i].res); +}