Repository: shadowmoose/pyderman

Issue:
pyderman.install() returns error when specifying full version of chromedriver.
pyderman.install() returns error when specifying full version of chromedriver.

I'm looking at the latest commit (not officially released yet).  
https://github.com/shadowmoose/pyderman/commit/d377c81e5684fc637388254f0f78e52748b0df0c

```python
pyderman.install(browser=pyderman.chrome version="101.0.4951.41")
```
Results in: `Exception: Unable to locate ChromeDriver version: 101.0.4951.41!`

It appears to be related to the changes in https://github.com/shadowmoose/pyderman/pull/13/files

The code assumes that making a request to the following URL will return a version
https://chromedriver.storage.googleapis.com/LATEST_RELEASE_101.0.4951.41

Looking through the xml on https://chromedriver.storage.googleapis.com/ there does not appear to be the option for that version.  In fact I'm not seeing any options for `LATEST_RELEASE_X.X.X.X`. The options appear to be limited to `LATEST_RELEASE_X.X.X`

Looking up versions seems to work with the Major and patch versions.  These are valid lookups:

- https://chromedriver.storage.googleapis.com/LATEST_RELEASE_101
- https://chromedriver.storage.googleapis.com/LATEST_RELEASE_101.0.4951




Comments:

Patch:
diff --git a/pyderman/drivers/chrome.py b/pyderman/drivers/chrome.py
index 5b54fd6..7859b54 100644
--- a/pyderman/drivers/chrome.py
+++ b/pyderman/drivers/chrome.py
@@ -11,10 +11,16 @@ _base_download = "https://chromedriver.storage.googleapis.com/%s/chromedriver_%s
 def get_url(
     version: str = "latest", _os: str | None = None, _os_bit: str | None = None
 ) -> tuple[str, str, str]:
+    match = re.match(r"^(\d*)[.]?(\d*)[.]?(\d*)[.]?(\d*)$", version)
     if version == "latest":
         resolved_version = downloader.raw(_base_version)
-    elif re.match(r"\d+(\.\d+\.\d+)?", version):
-        resolved_version = downloader.raw("{}_{}".format(_base_version, version))
+    elif match:
+        major, minor, patch, build = match.groups()
+        if patch:
+            patch_version = "{}.{}.{}".format(major, minor, patch)
+        else:
+            patch_version = major
+        resolved_version = downloader.raw("{}_{}".format(_base_version, patch_version))
     else:
         resolved_version = version
     if not resolved_version:


Test patch:
diff --git a/pyderman/test.py b/pyderman/test.py
index 7ea9d03..127d25a 100644
--- a/pyderman/test.py
+++ b/pyderman/test.py
@@ -2,10 +2,19 @@ from __future__ import annotations
 
 import os
 import platform
+import re
 import subprocess
 import unittest
 from types import ModuleType
 
+try:
+    # Python 3
+    from urllib.request import urlopen
+except ImportError:
+    # Python 2
+    # noinspection PyUnresolvedReferences
+    from urllib2 import urlopen  # type: ignore[import,no-redef]
+
 from pyderman import chrome, edge, firefox, install, opera, phantomjs
 
 
@@ -59,5 +68,54 @@ class TestDriverInstalls(unittest.TestCase):
         process_driver(edge, self)
 
 
+class TestChrome(unittest.TestCase):
+    def setUp(self) -> None:
+        version_re = re.compile(r"^(\d+)\.(\d+)\.(\d+)\.(\d+)$")
+        url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE"
+        resp = urlopen(url, timeout=15)
+        html = resp.read().decode("utf-8", errors="ignore")
+        version_string = str(html)
+        self.latest = version_string
+
+        match = version_re.match(version_string)
+        if not match:
+            raise ValueError("Invalid version string: %r" % version_string)
+
+        major, minor, patch, build = match.groups()
+        self.major = major
+        self.minor = minor
+        self.patch = patch
+        self.build = build
+        return
+
+    def chrome_version(self, version: str) -> None:
+        drvr, url, vers = chrome.get_url(version, _os="mac", _os_bit="64")
+        self.assertEqual(vers, self.latest)
+        self.assertEqual(
+            url,
+            f"https://chromedriver.storage.googleapis.com/{self.latest}/chromedriver_mac64.zip",
+        )
+
+    def test_get_latest(self) -> None:
+        self.chrome_version("latest")
+
+    def test_get_major(self) -> None:
+        self.chrome_version(f"{self.major}")
+
+    def test_get_patch(self) -> None:
+        self.chrome_version(f"{self.major}.{self.minor}.{self.patch}")
+
+    def test_get_build(self) -> None:
+        self.chrome_version(f"{self.latest}")
+
+    def test_get_nonsense(self) -> None:
+        with self.assertRaises(Exception) as exc:
+            self.chrome_version("25.25.25.25")
+        self.assertEqual(
+            str(exc.exception), "Unable to locate ChromeDriver version: 25.25.25.25!"
+        )
+        return
+
+
 if __name__ == "__main__":
     unittest.main()