Repository: Senth/minecraft-mod-manager (python)

Issue:
mcman crashes with lazy-language-loader
### Describe the bug 
Minecraft Mod Manager crashes when attempting to download the lazy language loader mod

### Steps to reproduce
Steps to reproduce the behavior:
1. have lazy-language-loader in your mods folder
2. Then ran `mmm update -v 1.18 --beta --mod-loader fabric --verbose`

### Expected Behavior
Lazy language loader should be updated

### Info
 - OS: Windows 10 ver 21H1
 - Python --version: 3.10.0
 - minecraft-mod-manager --version: 1.2.4


Pull request:
Fix if Modrinth versions had empty 'files' array.
### What changed?
- Catches IndexError and skips that version

### Testing
- [X] Added unit tests
- [ ] Added integration tests
- [ ] ...Your own tests...

### Related Issues
Fixes #145


Patch:
diff --git a/.gitignore b/.gitignore
index 8af626a..fa4dbfc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,3 @@
 .vscode
 **/__pycache__
-debug.log
-/mods
-node_modules
-packages
-.yarn
-coverage
-.eslintrc
+temp
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 081cc84..76907c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed
 
-- Failed to get information from some forge mods if they contained inline comments [#146](https://github.com/Senth/minecraft-mod-manager/issues/146)
+- Crash when loading forge mods if they contained inline comments [#146](https://github.com/Senth/minecraft-mod-manager/issues/146)
+- Crash if a mod from Modrith was missing file links [#145](https://github.com/Senth/minecraft-mod-manager/issues/145)
 
 ## [1.2.7] - 2022-03-06
 
diff --git a/minecraft_mod_manager/gateways/api/modrinth_api.py b/minecraft_mod_manager/gateways/api/modrinth_api.py
index e7aaf56..bb2c481 100644
--- a/minecraft_mod_manager/gateways/api/modrinth_api.py
+++ b/minecraft_mod_manager/gateways/api/modrinth_api.py
@@ -19,9 +19,13 @@ class ModrinthApi(Api):
         versions: List[VersionInfo] = []
         json = self.downloader.get(ModrinthApi._make_versions_url(mod))
         for json_version in json:
-            version = ModrinthApi._json_to_version_info(json_version)
-            version.name = mod.name
-            versions.append(version)
+            try:
+                version = ModrinthApi._json_to_version_info(json_version)
+                version.name = mod.name
+                versions.append(version)
+            except IndexError:
+                # Skip this version
+                pass
 
         return versions
 
@@ -56,6 +60,7 @@ class ModrinthApi(Api):
 
     @staticmethod
     def _json_to_version_info(data: Any) -> VersionInfo:
+
         return VersionInfo(
             stability=Stabilities.from_name(data["version_type"]),
             mod_loaders=Api._to_mod_loaders(data["loaders"]),


Test patch:
diff --git a/minecraft_mod_manager/gateways/api/modrinth_api_test.py b/minecraft_mod_manager/gateways/api/modrinth_api_test.py
index 42914ef..4e7de70 100644
--- a/minecraft_mod_manager/gateways/api/modrinth_api_test.py
+++ b/minecraft_mod_manager/gateways/api/modrinth_api_test.py
@@ -15,6 +15,7 @@ from .modrinth_api import ModrinthApi
 testdata_dir = Path(__file__).parent.joinpath("testdata").joinpath("modrinth_api")
 search_result_file = testdata_dir.joinpath("search_fabric-api.json")
 versions_result_file = testdata_dir.joinpath("versions_fabric-api.json")
+versions_without_files_file = testdata_dir.joinpath("versions-without-files.json")
 
 
 @pytest.fixture
@@ -29,6 +30,12 @@ def versions_result():
         return json.load(file)
 
 
+@pytest.fixture
+def versions_without_files():
+    with open(versions_without_files_file) as file:
+        return json.load(file)
+
+
 @pytest.fixture
 def downloader():
     mocked = mock(Downloader)
@@ -58,17 +65,17 @@ def mod(id="fabric-api", name="Fabric API", site_slug="fabric-api", site_id=site
         ),
         (
             "Find site id by id",
-            mod(site_id=None),
+            mod(site_id=""),
             (site_id, "fabric-api"),
         ),
         (
             "Find site id from filename",
-            mod(id="invalid", site_slug=None, file="fabric-api-1.14.4-1.2.0+v191024.jar"),
+            mod(id="invalid", site_slug="", file="fabric-api-1.14.4-1.2.0+v191024.jar"),
             (site_id, "fabric-api"),
         ),
         (
             "Site id not found",
-            mod(id="invalid", site_slug=None),
+            mod(id="invalid", site_slug=""),
             None,
         ),
     ],
@@ -136,3 +143,36 @@ def test_get_all_versions_directly_when_we_have_mod_id(api: ModrinthApi, version
     unstub()
 
     assert expected == versions
+
+
+def test_get_versions_without_files(api: ModrinthApi, versions_without_files):
+    when(api.downloader).get(...).thenReturn(versions_without_files)
+    expected = [
+        VersionInfo(
+            stability=Stabilities.release,
+            mod_loaders=set([ModLoaders.fabric]),
+            site=Sites.modrinth,
+            name="Fabric API",
+            upload_time=1638379386,
+            minecraft_versions=["1.18"],
+            download_url="https://cdn.modrinth.com/data/Nz0RSWrF/versions/0.2.5/lazy-language-loader-0.2.5.jar",
+            filename="lazy-language-loader-0.2.5.jar",
+        ),
+        VersionInfo(
+            stability=Stabilities.release,
+            mod_loaders=set([ModLoaders.fabric]),
+            site=Sites.modrinth,
+            name="Fabric API",
+            upload_time=1638297554,
+            minecraft_versions=["1.18"],
+            download_url="https://cdn.modrinth.com/data/Nz0RSWrF/versions/0.2.3/lazy-language-loader-0.2.3.jar",
+            filename="lazy-language-loader-0.2.3.jar",
+        ),
+    ]
+
+    versions = api.get_all_versions(mod())
+
+    verifyStubbedInvocationsAreUsed()
+    unstub()
+
+    assert expected == versions
diff --git a/minecraft_mod_manager/gateways/api/testdata/modrinth_api/versions-without-files.json b/minecraft_mod_manager/gateways/api/testdata/modrinth_api/versions-without-files.json
new file mode 100644
index 0000000..4a9f4f2
--- /dev/null
+++ b/minecraft_mod_manager/gateways/api/testdata/modrinth_api/versions-without-files.json
@@ -0,0 +1,75 @@
+[
+  {
+    "id": "cbpDCPIJ",
+    "mod_id": "Nz0RSWrF",
+    "author_id": "Nrex64Q7",
+    "featured": false,
+    "name": "0.2.5 - Major fix!!",
+    "version_number": "0.2.5",
+    "changelog": "# 0.2.5\n### **NOTE: DO NOT DOWNLOAD THE DEV, SOURCES, OR SOURCES-DEV UNLESS YOU ARE A DEVELOPER!**\n## Additions\n```diff\n+ Fix loading on 1.18.x due to incorrectly specified minimum Minecraft version\n```\n## Links\n[Modrinth](https://modrinth.com/mod/lazy-language-loader)\n[CurseForge](https://www.curseforge.com/minecraft/mc-mods/lazy-language-loader)\n[Github](https://github.com/ChachyDev/lazy-language-loader)",
+    "changelog_url": null,
+    "date_published": "2021-12-01T17:23:06.412792Z",
+    "downloads": 25,
+    "version_type": "release",
+    "files": [
+      {
+        "hashes": {
+          "sha1": "feb136c022099b73a7f28adc996ac83add7929e7",
+          "sha512": "7b2ea0b7865fcd05168195ce22a207353ae4db11376a63e20038130196789cd54958d863e4ee3065f0164ffac6e4878f3bd0f2b079719db8ba9cf5cda3682c85"
+        },
+        "url": "https://cdn.modrinth.com/data/Nz0RSWrF/versions/0.2.5/lazy-language-loader-0.2.5.jar",
+        "filename": "lazy-language-loader-0.2.5.jar",
+        "primary": false
+      }
+    ],
+    "dependencies": [],
+    "game_versions": [
+      "1.18"
+    ],
+    "loaders": ["fabric"]
+  },
+  {
+    "id": "gbbefmHf",
+    "mod_id": "Nz0RSWrF",
+    "author_id": "Nrex64Q7",
+    "featured": false,
+    "name": "0.2.4 - Bug fixes",
+    "version_number": "0.2.4",
+    "changelog": "# 0.2.4\n### **NOTE: DO NOT DOWNLOAD THE DEV, SOURCES, OR SOURCES-DEV UNLESS YOU ARE A DEVELOPER!**\n## Additions\n```diff\n+ Pull in patches from 0.2.2 (Accidentally removed)\n```\n## Links\n[Modrinth](https://modrinth.com/mod/lazy-language-loader)\n[CurseForge](https://www.curseforge.com/minecraft/mc-mods/lazy-language-loader)\n[Github](https://github.com/ChachyDev/lazy-language-loader)\n\n**DOWNLOAD REMOVED AS MOD LOADING IS BROKEN**",
+    "changelog_url": null,
+    "date_published": "2021-12-01T07:44:16.974297Z",
+    "downloads": 17,
+    "version_type": "release",
+    "files": [],
+    "dependencies": [],
+    "game_versions": ["1.18"],
+    "loaders": ["fabric"]
+  },
+  {
+    "id": "m8ve59qv",
+    "mod_id": "Nz0RSWrF",
+    "author_id": "Nrex64Q7",
+    "featured": false,
+    "name": "1.18 support!",
+    "version_number": "0.2.3",
+    "changelog": "# 0.2.3\n### **NOTE: DO NOT DOWNLOAD THE DEV, SOURCES, OR SOURCES-DEV UNLESS YOU ARE A DEVELOPER!**\n## Additions\n```diff\n+ Add 1.18 support\n```\n## Links\n[Modrinth](https://modrinth.com/mod/lazy-language-loader)\n[CurseForge](https://www.curseforge.com/minecraft/mc-mods/lazy-language-loader)\n[Github](https://github.com/ChachyDev/lazy-language-loader)",
+    "changelog_url": null,
+    "date_published": "2021-11-30T18:39:14.403963Z",
+    "downloads": 17,
+    "version_type": "release",
+    "files": [
+      {
+        "hashes": {
+          "sha1": "4b903d6004a2b54a83df23529843fb378d603f23",
+          "sha512": "c0a698232c552e479e8640a41b1d0c464c3e3420be53f146c0723cfcb1e1e56c0c5efd2673008844702a715ee9618b85264b294cdee72c6daa2086bb69e469af"
+        },
+        "url": "https://cdn.modrinth.com/data/Nz0RSWrF/versions/0.2.3/lazy-language-loader-0.2.3.jar",
+        "filename": "lazy-language-loader-0.2.3.jar",
+        "primary": false
+      }
+    ],
+    "dependencies": [],
+    "game_versions": ["1.18"],
+    "loaders": ["fabric"]
+  }
+]