Explorar o código

Add compatibility checker tests

Steven Silvester %!s(int64=8) %!d(string=hai) anos
pai
achega
f6a63c8fa5
Modificáronse 2 ficheiros con 67 adicións e 45 borrados
  1. 51 42
      jupyterlab/commands.py
  2. 16 3
      jupyterlab/tests/test_jupyterlab.py

+ 51 - 42
jupyterlab/commands.py

@@ -466,48 +466,8 @@ def _validate_compatibility(extension, deps, core_data):
 
     for (key, value) in deps.items():
         if key in singletons:
-            # Test for overlapping semver ranges.
-            r1 = Range(core_deps[key], True)
-            r2 = Range(value, True)
-
-            # If either range is empty, we cannot verify.
-            if not r1.range or not r2.range:
-                continue
-
-            x1 = r1.set[0][0].semver
-            x2 = r1.set[0][-1].semver
-            y1 = r2.set[0][0].semver
-            y2 = r2.set[0][-1].semver
-
-            o1 = r1.set[0][0].operator
-            o2 = r2.set[0][0].operator
-
-            # We do not handle (<) specifiers.
-            if (o1.startswith('<') or o2.startswith('<')):
-                continue
-
-            # Handle single value specifiers.
-            lx = lte if x1 == x2 else lt
-            ly = lte if y1 == y2 else lt
-            gx = gte if x1 == x2 else gt
-            gy = gte if x1 == x2 else gt
-
-            # Handle unbounded (>) specifiers.
-            def noop(x, y, z):
-                return True
-
-            if x1 == x2 and o1.startswith('>'):
-                lx = noop
-            if y1 == y2 and o2.startswith('>'):
-                ly = noop
-
-            # Check for overlap.
-            overlap = (gte(x1, y1, True) and ly(x1, y2, True) or
-                       gy(x2, y1, True) and ly(x2, y2, True) or
-                       gte(y1, x1, True) and lx(y1, x2, True) or
-                       gx(y2, x1, True) and lx(y2, x2, True))
-
-            if not overlap:
+            overlap = _test_overlap(core_deps[key], value)
+            if overlap is False:
                 errors.append((key, core_deps[key], value))
 
     return errors
@@ -520,6 +480,55 @@ def _get_core_data():
         return json.load(fid)
 
 
+def _test_overlap(spec1, spec2):
+    """Test whether two version specs overlap.
+
+    Returns `None` if we cannot determine compatibility,
+    otherwise whether there is an overlap
+    """
+    # Test for overlapping semver ranges.
+    r1 = Range(spec1, True)
+    r2 = Range(spec2, True)
+
+    # If either range is empty, we cannot verify.
+    if not r1.range or not r2.range:
+        return
+
+    x1 = r1.set[0][0].semver
+    x2 = r1.set[0][-1].semver
+    y1 = r2.set[0][0].semver
+    y2 = r2.set[0][-1].semver
+
+    o1 = r1.set[0][0].operator
+    o2 = r2.set[0][0].operator
+
+    # We do not handle (<) specifiers.
+    if (o1.startswith('<') or o2.startswith('<')):
+        return
+
+    # Handle single value specifiers.
+    lx = lte if x1 == x2 else lt
+    ly = lte if y1 == y2 else lt
+    gx = gte if x1 == x2 else gt
+    gy = gte if x1 == x2 else gt
+
+    # Handle unbounded (>) specifiers.
+    def noop(x, y, z):
+        return True
+
+    if x1 == x2 and o1.startswith('>'):
+        lx = noop
+    if y1 == y2 and o2.startswith('>'):
+        ly = noop
+
+    # Check for overlap.
+    return (
+        gte(x1, y1, True) and ly(x1, y2, True) or
+        gy(x2, y1, True) and ly(x2, y2, True) or
+        gte(y1, x1, True) and lx(y1, x2, True) or
+        gx(y2, x1, True) and lx(y2, x2, True)
+    )
+
 def _format_compatibility_errors(name, version, errors):
     """Format a message for compatibility errors.
     """

+ 16 - 3
jupyterlab/tests/test_jupyterlab.py

@@ -29,7 +29,8 @@ from jupyterlab.commands import (
     install_extension, uninstall_extension, list_extensions,
     build, link_package, unlink_package, should_build,
     disable_extension, enable_extension, _get_extensions,
-    _get_linked_packages, _ensure_package, _get_disabled
+    _get_linked_packages, _ensure_package, _get_disabled,
+    _test_overlap
 )
 
 here = os.path.dirname(os.path.abspath(__file__))
@@ -130,7 +131,7 @@ class TestExtension(TestCase):
             install_extension(self.incompat_dir)
 
     def test_install_failed(self):
-        path = self.mockpackage
+        path = self.mock_package
         with pytest.raises(ValueError):
             install_extension(path)
         with open(pjoin(path, 'package.json')) as fid:
@@ -160,7 +161,7 @@ class TestExtension(TestCase):
         assert '@jupyterlab/python-tests' in _get_extensions(self.app_dir)
 
     def test_link_package(self):
-        path = self.mockpackage
+        path = self.mock_package
         link_package(path)
         linked = _get_linked_packages().keys()
         with open(pjoin(path, 'package.json')) as fid:
@@ -310,3 +311,15 @@ class TestExtension(TestCase):
         assert not should_build()[0]
         uninstall_extension('@jupyterlab/python-tests')
         assert should_build()[0]
+
+    def test_compatibility(self):
+        assert _test_overlap('^0.6.0', '^0.6.1')
+        assert _test_overlap('>0.1', '0.6')
+        assert _test_overlap('~0.5.0', '~0.5.2')
+        assert _test_overlap('0.5.2', '^0.5.0')
+
+        assert not _test_overlap('^0.5.0', '^0.6.0')
+        assert not _test_overlap('~1.5.0', '^1.6.0')
+
+        assert _test_overlap('*', '0.6') is None
+        assert _test_overlap('<0.6', '0.1') is None