From 8112381e52b20a0d7652b9bfed973e8f45534b12 Mon Sep 17 00:00:00 2001
From: Sergei Zharinov <zharinov@users.noreply.github.com>
Date: Fri, 14 Jan 2022 08:39:55 +0300
Subject: [PATCH] test(maven): Integrate unit tests from Maven (#13551)

---
 lib/versioning/maven/compare.spec.ts | 520 ++++++++++++++++-----------
 lib/versioning/maven/readme.md       |  14 +
 2 files changed, 327 insertions(+), 207 deletions(-)

diff --git a/lib/versioning/maven/compare.spec.ts b/lib/versioning/maven/compare.spec.ts
index d4f5ace5d2..f15bec70b1 100644
--- a/lib/versioning/maven/compare.spec.ts
+++ b/lib/versioning/maven/compare.spec.ts
@@ -6,218 +6,324 @@ import {
 } from './compare';
 
 describe('versioning/maven/compare', () => {
-  describe('Non-standard behavior', () => {
-    test.each`
-      a               | b                | expected
-      ${'1-ga-1'}     | ${'1-1'}         | ${0}
-      ${'1.0-SNAP'}   | ${'1-snapshot'}  | ${0}
-      ${'1.0rc'}      | ${'1.0-preview'} | ${0}
-      ${'v1.2.3'}     | ${'1.2.3'}       | ${0}
-      ${'v0.0-1552'}  | ${'0.0-1552'}    | ${0}
-      ${'v0.0.1'}     | ${'0.0.1'}       | ${0}
-      ${'1-snap'}     | ${'1'}           | ${-1}
-      ${'1-preview'}  | ${'1-snapshot'}  | ${-1}
-      ${'1'}          | ${'1-snap'}      | ${1}
-      ${'1-snapshot'} | ${'1-preview'}   | ${1}
-    `('compare("$a", "$b") === $expected', ({ a, b, expected }) => {
-      expect(compare(a, b)).toEqual(expected);
+  describe('Standard behavior', () => {
+    // @see https://github.com/apache/maven/blob/master/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java
+    // @see https://github.com/apache/maven/blob/master/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/DefaultArtifactVersionTest.java
+    describe('equality', () => {
+      test.each`
+        x                       | y
+        ${'1'}                  | ${'1'}
+        ${'1'}                  | ${'1.0'}
+        ${'1'}                  | ${'1.0.0'}
+        ${'1.0'}                | ${'1.0.0'}
+        ${'1'}                  | ${'1-0'}
+        ${'1'}                  | ${'1.0-0'}
+        ${'1.0'}                | ${'1.0-0'}
+        ${'1a'}                 | ${'1-a'}
+        ${'1a'}                 | ${'1.0-a'}
+        ${'1a'}                 | ${'1.0.0-a'}
+        ${'1.0a'}               | ${'1-a'}
+        ${'1.0.0a'}             | ${'1-a'}
+        ${'1x'}                 | ${'1-x'}
+        ${'1x'}                 | ${'1.0-x'}
+        ${'1x'}                 | ${'1.0.0-x'}
+        ${'1.0x'}               | ${'1-x'}
+        ${'1.0.0x'}             | ${'1-x'}
+        ${'1ga'}                | ${'1'}
+        ${'1release'}           | ${'1'}
+        ${'1final'}             | ${'1'}
+        ${'1cr'}                | ${'1rc'}
+        ${'1a1'}                | ${'1-alpha-1'}
+        ${'1b2'}                | ${'1-beta-2'}
+        ${'1m3'}                | ${'1-milestone-3'}
+        ${'1X'}                 | ${'1x'}
+        ${'1A'}                 | ${'1a'}
+        ${'1B'}                 | ${'1b'}
+        ${'1M'}                 | ${'1m'}
+        ${'1Ga'}                | ${'1'}
+        ${'1GA'}                | ${'1'}
+        ${'1RELEASE'}           | ${'1'}
+        ${'1release'}           | ${'1'}
+        ${'1RELeaSE'}           | ${'1'}
+        ${'1Final'}             | ${'1'}
+        ${'1FinaL'}             | ${'1'}
+        ${'1FINAL'}             | ${'1'}
+        ${'1Cr'}                | ${'1Rc'}
+        ${'1cR'}                | ${'1rC'}
+        ${'1m3'}                | ${'1Milestone3'}
+        ${'1m3'}                | ${'1MileStone3'}
+        ${'1m3'}                | ${'1MILESTONE3'}
+        ${'2.0-0'}              | ${'2.0'}
+        ${'1.0.0'}              | ${'1'}
+        ${'1-a1'}               | ${'1-alpha-1'}
+        ${'1-b1'}               | ${'1-beta-1'}
+        ${'1.0.0'}              | ${'1.ga'}
+        ${'1-ga'}               | ${'1.ga'}
+        ${'1.final'}            | ${'1.0'}
+        ${'1'}                  | ${'1.0'}
+        ${'1.'}                 | ${'1-'}
+        ${'1.0.0-0.0.0'}        | ${'1-final'}
+        ${'1-1.foo-bar1baz-.1'} | ${'1-1.foo-bar-1-baz-0.1'}
+        ${'1.0ALPHA1'}          | ${'1.0-a1'}
+        ${'1.0Alpha1'}          | ${'1.0-a1'}
+        ${'1.0AlphA1'}          | ${'1.0-a1'}
+        ${'1.0BETA1'}           | ${'1.0-b1'}
+        ${'1.0MILESTONE1'}      | ${'1.0-m1'}
+        ${'1.0RC1'}             | ${'1.0-cr1'}
+        ${'1.0GA'}              | ${'1.0'}
+        ${'1.0FINAL'}           | ${'1.0'}
+        ${'1.0-SNAPSHOT'}       | ${'1-snapshot'}
+        ${'1.0alpha1'}          | ${'1.0-a1'}
+        ${'1.0alpha-1'}         | ${'1.0-a1'}
+        ${'1.0beta1'}           | ${'1.0-b1'}
+        ${'1.0beta-1'}          | ${'1.0-b1'}
+        ${'1.0milestone1'}      | ${'1.0-m1'}
+        ${'1.0milestone-1'}     | ${'1.0-m1'}
+        ${'1.0rc1'}             | ${'1.0-cr1'}
+        ${'1.0rc-1'}            | ${'1.0-cr1'}
+        ${'1.0ga'}              | ${'1.0'}
+        ${'1-0.ga'}             | ${'1.0'}
+        ${'1.0-final'}          | ${'1.0'}
+        ${'1-0-ga'}             | ${'1.0'}
+        ${'1-0-final'}          | ${'1-0'}
+        ${'1-0'}                | ${'1.0'}
+        ${'0.0-1552'}           | ${'0.0-1552'}
+        ${'5.0.7'}              | ${'5.0.7.RELEASE'}
+        ${'Hoxton.RELEASE'}     | ${'hoxton'}
+        ${'Hoxton.SR1'}         | ${'hoxton.sr-1'}
+      `('$x == $y', ({ x, y }) => {
+        expect(compare(x, y)).toBe(0);
+        expect(compare(y, x)).toBe(0);
+      });
     });
-  });
 
-  test.each`
-    a                       | b                          | expected
-    ${'1.0.0'}              | ${'1'}                     | ${0}
-    ${'1-a1'}               | ${'1-alpha-1'}             | ${0}
-    ${'1-b1'}               | ${'1-beta-1'}              | ${0}
-    ${'1.0.0'}              | ${'1.ga'}                  | ${0}
-    ${'1-ga'}               | ${'1.ga'}                  | ${0}
-    ${'1.final'}            | ${'1.0'}                   | ${0}
-    ${'1'}                  | ${'1.0'}                   | ${0}
-    ${'1.'}                 | ${'1-'}                    | ${0}
-    ${'1.0.0-0.0.0'}        | ${'1-final'}               | ${0}
-    ${'1-1.foo-bar1baz-.1'} | ${'1-1.foo-bar-1-baz-0.1'} | ${0}
-    ${'1.0ALPHA1'}          | ${'1.0-a1'}                | ${0}
-    ${'1.0Alpha1'}          | ${'1.0-a1'}                | ${0}
-    ${'1.0AlphA1'}          | ${'1.0-a1'}                | ${0}
-    ${'1.0BETA1'}           | ${'1.0-b1'}                | ${0}
-    ${'1.0MILESTONE1'}      | ${'1.0-m1'}                | ${0}
-    ${'1.0RC1'}             | ${'1.0-cr1'}               | ${0}
-    ${'1.0GA'}              | ${'1.0'}                   | ${0}
-    ${'1.0FINAL'}           | ${'1.0'}                   | ${0}
-    ${'1.0-SNAPSHOT'}       | ${'1-snapshot'}            | ${0}
-    ${'1.0alpha1'}          | ${'1.0-a1'}                | ${0}
-    ${'1.0alpha-1'}         | ${'1.0-a1'}                | ${0}
-    ${'1.0beta1'}           | ${'1.0-b1'}                | ${0}
-    ${'1.0beta-1'}          | ${'1.0-b1'}                | ${0}
-    ${'1.0milestone1'}      | ${'1.0-m1'}                | ${0}
-    ${'1.0milestone-1'}     | ${'1.0-m1'}                | ${0}
-    ${'1.0rc1'}             | ${'1.0-cr1'}               | ${0}
-    ${'1.0rc-1'}            | ${'1.0-cr1'}               | ${0}
-    ${'1.0ga'}              | ${'1.0'}                   | ${0}
-    ${'1-0.ga'}             | ${'1.0'}                   | ${0}
-    ${'1.0-final'}          | ${'1.0'}                   | ${0}
-    ${'1-0-ga'}             | ${'1.0'}                   | ${0}
-    ${'1-0-final'}          | ${'1-0'}                   | ${0}
-    ${'1-0'}                | ${'1.0'}                   | ${0}
-    ${'0.0-1552'}           | ${'0.0-1552'}              | ${0}
-    ${'5.0.7'}              | ${'5.0.7.RELEASE'}         | ${0}
-    ${'Hoxton.RELEASE'}     | ${'hoxton'}                | ${0}
-    ${'Hoxton.SR1'}         | ${'hoxton.sr-1'}           | ${0}
-    ${'1'}                  | ${'1.1'}                   | ${-1}
-    ${'1'}                  | ${'2'}                     | ${-1}
-    ${'1-snapshot'}         | ${'1'}                     | ${-1}
-    ${'1.2.3-snap1'}        | ${'1.2.3-snap2'}           | ${-1}
-    ${'1'}                  | ${'1-sp'}                  | ${-1}
-    ${'1-foo2'}             | ${'1-foo10'}               | ${-1}
-    ${'1-m1'}               | ${'1-milestone-2'}         | ${-1}
-    ${'1.foo'}              | ${'1-foo'}                 | ${-1}
-    ${'1-foo'}              | ${'1-1'}                   | ${-1}
-    ${'1-alpha.1'}          | ${'1-beta.1'}              | ${-1}
-    ${'1-1'}                | ${'1.1'}                   | ${-1}
-    ${'1-ga'}               | ${'1-ap'}                  | ${-1}
-    ${'1-ga.1'}             | ${'1-sp.1'}                | ${-1}
-    ${'1-sp-1'}             | ${'1-ga-1'}                | ${-1}
-    ${'1-cr1'}              | ${'1'}                     | ${-1}
-    ${'0.0-1552'}           | ${'1.10.520'}              | ${-1}
-    ${'0.0.1'}              | ${'999'}                   | ${-1}
-    ${'1.3-RC1-groovy-2.5'} | ${'1.3-groovy-2.5'}        | ${-1}
-    ${'1-abc'}              | ${'1-xyz'}                 | ${-1}
-    ${'Hoxton.RELEASE'}     | ${'Hoxton.SR1'}            | ${-1}
-    ${'1.1'}                | ${'1'}                     | ${1}
-    ${'2'}                  | ${'1'}                     | ${1}
-    ${'1'}                  | ${'1-snapshot'}            | ${1}
-    ${'1.2.3-snap2'}        | ${'1.2.3-snap1'}           | ${1}
-    ${'1-sp'}               | ${'1'}                     | ${1}
-    ${'1-foo10'}            | ${'1-foo2'}                | ${1}
-    ${'1-milestone-2'}      | ${'1-m1'}                  | ${1}
-    ${'1-foo'}              | ${'1.foo'}                 | ${1}
-    ${'1-1'}                | ${'1-foo'}                 | ${1}
-    ${'1-beta.1'}           | ${'1-alpha.1'}             | ${1}
-    ${'1.1'}                | ${'1-1'}                   | ${1}
-    ${'1-sp'}               | ${'1-ga'}                  | ${1}
-    ${'1-sp.1'}             | ${'1-ga.1'}                | ${1}
-    ${'1-ga-1'}             | ${'1-sp-1'}                | ${1}
-    ${'1'}                  | ${'1-cr1'}                 | ${1}
-    ${'1.10.520'}           | ${'0.0-1552'}              | ${1}
-    ${'999'}                | ${'0.0.1'}                 | ${1}
-    ${'1.3-groovy-2.5'}     | ${'1.3-RC1-groovy-2.5'}    | ${1}
-    ${'1-snapshot'}         | ${'1-milestone'}           | ${1}
-    ${'1-xyz'}              | ${'1-abc'}                 | ${1}
-    ${'Hoxton.SR1'}         | ${'Hoxton.RELEASE'}        | ${1}
-  `('compare("$a", "$b") === $expected', ({ a, b, expected }) => {
-    expect(compare(a, b)).toEqual(expected);
+    describe('ordering', () => {
+      test.each`
+        x                                               | y
+        ${'1'}                                          | ${'2'}
+        ${'1.5'}                                        | ${'2'}
+        ${'1'}                                          | ${'2.5'}
+        ${'1.0'}                                        | ${'1.1'}
+        ${'1.1'}                                        | ${'1.2'}
+        ${'1.0.0'}                                      | ${'1.1'}
+        ${'1.0.1'}                                      | ${'1.1'}
+        ${'1.1'}                                        | ${'1.2.0'}
+        ${'1.0-alpha-1'}                                | ${'1.0'}
+        ${'1.0-alpha-1'}                                | ${'1.0-alpha-2'}
+        ${'1.0-alpha-1'}                                | ${'1.0-beta-1'}
+        ${'1.0-beta-1'}                                 | ${'1.0-SNAPSHOT'}
+        ${'1.0-SNAPSHOT'}                               | ${'1.0'}
+        ${'1.0-alpha-1-SNAPSHOT'}                       | ${'1.0-alpha-1'}
+        ${'1.0'}                                        | ${'1.0-1'}
+        ${'1.0-1'}                                      | ${'1.0-2'}
+        ${'1.0.0'}                                      | ${'1.0-1'}
+        ${'2.0-1'}                                      | ${'2.0.1'}
+        ${'2.0.1-klm'}                                  | ${'2.0.1-lmn'}
+        ${'2.0.1'}                                      | ${'2.0.1-xyz'}
+        ${'2.0.1'}                                      | ${'2.0.1-123'}
+        ${'2.0.1-xyz'}                                  | ${'2.0.1-123'}
+        ${'1'}                                          | ${'2'}
+        ${'1.5'}                                        | ${'2'}
+        ${'1'}                                          | ${'2.5'}
+        ${'1.0'}                                        | ${'1.1'}
+        ${'1.1'}                                        | ${'1.2'}
+        ${'1.0.0'}                                      | ${'1.1'}
+        ${'1.1'}                                        | ${'1.2.0'}
+        ${'1.1.2.alpha1'}                               | ${'1.1.2'}
+        ${'1.1.2.alpha1'}                               | ${'1.1.2.beta1'}
+        ${'1.1.2.beta1'}                                | ${'1.2'}
+        ${'1.0-alpha-1'}                                | ${'1.0'}
+        ${'1.0-alpha-1'}                                | ${'1.0-alpha-2'}
+        ${'1.0-alpha-2'}                                | ${'1.0-alpha-15'}
+        ${'1.0-alpha-1'}                                | ${'1.0-beta-1'}
+        ${'1.0-beta-1'}                                 | ${'1.0-SNAPSHOT'}
+        ${'1.0-SNAPSHOT'}                               | ${'1.0'}
+        ${'1.0-alpha-1-SNAPSHOT'}                       | ${'1.0-alpha-1'}
+        ${'1.0'}                                        | ${'1.0-1'}
+        ${'1.0-1'}                                      | ${'1.0-2'}
+        ${'2.0'}                                        | ${'2.0-1'}
+        ${'2.0.0'}                                      | ${'2.0-1'}
+        ${'2.0-1'}                                      | ${'2.0.1'}
+        ${'2.0.1-klm'}                                  | ${'2.0.1-lmn'}
+        ${'2.0.1'}                                      | ${'2.0.1-xyz'}
+        ${'2.0.1-xyz-1'}                                | ${'2.0.1-1-xyz'}
+        ${'2.0.1'}                                      | ${'2.0.1-123'}
+        ${'2.0.1-xyz'}                                  | ${'2.0.1-123'}
+        ${'1.2.3-10000000000'}                          | ${'1.2.3-10000000001'}
+        ${'1.2.3-1'}                                    | ${'1.2.3-10000000001'}
+        ${'2.3.0-v200706262000'}                        | ${'2.3.0-v200706262130'}
+        ${'2.0.0.v200706041905-7C78EK9E_EkMNfNOd2d8qq'} | ${'2.0.0.v200706041906-7C78EK9E_EkMNfNOd2d8qq'}
+        ${'1.0-RC1'}                                    | ${'1.0-SNAPSHOT'}
+        ${'1.0-rc1'}                                    | ${'1.0-SNAPSHOT'}
+        ${'1.0-rc-1'}                                   | ${'1.0-SNAPSHOT'}
+        ${'1'}                                          | ${'1.1'}
+        ${'1'}                                          | ${'2'}
+        ${'1-snapshot'}                                 | ${'1'}
+        ${'1.2.3-snap1'}                                | ${'1.2.3-snap2'}
+        ${'1'}                                          | ${'1-sp'}
+        ${'1-foo2'}                                     | ${'1-foo10'}
+        ${'1-m1'}                                       | ${'1-milestone-2'}
+        ${'1.foo'}                                      | ${'1-foo'}
+        ${'1-foo'}                                      | ${'1-1'}
+        ${'1-alpha.1'}                                  | ${'1-beta.1'}
+        ${'1-1'}                                        | ${'1.1'}
+        ${'1-ga'}                                       | ${'1-sp'}
+        ${'1-ga.1'}                                     | ${'1-sp.1'}
+        ${'1-sp-1'}                                     | ${'1-ga-1'}
+        ${'1-cr1'}                                      | ${'1'}
+        ${'0.0-1552'}                                   | ${'1.10.520'}
+        ${'0.0.1'}                                      | ${'999'}
+        ${'1.3-RC1-groovy-2.5'}                         | ${'1.3-groovy-2.5'}
+        ${'1-milestone'}                                | ${'1-snapshot'}
+        ${'1-abc'}                                      | ${'1-xyz'}
+        ${'Hoxton.RELEASE'}                             | ${'Hoxton.SR1'}
+      `('$x < $y', ({ x, y }) => {
+        expect(compare(x, y)).toBe(-1);
+        expect(compare(y, x)).toBe(1);
+      });
+    });
   });
 
-  test.each`
-    input
-    ${'1.2.3-SNAPSHOT'}
-    ${'[]'}
-    ${'[,]'}
-    ${'('}
-    ${'['}
-    ${','}
-    ${'[1.0'}
-    ${'1.0]'}
-    ${'[1.0],'}
-    ${',[1.0]'}
-    ${'(,1.1),(1.0,)'}
-    ${'(0,1.1),(1.0,2.0)'}
-    ${'(0,1.1),(,2.0)'}
-    ${'(,1.0],,[1.2,)'}
-    ${'(,1.0],[1.2,),'}
-    ${'[1.5,]'}
-    ${'[2.0,1.0)'}
-    ${'[1.2,1.3],1.4'}
-    ${'[1.2,,1.3]'}
-    ${'[1.3,1.2]'}
-    ${'[1,[2,3],4]'}
-    ${'[,1.0]'}
-    ${'[,1.0],[,1.0]'}
-  `('filters out incorrect range: $input', ({ input }) => {
-    const range = parseRange(input);
-    expect(range).toBeNull();
-    expect(rangeToStr(range)).toBeNull();
+  describe('Non-standard behavior', () => {
+    describe('equality', () => {
+      test.each`
+        x              | y
+        ${'1-ga-1'}    | ${'1-1'}
+        ${'1.0-SNAP'}  | ${'1-snapshot'}
+        ${'1.0rc'}     | ${'1.0-preview'}
+        ${'v1.2.3'}    | ${'1.2.3'}
+        ${'v0.0-1552'} | ${'0.0-1552'}
+        ${'v0.0.1'}    | ${'0.0.1'}
+      `('$x == $y', ({ x, y }) => {
+        expect(compare(x, y)).toBe(0);
+        expect(compare(y, x)).toBe(0);
+      });
+    });
+
+    describe('ordering', () => {
+      test.each`
+        x              | y
+        ${'1-snap'}    | ${'1'}
+        ${'1-preview'} | ${'1-snapshot'}
+      `('$x < $y', ({ x, y }) => {
+        expect(compare(x, y)).toBe(-1);
+        expect(compare(y, x)).toBe(1);
+      });
+    });
   });
 
-  test.each`
-    input          | leftType             | leftValue | leftBracket | rightType            | rightValue | rightBracket
-    ${'[1.0]'}     | ${'INCLUDING_POINT'} | ${'1.0'}  | ${'['}      | ${'INCLUDING_POINT'} | ${'1.0'}   | ${']'}
-    ${'(,1.0]'}    | ${'EXCLUDING_POINT'} | ${null}   | ${'('}      | ${'INCLUDING_POINT'} | ${'1.0'}   | ${']'}
-    ${'[1.2,1.3]'} | ${'INCLUDING_POINT'} | ${'1.2'}  | ${'['}      | ${'INCLUDING_POINT'} | ${'1.3'}   | ${']'}
-    ${'[1.0,2.0)'} | ${'INCLUDING_POINT'} | ${'1.0'}  | ${'['}      | ${'EXCLUDING_POINT'} | ${'2.0'}   | ${')'}
-    ${'[1.5,)'}    | ${'INCLUDING_POINT'} | ${'1.5'}  | ${'['}      | ${'EXCLUDING_POINT'} | ${null}    | ${')'}
-  `(
-    'parseRange("$input")',
-    ({
-      input,
-      leftType,
-      leftValue,
-      leftBracket,
-      rightType,
-      rightValue,
-      rightBracket,
-    }) => {
-      const parseResult = [
-        {
-          leftType,
-          leftValue,
-          leftBracket,
-          rightType,
-          rightValue,
-          rightBracket,
-        },
-      ];
-      expect(parseRange(input)).toEqual(parseResult);
-      expect(rangeToStr(parseResult as never)).toEqual(input);
-    }
-  );
+  describe('Ranges', () => {
+    test.each`
+      input
+      ${'1.2.3-SNAPSHOT'}
+      ${'[]'}
+      ${'[,]'}
+      ${'('}
+      ${'['}
+      ${','}
+      ${'[1.0'}
+      ${'1.0]'}
+      ${'[1.0],'}
+      ${',[1.0]'}
+      ${'(,1.1),(1.0,)'}
+      ${'(0,1.1),(1.0,2.0)'}
+      ${'(0,1.1),(,2.0)'}
+      ${'(,1.0],,[1.2,)'}
+      ${'(,1.0],[1.2,),'}
+      ${'[1.5,]'}
+      ${'[2.0,1.0)'}
+      ${'[1.2,1.3],1.4'}
+      ${'[1.2,,1.3]'}
+      ${'[1.3,1.2]'}
+      ${'[1,[2,3],4]'}
+      ${'[,1.0]'}
+      ${'[,1.0],[,1.0]'}
+    `('filters out incorrect range: $input', ({ input }) => {
+      const range = parseRange(input);
+      expect(range).toBeNull();
+      expect(rangeToStr(range)).toBeNull();
+    });
 
-  test.each`
-    range                      | version      | expected
-    ${'[1.2.3]'}               | ${'1.2.3'}   | ${'[1.2.3]'}
-    ${'[1.2.3]'}               | ${'1.2.4'}   | ${'[1.2.4]'}
-    ${'[1.0.0,1.2.3]'}         | ${'0.0.1'}   | ${'[1.0.0,1.2.3]'}
-    ${'[1.0.0,1.2.3]'}         | ${'1.2.4'}   | ${'[1.0.0,1.2.4]'}
-    ${'[1.0.0,1.2.23]'}        | ${'1.1.0'}   | ${'[1.0.0,1.2.23]'}
-    ${'(,1.0]'}                | ${'2.0'}     | ${'(,2.0]'}
-    ${'],1.0]'}                | ${'2.0'}     | ${'],2.0]'}
-    ${'(,1.0)'}                | ${'2.0'}     | ${'(,3.0)'}
-    ${'],1.0['}                | ${'2.0'}     | ${'],3.0['}
-    ${'[1.0,1.2.3],[1.3,1.5)'} | ${'1.2.4'}   | ${'[1.0,1.2.4],[1.3,1.5)'}
-    ${'[1.0,1.2.3],[1.3,1.5['} | ${'1.2.4'}   | ${'[1.0,1.2.4],[1.3,1.5['}
-    ${'[1.2.3,)'}              | ${'1.2.4'}   | ${'[1.2.4,)'}
-    ${'[1.2.3,['}              | ${'1.2.4'}   | ${'[1.2.4,['}
-    ${'[1.2.3,]'}              | ${'1.2.4'}   | ${'[1.2.3,]'}
-    ${'[0.21,0.22)'}           | ${'0.20.21'} | ${'[0.21,0.22)'}
-    ${'[0.21,0.22)'}           | ${'0.21.1'}  | ${'[0.21,0.22)'}
-    ${'[0.21,0.22.0)'}         | ${'0.22.1'}  | ${'[0.21,0.22.2)'}
-    ${'[0.21,0.22)'}           | ${'0.23'}    | ${'[0.23,0.24)'}
-    ${'[1.8,1.9)'}             | ${'1.9.0.1'} | ${'[1.9,1.10)'}
-    ${'[1.8a,1.9)'}            | ${'1.9.0.1'} | ${'[1.8a,1.10)'}
-    ${'[1.8,1.9.0)'}           | ${'1.9.0.1'} | ${'[1.8,1.10.0)'}
-    ${'[1.8,1.9.0.0)'}         | ${'1.9.0.1'} | ${'[1.8,1.9.0.2)'}
-    ${'[1.8,1.9.0.0)'}         | ${'1.10.1'}  | ${'[1.8,1.10.2.0)'}
-    ${'[1.8,1.9)'}             | ${'1.9.1'}   | ${'[1.9,1.10)'}
-    ${'[1.8,1.9)'}             | ${'1.10.0'}  | ${'[1.10,1.11)'}
-    ${'[1.8,1.9)'}             | ${'1.10.1'}  | ${'[1.10,1.11)'}
-    ${'(,1.0.0]'}              | ${'2.0.0'}   | ${'(,2.0.0]'}
-    ${'(,1.0]'}                | ${'2.0.0'}   | ${'(,2.0]'}
-    ${'(,1]'}                  | ${'2.0.0'}   | ${'(,2]'}
-    ${'(,1.0.0-foobar]'}       | ${'2.0.0'}   | ${'(,2.0.0]'}
-    ${'[1,2]'}                 | ${'2'}       | ${'[1,2]'}
-    ${'[1,2)'}                 | ${'2'}       | ${'[2,3)'}
-    ${'[0,2)'}                 | ${'2'}       | ${'[0,3)'}
-    ${'[1.2,1.3]'}             | ${'1.3'}     | ${'[1.2,1.3]'}
-    ${'[1.2,1.3)'}             | ${'1.3'}     | ${'[1.3,1.4)'}
-    ${'[1.1,1.3)'}             | ${'1.3'}     | ${'[1.1,1.4)'}
-    ${'[1.2.3,1.2.4]'}         | ${'1.2.4'}   | ${'[1.2.3,1.2.4]'}
-    ${'[1.2.3,1.2.4)'}         | ${'1.2.4'}   | ${'[1.2.4,1.2.5)'}
-    ${'[1.2.1,1.2.4)'}         | ${'1.2.4'}   | ${'[1.2.1,1.2.5)'}
-    ${'[1,1.2.3)'}             | ${'1.2.3'}   | ${'[1,1.2.4)'}
-  `(
-    'autoExtendMavenRange("$range", "$version") === $expected',
-    ({ range, version, expected }) => {
-      expect(autoExtendMavenRange(range, version)).toEqual(expected);
-    }
-  );
+    test.each`
+      input          | leftType             | leftValue | leftBracket | rightType            | rightValue | rightBracket
+      ${'[1.0]'}     | ${'INCLUDING_POINT'} | ${'1.0'}  | ${'['}      | ${'INCLUDING_POINT'} | ${'1.0'}   | ${']'}
+      ${'(,1.0]'}    | ${'EXCLUDING_POINT'} | ${null}   | ${'('}      | ${'INCLUDING_POINT'} | ${'1.0'}   | ${']'}
+      ${'[1.2,1.3]'} | ${'INCLUDING_POINT'} | ${'1.2'}  | ${'['}      | ${'INCLUDING_POINT'} | ${'1.3'}   | ${']'}
+      ${'[1.0,2.0)'} | ${'INCLUDING_POINT'} | ${'1.0'}  | ${'['}      | ${'EXCLUDING_POINT'} | ${'2.0'}   | ${')'}
+      ${'[1.5,)'}    | ${'INCLUDING_POINT'} | ${'1.5'}  | ${'['}      | ${'EXCLUDING_POINT'} | ${null}    | ${')'}
+    `(
+      'parseRange("$input")',
+      ({
+        input,
+        leftType,
+        leftValue,
+        leftBracket,
+        rightType,
+        rightValue,
+        rightBracket,
+      }) => {
+        const parseResult = [
+          {
+            leftType,
+            leftValue,
+            leftBracket,
+            rightType,
+            rightValue,
+            rightBracket,
+          },
+        ];
+        expect(parseRange(input)).toEqual(parseResult);
+        expect(rangeToStr(parseResult as never)).toEqual(input);
+      }
+    );
+
+    test.each`
+      range                      | version      | expected
+      ${'[1.2.3]'}               | ${'1.2.3'}   | ${'[1.2.3]'}
+      ${'[1.2.3]'}               | ${'1.2.4'}   | ${'[1.2.4]'}
+      ${'[1.0.0,1.2.3]'}         | ${'0.0.1'}   | ${'[1.0.0,1.2.3]'}
+      ${'[1.0.0,1.2.3]'}         | ${'1.2.4'}   | ${'[1.0.0,1.2.4]'}
+      ${'[1.0.0,1.2.23]'}        | ${'1.1.0'}   | ${'[1.0.0,1.2.23]'}
+      ${'(,1.0]'}                | ${'2.0'}     | ${'(,2.0]'}
+      ${'],1.0]'}                | ${'2.0'}     | ${'],2.0]'}
+      ${'(,1.0)'}                | ${'2.0'}     | ${'(,3.0)'}
+      ${'],1.0['}                | ${'2.0'}     | ${'],3.0['}
+      ${'[1.0,1.2.3],[1.3,1.5)'} | ${'1.2.4'}   | ${'[1.0,1.2.4],[1.3,1.5)'}
+      ${'[1.0,1.2.3],[1.3,1.5['} | ${'1.2.4'}   | ${'[1.0,1.2.4],[1.3,1.5['}
+      ${'[1.2.3,)'}              | ${'1.2.4'}   | ${'[1.2.4,)'}
+      ${'[1.2.3,['}              | ${'1.2.4'}   | ${'[1.2.4,['}
+      ${'[1.2.3,]'}              | ${'1.2.4'}   | ${'[1.2.3,]'}
+      ${'[0.21,0.22)'}           | ${'0.20.21'} | ${'[0.21,0.22)'}
+      ${'[0.21,0.22)'}           | ${'0.21.1'}  | ${'[0.21,0.22)'}
+      ${'[0.21,0.22.0)'}         | ${'0.22.1'}  | ${'[0.21,0.22.2)'}
+      ${'[0.21,0.22)'}           | ${'0.23'}    | ${'[0.23,0.24)'}
+      ${'[1.8,1.9)'}             | ${'1.9.0.1'} | ${'[1.9,1.10)'}
+      ${'[1.8a,1.9)'}            | ${'1.9.0.1'} | ${'[1.8a,1.10)'}
+      ${'[1.8,1.9.0)'}           | ${'1.9.0.1'} | ${'[1.8,1.10.0)'}
+      ${'[1.8,1.9.0.0)'}         | ${'1.9.0.1'} | ${'[1.8,1.9.0.2)'}
+      ${'[1.8,1.9.0.0)'}         | ${'1.10.1'}  | ${'[1.8,1.10.2.0)'}
+      ${'[1.8,1.9)'}             | ${'1.9.1'}   | ${'[1.9,1.10)'}
+      ${'[1.8,1.9)'}             | ${'1.10.0'}  | ${'[1.10,1.11)'}
+      ${'[1.8,1.9)'}             | ${'1.10.1'}  | ${'[1.10,1.11)'}
+      ${'(,1.0.0]'}              | ${'2.0.0'}   | ${'(,2.0.0]'}
+      ${'(,1.0]'}                | ${'2.0.0'}   | ${'(,2.0]'}
+      ${'(,1]'}                  | ${'2.0.0'}   | ${'(,2]'}
+      ${'(,1.0.0-foobar]'}       | ${'2.0.0'}   | ${'(,2.0.0]'}
+      ${'[1,2]'}                 | ${'2'}       | ${'[1,2]'}
+      ${'[1,2)'}                 | ${'2'}       | ${'[2,3)'}
+      ${'[0,2)'}                 | ${'2'}       | ${'[0,3)'}
+      ${'[1.2,1.3]'}             | ${'1.3'}     | ${'[1.2,1.3]'}
+      ${'[1.2,1.3)'}             | ${'1.3'}     | ${'[1.3,1.4)'}
+      ${'[1.1,1.3)'}             | ${'1.3'}     | ${'[1.1,1.4)'}
+      ${'[1.2.3,1.2.4]'}         | ${'1.2.4'}   | ${'[1.2.3,1.2.4]'}
+      ${'[1.2.3,1.2.4)'}         | ${'1.2.4'}   | ${'[1.2.4,1.2.5)'}
+      ${'[1.2.1,1.2.4)'}         | ${'1.2.4'}   | ${'[1.2.1,1.2.5)'}
+      ${'[1,1.2.3)'}             | ${'1.2.3'}   | ${'[1,1.2.4)'}
+    `(
+      'autoExtendMavenRange("$range", "$version") === $expected',
+      ({ range, version, expected }) => {
+        expect(autoExtendMavenRange(range, version)).toEqual(expected);
+      }
+    );
+  });
 });
diff --git a/lib/versioning/maven/readme.md b/lib/versioning/maven/readme.md
index b59105f940..4512769a5d 100644
--- a/lib/versioning/maven/readme.md
+++ b/lib/versioning/maven/readme.md
@@ -1,3 +1,17 @@
 Maven versioning is similar to SemVer but also very different in places. It's specified by Maven itself.
 
 Ranges are supported using Maven's special syntax.
+
+For development purposes, download [maven-artifact JAR](https://mvnrepository.com/artifact/org.apache.maven/maven-artifact/3.8.4) and run:
+
+```sh
+$ java -jar maven-artifact-*.jar 3.2.4-alpha-1 3.2.4-SNAPSHOT 3.2.4.0
+Display parameters as parsed by Maven (in canonical form) and comparison result:
+1. 3.2.4-alpha-1 == 3.2.4.alpha.1
+   3.2.4-alpha-1 < 3.2.4-SNAPSHOT
+2. 3.2.4-SNAPSHOT == 3.2.4.snapshot
+   3.2.4-SNAPSHOT < 3.2.4.0
+3. 3.2.4.0 == 3.2.4
+```
+
+Also, take a look at [maven-cmp](https://github.com/zharinov/maven-cmp) utility.
-- 
GitLab