aboutsummaryrefslogtreecommitdiffstats
path: root/tests/mason-core
diff options
context:
space:
mode:
Diffstat (limited to 'tests/mason-core')
-rw-r--r--tests/mason-core/installer/installer_spec.lua4
-rw-r--r--tests/mason-core/installer/managers/cargo_spec.lua112
-rw-r--r--tests/mason-core/installer/managers/composer_spec.lua22
-rw-r--r--tests/mason-core/installer/managers/gem_spec.lua50
-rw-r--r--tests/mason-core/installer/managers/golang_spec.lua56
-rw-r--r--tests/mason-core/installer/managers/luarocks_spec.lua63
-rw-r--r--tests/mason-core/installer/managers/npm_spec.lua53
-rw-r--r--tests/mason-core/installer/managers/nuget_spec.lua21
-rw-r--r--tests/mason-core/installer/managers/opam_spec.lua20
-rw-r--r--tests/mason-core/installer/managers/pypi_spec.lua126
-rw-r--r--tests/mason-core/installer/managers/std_spec.lua150
-rw-r--r--tests/mason-core/installer/registry/installer_spec.lua203
-rw-r--r--tests/mason-core/installer/registry/link_spec.lua231
-rw-r--r--tests/mason-core/installer/registry/providers/cargo_spec.lua143
-rw-r--r--tests/mason-core/installer/registry/providers/composer_spec.lua66
-rw-r--r--tests/mason-core/installer/registry/providers/gem_spec.lua72
-rw-r--r--tests/mason-core/installer/registry/providers/generic_spec.lua100
-rw-r--r--tests/mason-core/installer/registry/providers/github_spec.lua355
-rw-r--r--tests/mason-core/installer/registry/providers/golang_spec.lua68
-rw-r--r--tests/mason-core/installer/registry/providers/luarocks_spec.lua78
-rw-r--r--tests/mason-core/installer/registry/providers/npm_spec.lua72
-rw-r--r--tests/mason-core/installer/registry/providers/nuget_spec.lua45
-rw-r--r--tests/mason-core/installer/registry/providers/opam_spec.lua45
-rw-r--r--tests/mason-core/installer/registry/providers/pypi_spec.lua110
-rw-r--r--tests/mason-core/installer/registry/util_spec.lua81
-rw-r--r--tests/mason-core/managers/powershell_spec.lua4
-rw-r--r--tests/mason-core/package/package_spec.lua3
27 files changed, 2349 insertions, 4 deletions
diff --git a/tests/mason-core/installer/installer_spec.lua b/tests/mason-core/installer/installer_spec.lua
index 66cdb89b..aa459cce 100644
--- a/tests/mason-core/installer/installer_spec.lua
+++ b/tests/mason-core/installer/installer_spec.lua
@@ -63,7 +63,7 @@ describe("installer", function()
local handler = InstallHandleGenerator "dummy"
---@param ctx InstallContext
handler.package.spec.install = function(ctx)
- ctx.receipt:with_primary_source { type = "source", metadata = {} }
+ ctx.receipt:with_primary_source { type = "source", source = {} }
ctx.fs:write_file("target", "")
ctx.fs:write_file("file.jar", "")
@@ -86,7 +86,7 @@ describe("installer", function()
---@type InstallReceipt
local receipt = vim.json.decode(arg)
assert.equals("dummy", receipt.name)
- assert.same({ type = "source", metadata = {} }, receipt.primary_source)
+ assert.same({ type = "source", source = {} }, receipt.primary_source)
assert.same({}, receipt.secondary_sources)
assert.same("1.1", receipt.schema_version)
assert.same({
diff --git a/tests/mason-core/installer/managers/cargo_spec.lua b/tests/mason-core/installer/managers/cargo_spec.lua
new file mode 100644
index 00000000..63768f4d
--- /dev/null
+++ b/tests/mason-core/installer/managers/cargo_spec.lua
@@ -0,0 +1,112 @@
+local installer = require "mason-core.installer"
+local cargo = require "mason-core.installer.managers.cargo"
+
+describe("cargo manager", function()
+ it("should install", function()
+ local handle = InstallHandleGenerator "dummy"
+ local ctx = InstallContextGenerator(handle)
+ installer.exec_in_context(ctx, function()
+ cargo.install("my-crate", "1.0.0")
+ end)
+
+ assert.spy(ctx.spawn.cargo).was_called(1)
+ assert.spy(ctx.spawn.cargo).was_called_with {
+ "install",
+ "--root",
+ ".",
+ { "--version", "1.0.0" },
+ vim.NIL, -- features
+ vim.NIL, -- locked
+ "my-crate",
+ }
+ end)
+
+ it("should install locked", function()
+ local handle = InstallHandleGenerator "dummy"
+ local ctx = InstallContextGenerator(handle)
+ installer.exec_in_context(ctx, function()
+ cargo.install("my-crate", "1.0.0", {
+ locked = true,
+ })
+ end)
+
+ assert.spy(ctx.spawn.cargo).was_called(1)
+ assert.spy(ctx.spawn.cargo).was_called_with {
+ "install",
+ "--root",
+ ".",
+ { "--version", "1.0.0" },
+ vim.NIL, -- features
+ "--locked", -- locked
+ "my-crate",
+ }
+ end)
+
+ it("should install provided features", function()
+ local handle = InstallHandleGenerator "dummy"
+ local ctx = InstallContextGenerator(handle)
+ installer.exec_in_context(ctx, function()
+ cargo.install("my-crate", "1.0.0", {
+ features = "lsp,cli",
+ })
+ end)
+
+ assert.spy(ctx.spawn.cargo).was_called(1)
+ assert.spy(ctx.spawn.cargo).was_called_with {
+ "install",
+ "--root",
+ ".",
+ { "--version", "1.0.0" },
+ { "--features", "lsp,cli" }, -- features
+ vim.NIL, -- locked
+ "my-crate",
+ }
+ end)
+
+ it("should install git tag source", function()
+ local handle = InstallHandleGenerator "dummy"
+ local ctx = InstallContextGenerator(handle)
+ installer.exec_in_context(ctx, function()
+ cargo.install("my-crate", "1.0.0", {
+ git = {
+ url = "https://github.com/neovim/neovim",
+ },
+ })
+ end)
+
+ assert.spy(ctx.spawn.cargo).was_called(1)
+ assert.spy(ctx.spawn.cargo).was_called_with {
+ "install",
+ "--root",
+ ".",
+ { "--git", "https://github.com/neovim/neovim", "--tag", "1.0.0" },
+ vim.NIL, -- features
+ vim.NIL, -- locked
+ "my-crate",
+ }
+ end)
+
+ it("should install git rev source", function()
+ local handle = InstallHandleGenerator "dummy"
+ local ctx = InstallContextGenerator(handle)
+ installer.exec_in_context(ctx, function()
+ cargo.install("my-crate", "16dfc89abd413c391e5b63ae5d132c22843ce9a7", {
+ git = {
+ url = "https://github.com/neovim/neovim",
+ rev = true,
+ },
+ })
+ end)
+
+ assert.spy(ctx.spawn.cargo).was_called(1)
+ assert.spy(ctx.spawn.cargo).was_called_with {
+ "install",
+ "--root",
+ ".",
+ { "--git", "https://github.com/neovim/neovim", "--rev", "16dfc89abd413c391e5b63ae5d132c22843ce9a7" },
+ vim.NIL, -- features
+ vim.NIL, -- locked
+ "my-crate",
+ }
+ end)
+end)
diff --git a/tests/mason-core/installer/managers/composer_spec.lua b/tests/mason-core/installer/managers/composer_spec.lua
new file mode 100644
index 00000000..a4e1f82f
--- /dev/null
+++ b/tests/mason-core/installer/managers/composer_spec.lua
@@ -0,0 +1,22 @@
+local installer = require "mason-core.installer"
+local composer = require "mason-core.installer.managers.composer"
+
+describe("composer manager", function()
+ it("should install", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ composer.install("my-package", "1.0.0")
+ end)
+
+ assert.spy(ctx.spawn.composer).was_called(2)
+ assert.spy(ctx.spawn.composer).was_called_with {
+ "init",
+ "--no-interaction",
+ "--stability=stable",
+ }
+ assert.spy(ctx.spawn.composer).was_called_with {
+ "require",
+ "my-package:1.0.0",
+ }
+ end)
+end)
diff --git a/tests/mason-core/installer/managers/gem_spec.lua b/tests/mason-core/installer/managers/gem_spec.lua
new file mode 100644
index 00000000..580c6432
--- /dev/null
+++ b/tests/mason-core/installer/managers/gem_spec.lua
@@ -0,0 +1,50 @@
+local installer = require "mason-core.installer"
+local gem = require "mason-core.installer.managers.gem"
+
+describe("gem manager", function()
+ it("should install", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ gem.install("my-gem", "1.0.0")
+ end)
+
+ assert.spy(ctx.spawn.gem).was_called(1)
+ assert.spy(ctx.spawn.gem).was_called_with {
+ "install",
+ "--no-user-install",
+ "--no-format-executable",
+ "--install-dir=.",
+ "--bindir=bin",
+ "--no-document",
+ "my-gem:1.0.0",
+ vim.NIL, -- extra_packages
+ env = {
+ GEM_HOME = ctx.cwd:get(),
+ },
+ }
+ end)
+
+ it("should install extra packages", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ gem.install("my-gem", "1.0.0", {
+ extra_packages = { "extra-gem" },
+ })
+ end)
+
+ assert.spy(ctx.spawn.gem).was_called(1)
+ assert.spy(ctx.spawn.gem).was_called_with {
+ "install",
+ "--no-user-install",
+ "--no-format-executable",
+ "--install-dir=.",
+ "--bindir=bin",
+ "--no-document",
+ "my-gem:1.0.0",
+ { "extra-gem" },
+ env = {
+ GEM_HOME = ctx.cwd:get(),
+ },
+ }
+ end)
+end)
diff --git a/tests/mason-core/installer/managers/golang_spec.lua b/tests/mason-core/installer/managers/golang_spec.lua
new file mode 100644
index 00000000..cdad6e25
--- /dev/null
+++ b/tests/mason-core/installer/managers/golang_spec.lua
@@ -0,0 +1,56 @@
+local installer = require "mason-core.installer"
+local golang = require "mason-core.installer.managers.golang"
+
+describe("golang manager", function()
+ it("should install", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ golang.install("my-golang", "1.0.0")
+ end)
+
+ assert.spy(ctx.spawn.go).was_called(1)
+ assert.spy(ctx.spawn.go).was_called_with {
+ "install",
+ "-v",
+ "my-golang@1.0.0",
+ env = {
+ GOBIN = ctx.cwd:get(),
+ },
+ }
+ end)
+
+ it("should install extra packages", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ golang.install("my-golang", "1.0.0", {
+ extra_packages = { "extra", "package" },
+ })
+ end)
+
+ assert.spy(ctx.spawn.go).was_called(3)
+ assert.spy(ctx.spawn.go).was_called_with {
+ "install",
+ "-v",
+ "my-golang@1.0.0",
+ env = {
+ GOBIN = ctx.cwd:get(),
+ },
+ }
+ assert.spy(ctx.spawn.go).was_called_with {
+ "install",
+ "-v",
+ "extra@latest",
+ env = {
+ GOBIN = ctx.cwd:get(),
+ },
+ }
+ assert.spy(ctx.spawn.go).was_called_with {
+ "install",
+ "-v",
+ "package@latest",
+ env = {
+ GOBIN = ctx.cwd:get(),
+ },
+ }
+ end)
+end)
diff --git a/tests/mason-core/installer/managers/luarocks_spec.lua b/tests/mason-core/installer/managers/luarocks_spec.lua
new file mode 100644
index 00000000..69ac3946
--- /dev/null
+++ b/tests/mason-core/installer/managers/luarocks_spec.lua
@@ -0,0 +1,63 @@
+local installer = require "mason-core.installer"
+local stub = require "luassert.stub"
+local luarocks = require "mason-core.installer.managers.luarocks"
+
+describe("luarocks manager", function()
+ it("should install", function()
+ local ctx = create_dummy_context()
+ stub(ctx, "promote_cwd")
+ installer.exec_in_context(ctx, function()
+ luarocks.install("my-rock", "1.0.0")
+ end)
+
+ assert.spy(ctx.promote_cwd).was_called(1)
+ assert.spy(ctx.spawn.luarocks).was_called(1)
+ assert.spy(ctx.spawn.luarocks).was_called_with {
+ "install",
+ { "--tree", ctx.cwd:get() },
+ vim.NIL, -- dev
+ vim.NIL, -- server
+ { "my-rock", "1.0.0" },
+ }
+ end)
+
+ it("should install dev mode", function()
+ local ctx = create_dummy_context()
+ stub(ctx, "promote_cwd")
+ installer.exec_in_context(ctx, function()
+ luarocks.install("my-rock", "1.0.0", {
+ dev = true,
+ })
+ end)
+
+ assert.spy(ctx.promote_cwd).was_called(1)
+ assert.spy(ctx.spawn.luarocks).was_called(1)
+ assert.spy(ctx.spawn.luarocks).was_called_with {
+ "install",
+ { "--tree", ctx.cwd:get() },
+ "--dev",
+ vim.NIL, -- server
+ { "my-rock", "1.0.0" },
+ }
+ end)
+
+ it("should install using provided server", function()
+ local ctx = create_dummy_context()
+ stub(ctx, "promote_cwd")
+ installer.exec_in_context(ctx, function()
+ luarocks.install("my-rock", "1.0.0", {
+ server = "https://luarocks.org/dev",
+ })
+ end)
+
+ assert.spy(ctx.promote_cwd).was_called(1)
+ assert.spy(ctx.spawn.luarocks).was_called(1)
+ assert.spy(ctx.spawn.luarocks).was_called_with {
+ "install",
+ { "--tree", ctx.cwd:get() },
+ vim.NIL, -- dev
+ "--server=https://luarocks.org/dev",
+ { "my-rock", "1.0.0" },
+ }
+ end)
+end)
diff --git a/tests/mason-core/installer/managers/npm_spec.lua b/tests/mason-core/installer/managers/npm_spec.lua
new file mode 100644
index 00000000..655acb64
--- /dev/null
+++ b/tests/mason-core/installer/managers/npm_spec.lua
@@ -0,0 +1,53 @@
+local installer = require "mason-core.installer"
+local stub = require "luassert.stub"
+local match = require "luassert.match"
+local npm = require "mason-core.installer.managers.npm"
+
+describe("npm manager", function()
+ it("should init package.json", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "append_file")
+ installer.exec_in_context(ctx, function()
+ npm.init()
+ end)
+
+ assert.spy(ctx.spawn.npm).was_called(1)
+ assert.spy(ctx.spawn.npm).was_called_with {
+ "init",
+ "--yes",
+ "--scope=mason",
+ }
+ assert.spy(ctx.fs.append_file).was_called(1)
+ assert.spy(ctx.fs.append_file).was_called_with(match.is_ref(ctx.fs), ".npmrc", "global-style=true")
+ end)
+
+ it("should install", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ npm.install("my-package", "1.0.0")
+ end)
+
+ assert.spy(ctx.spawn.npm).was_called(1)
+ assert.spy(ctx.spawn.npm).was_called_with {
+ "install",
+ "my-package@1.0.0",
+ vim.NIL, -- extra_packages
+ }
+ end)
+
+ it("should install extra packages", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ npm.install("my-package", "1.0.0", {
+ extra_packages = { "extra-package" },
+ })
+ end)
+
+ assert.spy(ctx.spawn.npm).was_called(1)
+ assert.spy(ctx.spawn.npm).was_called_with {
+ "install",
+ "my-package@1.0.0",
+ { "extra-package" },
+ }
+ end)
+end)
diff --git a/tests/mason-core/installer/managers/nuget_spec.lua b/tests/mason-core/installer/managers/nuget_spec.lua
new file mode 100644
index 00000000..1bdecf37
--- /dev/null
+++ b/tests/mason-core/installer/managers/nuget_spec.lua
@@ -0,0 +1,21 @@
+local installer = require "mason-core.installer"
+local nuget = require "mason-core.installer.managers.nuget"
+
+describe("nuget manager", function()
+ it("should install", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ nuget.install("nuget-package", "1.0.0")
+ end)
+
+ assert.spy(ctx.spawn.dotnet).was_called(1)
+ assert.spy(ctx.spawn.dotnet).was_called_with {
+ "tool",
+ "update",
+ "--tool-path",
+ ".",
+ { "--version", "1.0.0" },
+ "nuget-package",
+ }
+ end)
+end)
diff --git a/tests/mason-core/installer/managers/opam_spec.lua b/tests/mason-core/installer/managers/opam_spec.lua
new file mode 100644
index 00000000..c1fe59f6
--- /dev/null
+++ b/tests/mason-core/installer/managers/opam_spec.lua
@@ -0,0 +1,20 @@
+local installer = require "mason-core.installer"
+local opam = require "mason-core.installer.managers.opam"
+
+describe("opam manager", function()
+ it("should install", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ opam.install("opam-package", "1.0.0")
+ end)
+
+ assert.spy(ctx.spawn.opam).was_called(1)
+ assert.spy(ctx.spawn.opam).was_called_with {
+ "install",
+ "--destdir=.",
+ "--yes",
+ "--verbose",
+ "opam-package.1.0.0",
+ }
+ end)
+end)
diff --git a/tests/mason-core/installer/managers/pypi_spec.lua b/tests/mason-core/installer/managers/pypi_spec.lua
new file mode 100644
index 00000000..f0a6cdc6
--- /dev/null
+++ b/tests/mason-core/installer/managers/pypi_spec.lua
@@ -0,0 +1,126 @@
+local installer = require "mason-core.installer"
+local stub = require "luassert.stub"
+local path = require "mason-core.path"
+local pypi = require "mason-core.installer.managers.pypi"
+
+---@param ctx InstallContext
+local function venv_py(ctx)
+ return path.concat {
+ ctx.cwd:get(),
+ "venv",
+ "bin",
+ "python",
+ }
+end
+
+describe("pypi manager", function()
+ it("should init venv without upgrading pip", function()
+ local ctx = create_dummy_context()
+ stub(ctx, "promote_cwd")
+ installer.exec_in_context(ctx, function()
+ pypi.init { upgrade_pip = false }
+ end)
+
+ assert.spy(ctx.promote_cwd).was_called(1)
+ assert.spy(ctx.spawn.python3).was_called(1)
+ assert.spy(ctx.spawn.python3).was_called_with {
+ "-m",
+ "venv",
+ "venv",
+ }
+ end)
+
+ it("should init venv and upgrade pip", function()
+ local ctx = create_dummy_context()
+ stub(ctx, "promote_cwd")
+ installer.exec_in_context(ctx, function()
+ pypi.init { upgrade_pip = true, install_extra_args = { "--proxy", "http://localhost" } }
+ end)
+
+ assert.spy(ctx.promote_cwd).was_called(1)
+ assert.spy(ctx.spawn.python3).was_called(1)
+ assert.spy(ctx.spawn.python3).was_called_with {
+ "-m",
+ "venv",
+ "venv",
+ }
+ assert.spy(ctx.spawn[venv_py(ctx)]).was_called(1)
+ assert.spy(ctx.spawn[venv_py(ctx)]).was_called_with {
+ "-m",
+ "pip",
+ "--disable-pip-version-check",
+ "install",
+ "-U",
+ { "--proxy", "http://localhost" },
+ { "pip" },
+ }
+ end)
+
+ it("should install", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ pypi.install("pypi-package", "1.0.0")
+ end)
+
+ assert.spy(ctx.spawn[venv_py(ctx)]).was_called(1)
+ assert.spy(ctx.spawn[venv_py(ctx)]).was_called_with {
+ "-m",
+ "pip",
+ "--disable-pip-version-check",
+ "install",
+ "-U",
+ vim.NIL, -- install_extra_args
+ {
+ "pypi-package==1.0.0",
+ vim.NIL, -- extra_packages
+ },
+ }
+ end)
+
+ it("should install extra specifier", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ pypi.install("pypi-package", "1.0.0", {
+ extra = "lsp",
+ })
+ end)
+
+ assert.spy(ctx.spawn[venv_py(ctx)]).was_called(1)
+ assert.spy(ctx.spawn[venv_py(ctx)]).was_called_with {
+ "-m",
+ "pip",
+ "--disable-pip-version-check",
+ "install",
+ "-U",
+ vim.NIL, -- install_extra_args
+ {
+ "pypi-package[lsp]==1.0.0",
+ vim.NIL, -- extra_packages
+ },
+ }
+ end)
+
+ it("should install extra packages", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ pypi.install("pypi-package", "1.0.0", {
+ extra_packages = { "extra-package" },
+ install_extra_args = { "--proxy", "http://localhost:9000" },
+ })
+ end)
+
+ assert.spy(ctx.spawn[venv_py(ctx)]).was_called(1)
+ assert.spy(ctx.spawn[venv_py(ctx)]).was_called_with {
+ "-m",
+ "pip",
+ "--disable-pip-version-check",
+ "install",
+ "-U",
+ { "--proxy", "http://localhost:9000" },
+ {
+ "pypi-package==1.0.0",
+ { "extra-package" },
+ },
+ }
+ end)
+end)
diff --git a/tests/mason-core/installer/managers/std_spec.lua b/tests/mason-core/installer/managers/std_spec.lua
new file mode 100644
index 00000000..feff9abe
--- /dev/null
+++ b/tests/mason-core/installer/managers/std_spec.lua
@@ -0,0 +1,150 @@
+local installer = require "mason-core.installer"
+local stub = require "luassert.stub"
+local match = require "luassert.match"
+local std = require "mason-core.installer.managers.std"
+
+describe("std unpack [Unix]", function()
+ it("should unpack .gz", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ std.unpack "file.gz"
+ end)
+
+ assert.spy(ctx.spawn.gzip).was_called(1)
+ assert.spy(ctx.spawn.gzip).was_called_with { "-d", "file.gz" }
+ end)
+
+ it("should unpack .tar", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "unlink")
+ installer.exec_in_context(ctx, function()
+ std.unpack "file.tar"
+ end)
+
+ assert.spy(ctx.spawn.tar).was_called(1)
+ assert.spy(ctx.spawn.tar).was_called_with { "--no-same-owner", "-xvf", "file.tar" }
+ assert.spy(ctx.fs.unlink).was_called(1)
+ assert.spy(ctx.fs.unlink).was_called_with(match.is_ref(ctx.fs), "file.tar")
+ end)
+
+ it("should unpack .tar.bz2", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "unlink")
+ installer.exec_in_context(ctx, function()
+ std.unpack "file.tar.bz2"
+ end)
+
+ assert.spy(ctx.spawn.tar).was_called(1)
+ assert.spy(ctx.spawn.tar).was_called_with { "--no-same-owner", "-xvf", "file.tar.bz2" }
+ assert.spy(ctx.fs.unlink).was_called(1)
+ assert.spy(ctx.fs.unlink).was_called_with(match.is_ref(ctx.fs), "file.tar.bz2")
+ end)
+
+ it("should unpack .tar.gz", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "unlink")
+ installer.exec_in_context(ctx, function()
+ std.unpack "file.tar.gz"
+ end)
+
+ assert.spy(ctx.spawn.tar).was_called(1)
+ assert.spy(ctx.spawn.tar).was_called_with { "--no-same-owner", "-xvf", "file.tar.gz" }
+ assert.spy(ctx.fs.unlink).was_called(1)
+ assert.spy(ctx.fs.unlink).was_called_with(match.is_ref(ctx.fs), "file.tar.gz")
+ end)
+
+ it("should unpack .tar.xz", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "unlink")
+ installer.exec_in_context(ctx, function()
+ std.unpack "file.tar.xz"
+ end)
+
+ assert.spy(ctx.spawn.tar).was_called(1)
+ assert.spy(ctx.spawn.tar).was_called_with { "--no-same-owner", "-xvf", "file.tar.xz" }
+ assert.spy(ctx.fs.unlink).was_called(1)
+ assert.spy(ctx.fs.unlink).was_called_with(match.is_ref(ctx.fs), "file.tar.xz")
+ end)
+
+ it("should unpack .tar.zst", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "unlink")
+ installer.exec_in_context(ctx, function()
+ std.unpack "file.tar.zst"
+ end)
+
+ assert.spy(ctx.spawn.tar).was_called(1)
+ assert.spy(ctx.spawn.tar).was_called_with { "--no-same-owner", "-xvf", "file.tar.zst" }
+ assert.spy(ctx.fs.unlink).was_called(1)
+ assert.spy(ctx.fs.unlink).was_called_with(match.is_ref(ctx.fs), "file.tar.zst")
+ end)
+
+ it("should unpack .vsix", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "unlink")
+ installer.exec_in_context(ctx, function()
+ std.unpack "file.vsix"
+ end)
+
+ assert.spy(ctx.spawn.unzip).was_called(1)
+ assert.spy(ctx.spawn.unzip).was_called_with { "-d", ".", "file.vsix" }
+ assert.spy(ctx.fs.unlink).was_called(1)
+ assert.spy(ctx.fs.unlink).was_called_with(match.is_ref(ctx.fs), "file.vsix")
+ end)
+
+ it("should unpack .zip", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "unlink")
+ installer.exec_in_context(ctx, function()
+ std.unpack "file.zip"
+ end)
+
+ assert.spy(ctx.spawn.unzip).was_called(1)
+ assert.spy(ctx.spawn.unzip).was_called_with { "-d", ".", "file.zip" }
+ assert.spy(ctx.fs.unlink).was_called(1)
+ assert.spy(ctx.fs.unlink).was_called_with(match.is_ref(ctx.fs), "file.zip")
+ end)
+end)
+
+describe("std clone", function()
+ it("should clone", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ std.clone "https://github.com/williamboman/mason.nvim"
+ end)
+
+ assert.spy(ctx.spawn.git).was_called(1)
+ assert.spy(ctx.spawn.git).was_called_with {
+ "clone",
+ "--depth",
+ "1",
+ vim.NIL, -- recursive
+ "https://github.com/williamboman/mason.nvim",
+ ".",
+ }
+ end)
+
+ it("should clone and checkout rev", function()
+ local ctx = create_dummy_context()
+ installer.exec_in_context(ctx, function()
+ std.clone("https://github.com/williamboman/mason.nvim", {
+ rev = "e1fd03b1856cb5ad8425f49e18353dc524b02f91",
+ recursive = true,
+ })
+ end)
+
+ assert.spy(ctx.spawn.git).was_called(3)
+ assert.spy(ctx.spawn.git).was_called_with {
+ "clone",
+ "--depth",
+ "1",
+ "--recursive",
+ "https://github.com/williamboman/mason.nvim",
+ ".",
+ }
+ assert
+ .spy(ctx.spawn.git)
+ .was_called_with { "fetch", "--depth", "1", "origin", "e1fd03b1856cb5ad8425f49e18353dc524b02f91" }
+ assert.spy(ctx.spawn.git).was_called_with { "checkout", "FETCH_HEAD" }
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/installer_spec.lua b/tests/mason-core/installer/registry/installer_spec.lua
new file mode 100644
index 00000000..e6ca6f91
--- /dev/null
+++ b/tests/mason-core/installer/registry/installer_spec.lua
@@ -0,0 +1,203 @@
+local match = require "luassert.match"
+local stub = require "luassert.stub"
+local Result = require "mason-core.result"
+local installer = require "mason-core.installer.registry"
+local util = require "mason-core.installer.registry.util"
+
+---@type InstallerProvider
+local dummy_provider = {
+ ---@param source RegistryPackageSource
+ ---@param purl Purl
+ ---@param opts PackageInstallOpts
+ parse = function(source, purl, opts)
+ return Result.try(function(try)
+ if source.supported_platforms then
+ try(util.ensure_valid_platform(source.supported_platforms))
+ end
+ return {
+ package = purl.name,
+ extra_info = source.extra_info,
+ should_fail = source.should_fail,
+ }
+ end)
+ end,
+ install = function(ctx, source)
+ if source.should_fail then
+ return Result.failure "This is a failure."
+ else
+ return Result.success()
+ end
+ end,
+}
+
+describe("registry installer :: parsing", function()
+ it("should parse valid package specs", function()
+ installer.register_provider("dummy", dummy_provider)
+
+ local result = installer.parse({
+ schema = "registry+v1",
+ source = {
+ id = "pkg:dummy/package-name@v1.2.3",
+ extra_info = "here",
+ },
+ }, {})
+ local parsed = result:get_or_nil()
+
+ assert.is_true(result:is_success())
+ assert.is_true(match.is_ref(dummy_provider)(parsed.provider))
+ assert.same({
+ name = "package-name",
+ scheme = "pkg",
+ type = "dummy",
+ version = "v1.2.3",
+ }, parsed.purl)
+ assert.same({
+ package = "package-name",
+ extra_info = "here",
+ }, parsed.source)
+ end)
+
+ it("should reject incompatible schema versions", function()
+ installer.register_provider("dummy", dummy_provider)
+
+ local result = installer.parse({
+ schema = "registry+v1337",
+ source = {
+ id = "pkg:dummy/package-name@v1.2.3",
+ },
+ }, {})
+ assert.same(
+ Result.failure [[Current version of mason.nvim is not capable of parsing package schema version "registry+v1337".]],
+ result
+ )
+ end)
+
+ it("should use requested version", function()
+ installer.register_provider("dummy", dummy_provider)
+
+ local result = installer.parse({
+ schema = "registry+v1",
+ source = {
+ id = "pkg:dummy/package-name@v1.2.3",
+ },
+ }, { version = "v2.0.0" })
+
+ assert.is_true(result:is_success())
+ local parsed = result:get_or_nil()
+
+ assert.same({
+ name = "package-name",
+ scheme = "pkg",
+ type = "dummy",
+ version = "v2.0.0",
+ }, parsed.purl)
+ end)
+
+ it("should handle PLATFORM_UNSUPPORTED", function()
+ installer.register_provider("dummy", dummy_provider)
+
+ local result = installer.compile({
+ schema = "registry+v1",
+ source = {
+ id = "pkg:dummy/package-name@v1.2.3",
+ supported_platforms = { "VIC64" },
+ },
+ }, { version = "v2.0.0" })
+
+ assert.same(Result.failure "The current platform is unsupported.", result)
+ end)
+
+ it("should error upon parsing failures", function()
+ installer.register_provider("dummy", dummy_provider)
+
+ local result = installer.compile({
+ schema = "registry+v1",
+ source = {
+ id = "pkg:dummy/package-name@v1.2.3",
+ supported_platforms = { "VIC64" },
+ },
+ }, { version = "v2.0.0" })
+
+ assert.same(Result.failure "The current platform is unsupported.", result)
+ end)
+end)
+
+describe("registry installer :: compiling", function()
+ it("should run compiled installer function successfully", function()
+ installer.register_provider("dummy", dummy_provider)
+
+ local result = installer.compile({
+ schema = "registry+v1",
+ source = {
+ id = "pkg:dummy/package-name@v1.2.3",
+ },
+ }, {})
+
+ assert.is_true(result:is_success())
+ local installer_fn = result:get_or_nil()
+
+ local ctx = create_dummy_context()
+ local installer_result = require("mason-core.installer").exec_in_context(ctx, installer_fn)
+ assert.same(Result.success(), installer_result)
+ end)
+
+ it("should raise errors upon installer failures", function()
+ installer.register_provider("dummy", dummy_provider)
+
+ local result = installer.compile({
+ schema = "registry+v1",
+ source = {
+ id = "pkg:dummy/package-name@v1.2.3",
+ should_fail = true,
+ },
+ }, {})
+
+ assert.is_true(result:is_success())
+ local installer_fn = result:get_or_nil()
+
+ local ctx = create_dummy_context()
+ local err = assert.has_error(function()
+ require("mason-core.installer").exec_in_context(ctx, installer_fn)
+ end)
+ assert.equals("This is a failure.", err)
+ end)
+
+ it("should register links", function()
+ installer.register_provider("dummy", dummy_provider)
+ local link = require "mason-core.installer.registry.link"
+ stub(link, "bin", mockx.returns(Result.success()))
+ stub(link, "share", mockx.returns(Result.success()))
+ stub(link, "opt", mockx.returns(Result.success()))
+
+ local spec = {
+ schema = "registry+v1",
+ source = {
+ id = "pkg:dummy/package-name@v1.2.3",
+ },
+ bin = { ["exec"] = "exec" },
+ opt = { ["opt/"] = "opt/" },
+ share = { ["share/"] = "share/" },
+ }
+
+ local result = installer.compile(spec, {})
+
+ assert.is_true(result:is_success())
+ local installer_fn = result:get_or_nil()
+
+ local ctx = create_dummy_context()
+ local installer_result = require("mason-core.installer").exec_in_context(ctx, installer_fn)
+ assert.is_true(installer_result:is_success())
+
+ for _, spy in ipairs { link.bin, link.share, link.opt } do
+ assert.spy(spy).was_called(1)
+ assert.spy(spy).was_called_with(match.is_ref(ctx), spec, {
+ scheme = "pkg",
+ type = "dummy",
+ name = "package-name",
+ version = "v1.2.3",
+ }, {
+ package = "package-name",
+ })
+ end
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/link_spec.lua b/tests/mason-core/installer/registry/link_spec.lua
new file mode 100644
index 00000000..eef66349
--- /dev/null
+++ b/tests/mason-core/installer/registry/link_spec.lua
@@ -0,0 +1,231 @@
+local stub = require "luassert.stub"
+local match = require "luassert.match"
+local Result = require "mason-core.result"
+local Purl = require "mason-core.purl"
+local link = require "mason-core.installer.registry.link"
+local fs = require "mason-core.fs"
+local path = require "mason-core.path"
+
+describe("registry linker", function()
+ it("should expand bin table", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "file_exists")
+ stub(ctx.fs, "chmod")
+ stub(ctx.fs, "fstat")
+
+ ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), "exec.sh").returns(true)
+ ctx.fs.fstat.on_call_with(match.is_ref(ctx.fs), "exec.sh").returns {
+ mode = 493, -- 0755
+ }
+
+ local result = link.bin(
+ ctx,
+ {
+ bin = {
+ ["exec"] = "exec.sh",
+ },
+ },
+ Purl.parse("pkg:dummy/package@v1.0.0"):get_or_throw(),
+ {
+ metadata = "value",
+ }
+ )
+
+ assert.same(
+ Result.success {
+ ["exec"] = "exec.sh",
+ },
+ result
+ )
+ assert.same({
+ ["exec"] = "exec.sh",
+ }, ctx.links.bin)
+
+ assert.spy(ctx.fs.chmod).was_not_called()
+ end)
+
+ it("should chmod executable if necessary", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "file_exists")
+ stub(ctx.fs, "chmod")
+ stub(ctx.fs, "fstat")
+
+ ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), "exec.sh").returns(true)
+ ctx.fs.fstat.on_call_with(match.is_ref(ctx.fs), "exec.sh").returns {
+ mode = 420, -- 0644
+ }
+
+ local result = link.bin(
+ ctx,
+ {
+ bin = {
+ ["exec"] = "exec.sh",
+ },
+ },
+ Purl.parse("pkg:dummy/package@v1.0.0"):get_or_throw(),
+ {
+ metadata = "value",
+ }
+ )
+
+ assert.is_true(result:is_success())
+ assert.spy(ctx.fs.chmod).was_called(1)
+ assert.spy(ctx.fs.chmod).was_called_with(match.is_ref(ctx.fs), "exec.sh", 493)
+ end)
+
+ it("should interpolate bin table", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "file_exists")
+ stub(ctx.fs, "chmod")
+ stub(ctx.fs, "fstat")
+
+ ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), "v1.0.0-exec.sh").returns(true)
+ ctx.fs.fstat.on_call_with(match.is_ref(ctx.fs), "v1.0.0-exec.sh").returns {
+ mode = 493, -- 0755
+ }
+
+ local result = link.bin(
+ ctx,
+ {
+ bin = {
+ ["exec"] = "{{version}}-{{source.script}}",
+ },
+ },
+ Purl.parse("pkg:dummy/package@v1.0.0"):get_or_throw(),
+ {
+ script = "exec.sh",
+ }
+ )
+
+ assert.same(
+ Result.success {
+ ["exec"] = "v1.0.0-exec.sh",
+ },
+ result
+ )
+ end)
+
+ it("should delegate bin paths", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "file_exists")
+ stub(ctx.fs, "chmod")
+ stub(ctx.fs, "fstat")
+
+ local matrix = {
+ ["cargo:executable"] = "bin/executable",
+ ["composer:executable"] = "vendor/bin/executable",
+ ["golang:executable"] = "executable",
+ ["luarocks:executable"] = "bin/executable",
+ ["npm:executable"] = "node_modules/.bin/executable",
+ ["nuget:executable"] = "executable",
+ ["opam:executable"] = "bin/executable",
+ ["pypi:executable"] = "venv/bin/executable",
+ }
+
+ for bin, path in pairs(matrix) do
+ ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), path).returns(true)
+ ctx.fs.fstat.on_call_with(match.is_ref(ctx.fs), path).returns {
+ mode = 493, -- 0755
+ }
+
+ local result = link.bin(ctx, {
+ bin = {
+ ["executable"] = bin,
+ },
+ }, Purl.parse("pkg:dummy/package@v1.0.0"):get_or_throw(), {})
+
+ assert.same(
+ Result.success {
+ ["executable"] = path,
+ },
+ result
+ )
+ end
+ end)
+
+ it("should register share links", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "file_exists")
+ stub(fs.sync, "file_exists")
+ stub(vim.fn, "glob")
+
+ vim.fn.glob.on_call_with(path.concat { ctx.cwd:get(), "v1.0.0/dir/" } .. "**/*", false, true).returns {
+ path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file1" },
+ path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file2" },
+ path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file3" },
+ }
+ fs.sync.file_exists.on_call_with(path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file1" }).returns(true)
+ fs.sync.file_exists.on_call_with(path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file2" }).returns(true)
+ fs.sync.file_exists.on_call_with(path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file3" }).returns(true)
+
+ ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), "v1.0.0-exec.sh").returns(true)
+
+ local result = link.share(
+ ctx,
+ {
+ share = {
+ ["file"] = "{{version}}-{{source.file}}",
+ ["dir/"] = "{{version}}/dir/",
+ ["empty/"] = "{{source.empty}}",
+ },
+ },
+ Purl.parse("pkg:dummy/package@v1.0.0"):get_or_throw(),
+ {
+ file = "file",
+ }
+ )
+
+ assert.same(
+ Result.success {
+ ["file"] = "v1.0.0-file",
+ ["dir/file1"] = "v1.0.0/dir/file1",
+ ["dir/file2"] = "v1.0.0/dir/file2",
+ ["dir/file3"] = "v1.0.0/dir/file3",
+ },
+ result
+ )
+ end)
+
+ it("should register opt links", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "file_exists")
+ stub(fs.sync, "file_exists")
+ stub(vim.fn, "glob")
+
+ vim.fn.glob.on_call_with(path.concat { ctx.cwd:get(), "v1.0.0/dir/" } .. "**/*", false, true).returns {
+ path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file1" },
+ path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file2" },
+ path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file3" },
+ }
+ fs.sync.file_exists.on_call_with(path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file1" }).returns(true)
+ fs.sync.file_exists.on_call_with(path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file2" }).returns(true)
+ fs.sync.file_exists.on_call_with(path.concat { ctx.cwd:get(), "v1.0.0", "dir", "file3" }).returns(true)
+
+ ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), "v1.0.0-exec.sh").returns(true)
+
+ local result = link.opt(
+ ctx,
+ {
+ opt = {
+ ["file"] = "{{version}}-{{source.file}}",
+ ["dir/"] = "{{version}}/dir/",
+ ["empty/"] = "{{source.empty}}",
+ },
+ },
+ Purl.parse("pkg:dummy/package@v1.0.0"):get_or_throw(),
+ {
+ file = "file",
+ }
+ )
+
+ assert.same(
+ Result.success {
+ ["file"] = "v1.0.0-file",
+ ["dir/file1"] = "v1.0.0/dir/file1",
+ ["dir/file2"] = "v1.0.0/dir/file2",
+ ["dir/file3"] = "v1.0.0/dir/file3",
+ },
+ result
+ )
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/cargo_spec.lua b/tests/mason-core/installer/registry/providers/cargo_spec.lua
new file mode 100644
index 00000000..f2ae679c
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/cargo_spec.lua
@@ -0,0 +1,143 @@
+local stub = require "luassert.stub"
+local Result = require "mason-core.result"
+local cargo = require "mason-core.installer.registry.providers.cargo"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:cargo/crate-name@1.4.3"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("cargo provider :: parsing", function()
+ it("should parse package", function()
+ assert.same(
+ Result.success {
+ crate = "crate-name",
+ version = "1.4.3",
+ features = nil,
+ locked = true,
+ git = nil,
+ },
+ cargo.parse({}, purl())
+ )
+ end)
+
+ it("should respect repository_url qualifier", function()
+ assert.same(
+ Result.success {
+ crate = "crate-name",
+ version = "1.4.3",
+ features = nil,
+ locked = true,
+ git = { url = "https://github.com/crate-org/crate-name", rev = false },
+ },
+ cargo.parse({}, purl { qualifiers = { repository_url = "https://github.com/crate-org/crate-name" } })
+ )
+ end)
+
+ it("should respect repository_url qualifier with rev=true qualifier", function()
+ assert.same(
+ Result.success {
+ crate = "crate-name",
+ version = "1.4.3",
+ features = nil,
+ locked = true,
+ git = { url = "https://github.com/crate-org/crate-name", rev = true },
+ },
+ cargo.parse(
+ {},
+ purl { qualifiers = { repository_url = "https://github.com/crate-org/crate-name", rev = "true" } }
+ )
+ )
+ end)
+
+ it("should respect features qualifier", function()
+ assert.same(
+ Result.success {
+ crate = "crate-name",
+ version = "1.4.3",
+ features = "lsp,cli",
+ locked = true,
+ git = nil,
+ },
+ cargo.parse({}, purl { qualifiers = { features = "lsp,cli" } })
+ )
+ end)
+
+ it("should respect locked qualifier", function()
+ assert.same(
+ Result.success {
+ crate = "crate-name",
+ version = "1.4.3",
+ features = nil,
+ locked = false,
+ git = nil,
+ },
+ cargo.parse({}, purl { qualifiers = { locked = "false" } })
+ )
+ end)
+
+ it("should check supported platforms", function()
+ assert.same(
+ Result.failure "PLATFORM_UNSUPPORTED",
+ cargo.parse({
+ supported_platforms = { "VIC64" },
+ }, purl { qualifiers = { locked = "false" } })
+ )
+ end)
+end)
+
+describe("cargo provider :: installing", function()
+ it("should install cargo packages", function()
+ local ctx = create_dummy_context()
+ local manager = require "mason-core.installer.managers.cargo"
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return cargo.install(ctx, {
+ crate = "crate-name",
+ version = "1.2.0",
+ features = nil,
+ locked = true,
+ git = nil,
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(manager.install).was_called(1)
+ assert.spy(manager.install).was_called_with("crate-name", "1.2.0", {
+ git = nil,
+ features = nil,
+ locked = true,
+ })
+ end)
+
+ it("should ensure valid version", function()
+ local ctx = create_dummy_context {
+ version = "1.10.0",
+ }
+ local manager = require "mason-core.installer.managers.cargo"
+ local providers = require "mason-core.providers"
+ stub(providers.crates, "get_all_versions", mockx.returns(Result.success { "1.0.0" }))
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return cargo.install(ctx, {
+ crate = "crate-name",
+ version = "1.10.0",
+ features = nil,
+ locked = true,
+ git = nil,
+ })
+ end)
+
+ assert.is_true(result:is_failure())
+ assert.same(Result.failure [[Version "1.10.0" is not available.]], result)
+ assert.spy(manager.install).was_called(0)
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/composer_spec.lua b/tests/mason-core/installer/registry/providers/composer_spec.lua
new file mode 100644
index 00000000..4849e3f7
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/composer_spec.lua
@@ -0,0 +1,66 @@
+local stub = require "luassert.stub"
+local Result = require "mason-core.result"
+local composer = require "mason-core.installer.registry.providers.composer"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:composer/vendor/package@2.0.0"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("composer provider :: parsing", function()
+ it("should parse package", function()
+ assert.same(
+ Result.success {
+ package = "vendor/package",
+ version = "2.0.0",
+ },
+ composer.parse({}, purl())
+ )
+ end)
+end)
+
+describe("composer provider :: installing", function()
+ it("should install composer packages", function()
+ local ctx = create_dummy_context()
+ local manager = require "mason-core.installer.managers.composer"
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return composer.install(ctx, {
+ package = "vendor/package",
+ version = "1.2.0",
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(manager.install).was_called(1)
+ assert.spy(manager.install).was_called_with("vendor/package", "1.2.0")
+ end)
+
+ it("should ensure valid version", function()
+ local ctx = create_dummy_context {
+ version = "1.10.0",
+ }
+ local manager = require "mason-core.installer.managers.composer"
+ local providers = require "mason-core.providers"
+ stub(providers.packagist, "get_all_versions", mockx.returns(Result.success { "1.0.0" }))
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return composer.install(ctx, {
+ package = "vendor/package",
+ version = "1.10.0",
+ })
+ end)
+
+ assert.is_true(result:is_failure())
+ assert.same(Result.failure [[Version "1.10.0" is not available.]], result)
+ assert.spy(manager.install).was_called(0)
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/gem_spec.lua b/tests/mason-core/installer/registry/providers/gem_spec.lua
new file mode 100644
index 00000000..9696ec6e
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/gem_spec.lua
@@ -0,0 +1,72 @@
+local stub = require "luassert.stub"
+local Result = require "mason-core.result"
+local gem = require "mason-core.installer.registry.providers.gem"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:gem/package@1.2.0"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("gem provider :: parsing", function()
+ it("should parse package", function()
+ assert.same(
+ Result.success {
+ package = "package",
+ version = "1.2.0",
+ extra_packages = { "extra" },
+ },
+ gem.parse({ extra_packages = { "extra" } }, purl())
+ )
+ end)
+
+ it("should check supported platforms", function()
+ assert.same(Result.failure "PLATFORM_UNSUPPORTED", gem.parse({ supported_platforms = { "VIC64" } }, purl()))
+ end)
+end)
+
+describe("gem provider :: installing", function()
+ it("should install gem packages", function()
+ local ctx = create_dummy_context()
+ local manager = require "mason-core.installer.managers.gem"
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return gem.install(ctx, {
+ package = "package",
+ version = "5.2.0",
+ extra_packages = { "extra" },
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(manager.install).was_called(1)
+ assert.spy(manager.install).was_called_with("package", "5.2.0", { extra_packages = { "extra" } })
+ end)
+
+ it("should ensure valid version", function()
+ local ctx = create_dummy_context {
+ version = "1.10.0",
+ }
+ local manager = require "mason-core.installer.managers.gem"
+ local providers = require "mason-core.providers"
+ stub(providers.rubygems, "get_all_versions", mockx.returns(Result.success { "1.0.0" }))
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return gem.install(ctx, {
+ package = "package",
+ version = "1.10.0",
+ })
+ end)
+
+ assert.is_true(result:is_failure())
+ assert.same(Result.failure [[Version "1.10.0" is not available.]], result)
+ assert.spy(manager.install).was_called(0)
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/generic_spec.lua b/tests/mason-core/installer/registry/providers/generic_spec.lua
new file mode 100644
index 00000000..899709c5
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/generic_spec.lua
@@ -0,0 +1,100 @@
+local stub = require "luassert.stub"
+local Result = require "mason-core.result"
+local generic = require "mason-core.installer.registry.providers.generic"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:generic/namespace/name@v1.2.0"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("generic provider :: parsing", function()
+ it("should parse single download target", function()
+ assert.same(
+ Result.success {
+ download = {
+ files = {
+ ["name.tar.gz"] = [[https://getpackage.org/downloads/1.2.0/name.tar.gz]],
+ },
+ },
+ },
+ generic.parse({
+ download = {
+ files = {
+ ["name.tar.gz"] = [[https://getpackage.org/downloads/{{version | strip_prefix "v"}}/name.tar.gz]],
+ },
+ },
+ }, purl())
+ )
+ end)
+
+ it("should coalesce download target", function()
+ assert.same(
+ Result.success {
+ download = {
+ target = "linux_arm64",
+ files = {
+ ["name.tar.gz"] = [[https://getpackage.org/downloads/linux-aarch64/1.2.0/name.tar.gz]],
+ },
+ },
+ },
+ generic.parse({
+ download = {
+ {
+ target = "linux_arm64",
+ files = {
+ ["name.tar.gz"] = [[https://getpackage.org/downloads/linux-aarch64/{{version | strip_prefix "v"}}/name.tar.gz]],
+ },
+ },
+ {
+ target = "win_arm64",
+ files = {
+ ["name.tar.gz"] = [[https://getpackage.org/downloads/win-aarch64/{{version | strip_prefix "v"}}/name.tar.gz]],
+ },
+ },
+ },
+ }, purl(), { target = "linux_arm64" })
+ )
+ end)
+
+ it("should check supported platforms", function()
+ assert.same(Result.failure "PLATFORM_UNSUPPORTED", generic.parse({ supported_platforms = { "VIC64" } }, purl()))
+ end)
+end)
+
+describe("generic provider :: installing", function()
+ it("should install generic packages", function()
+ local ctx = create_dummy_context()
+ local std = require "mason-core.installer.managers.std"
+ stub(std, "download_file", mockx.returns(Result.success()))
+ stub(std, "unpack", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return generic.install(ctx, {
+ download = {
+ files = {
+ ["name.tar.gz"] = [[https://getpackage.org/downloads/linux-aarch64/1.2.0/name.tar.gz]],
+ ["archive.tar.gz"] = [[https://getpackage.org/downloads/linux-aarch64/1.2.0/archive.tar.gz]],
+ },
+ },
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(std.download_file).was_called(2)
+ assert
+ .spy(std.download_file)
+ .was_called_with("https://getpackage.org/downloads/linux-aarch64/1.2.0/name.tar.gz", "name.tar.gz")
+ assert
+ .spy(std.download_file)
+ .was_called_with("https://getpackage.org/downloads/linux-aarch64/1.2.0/archive.tar.gz", "archive.tar.gz")
+ assert.spy(std.unpack).was_called(2)
+ assert.spy(std.unpack).was_called_with "name.tar.gz"
+ assert.spy(std.unpack).was_called_with "archive.tar.gz"
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/github_spec.lua b/tests/mason-core/installer/registry/providers/github_spec.lua
new file mode 100644
index 00000000..0c43e3cf
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/github_spec.lua
@@ -0,0 +1,355 @@
+local stub = require "luassert.stub"
+local mock = require "luassert.mock"
+local spy = require "luassert.spy"
+local match = require "luassert.match"
+local Result = require "mason-core.result"
+local github = require "mason-core.installer.registry.providers.github"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+local registry_installer = require "mason-core.installer.registry"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:github/namespace/name@2023-03-09"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("github provider :: parsing", function()
+ it("should parse release asset source", function()
+ assert.same(
+ Result.success {
+ repo = "namespace/name",
+ asset = {
+ file = "file-2023-03-09.jar",
+ },
+ downloads = {
+ {
+ out_file = "file-2023-03-09.jar",
+ download_url = "https://github.com/namespace/name/releases/download/2023-03-09/file-2023-03-09.jar",
+ },
+ },
+ },
+ github.parse({
+ asset = {
+ file = "file-{{version}}.jar",
+ },
+ }, purl())
+ )
+ end)
+
+ it("should parse release asset source with multiple targets", function()
+ assert.same(
+ Result.success {
+ repo = "namespace/name",
+ asset = {
+ target = "linux_x64",
+ file = "file-linux-amd64-2023-03-09.tar.gz",
+ },
+ downloads = {
+ {
+ out_file = "file-linux-amd64-2023-03-09.tar.gz",
+ download_url = "https://github.com/namespace/name/releases/download/2023-03-09/file-linux-amd64-2023-03-09.tar.gz",
+ },
+ },
+ },
+ github.parse({
+ asset = {
+ {
+ target = "win_arm",
+ file = "file-win-arm-{{version}}.zip",
+ },
+ {
+ target = "linux_x64",
+ file = "file-linux-amd64-{{version}}.tar.gz",
+ },
+ },
+ }, purl(), { target = "linux_x64" })
+ )
+ end)
+
+ it("should parse release asset source with output to different directory", function()
+ assert.same(
+ Result.success {
+ repo = "namespace/name",
+ asset = {
+ file = "file-linux-amd64-2023-03-09.tar.gz:out-dir/",
+ },
+ downloads = {
+ {
+ out_file = "out-dir/file-linux-amd64-2023-03-09.tar.gz",
+ download_url = "https://github.com/namespace/name/releases/download/2023-03-09/file-linux-amd64-2023-03-09.tar.gz",
+ },
+ },
+ },
+ github.parse({
+ asset = {
+ file = "file-linux-amd64-{{version}}.tar.gz:out-dir/",
+ },
+ }, purl(), { target = "linux_x64" })
+ )
+ end)
+
+ it("should parse build source", function()
+ assert.same(
+ Result.success {
+ build = { run = [[npm install && npm run compile]] },
+ repo = "https://github.com/namespace/name.git",
+ rev = "2023-03-09",
+ },
+ github.parse({
+ build = {
+ run = [[npm install && npm run compile]],
+ },
+ }, purl())
+ )
+ end)
+
+ it("should parse build source with multiple targets", function()
+ assert.same(
+ Result.success {
+ build = { target = "win_x64", run = [[npm install]] },
+ repo = "https://github.com/namespace/name.git",
+ rev = "2023-03-09",
+ },
+ github.parse({
+ build = {
+ {
+ target = "linux_arm64",
+ run = [[npm install && npm run compile]],
+ },
+ {
+ target = "win_x64",
+ run = [[npm install]],
+ },
+ },
+ }, purl(), { target = "win_x64" })
+ )
+ end)
+
+ it("should upsert version overrides", function()
+ local result = registry_installer.parse({
+ schema = "registry+v1",
+ source = {
+ id = "pkg:github/owner/repo@1.2.3",
+ asset = {
+ {
+ target = "darwin_x64",
+ file = "asset.tar.gz",
+ },
+ },
+ version_overrides = {
+ {
+ constraint = "semver:<=1.0.0",
+ asset = {
+ {
+ target = "darwin_x64",
+ file = "old-asset.tar.gz",
+ },
+ },
+ },
+ },
+ },
+ }, { version = "1.0.0", target = "darwin_x64" })
+ local parsed = result:get_or_nil()
+
+ assert.is_true(result:is_success())
+ assert.same({
+ asset = {
+ target = "darwin_x64",
+ file = "old-asset.tar.gz",
+ },
+ downloads = {
+ {
+ download_url = "https://github.com/owner/repo/releases/download/1.0.0/old-asset.tar.gz",
+ out_file = "old-asset.tar.gz",
+ },
+ },
+ repo = "owner/repo",
+ }, parsed.source)
+ end)
+
+ it("should override source if version override provides its own purl id", function()
+ local result = registry_installer.parse({
+ schema = "registry+v1",
+ source = {
+ id = "pkg:github/owner/repo@1.2.3",
+ asset = {
+ file = "asset.tar.gz",
+ },
+ version_overrides = {
+ {
+ constraint = "semver:<=1.0.0",
+ id = "pkg:npm/old-package",
+ },
+ },
+ },
+ }, { version = "1.0.0", target = "darwin_x64" })
+
+ assert.is_true(result:is_success())
+ local parsed = result:get_or_throw()
+ assert.same({
+ type = "npm",
+ scheme = "pkg",
+ name = "old-package",
+ version = "1.0.0",
+ }, parsed.purl)
+ end)
+end)
+
+describe("github provider :: installing", function()
+ it("should install github release assets", function()
+ local ctx = create_dummy_context()
+ local std = require "mason-core.installer.managers.std"
+ stub(std, "download_file", mockx.returns(Result.success()))
+ stub(std, "unpack", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return github.install(ctx, {
+ repo = "namespace/name",
+ asset = {
+ file = "file-linux-amd64-2023-03-09.tar.gz",
+ },
+ downloads = {
+ {
+ out_file = "file-linux-amd64-2023-03-09.tar.gz",
+ download_url = "https://github.com/namespace/name/releases/download/2023-03-09/file-linux-amd64-2023-03-09.tar.gz",
+ },
+ {
+ out_file = "another-file-linux-amd64-2023-03-09.tar.gz",
+ download_url = "https://github.com/namespace/name/releases/download/2023-03-09/another-file-linux-amd64-2023-03-09.tar.gz",
+ },
+ },
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(std.download_file).was_called(2)
+ assert.spy(std.download_file).was_called_with(
+ "https://github.com/namespace/name/releases/download/2023-03-09/file-linux-amd64-2023-03-09.tar.gz",
+ "file-linux-amd64-2023-03-09.tar.gz"
+ )
+ assert.spy(std.download_file).was_called_with(
+ "https://github.com/namespace/name/releases/download/2023-03-09/another-file-linux-amd64-2023-03-09.tar.gz",
+ "another-file-linux-amd64-2023-03-09.tar.gz"
+ )
+ assert.spy(std.unpack).was_called(2)
+ assert.spy(std.unpack).was_called_with "file-linux-amd64-2023-03-09.tar.gz"
+ assert.spy(std.unpack).was_called_with "another-file-linux-amd64-2023-03-09.tar.gz"
+ end)
+
+ it("should install github release assets into specified output directory", function()
+ local ctx = create_dummy_context()
+ local std = require "mason-core.installer.managers.std"
+ local download_file_cwd, unpack_cwd
+ stub(std, "download_file", function()
+ download_file_cwd = ctx.cwd:get()
+ return Result.success()
+ end)
+ stub(std, "unpack", function()
+ unpack_cwd = ctx.cwd:get()
+ return Result.success()
+ end)
+ stub(ctx.fs, "mkdirp")
+ spy.on(ctx, "chdir")
+
+ local result = installer.exec_in_context(ctx, function()
+ return github.install(ctx, {
+ repo = "namespace/name",
+ asset = {
+ file = "file.zip",
+ },
+ downloads = {
+ {
+ out_file = "out/dir/file.zip",
+ download_url = "https://github.com/namespace/name/releases/download/2023-03-09/file.zip",
+ },
+ },
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(ctx.fs.mkdirp).was_called(1)
+ assert.spy(ctx.fs.mkdirp).was_called_with(match.is_ref(ctx.fs), "out/dir")
+ assert.spy(ctx.chdir).was_called(1)
+ assert.spy(ctx.chdir).was_called_with(match.is_ref(ctx), "out/dir", match.is_function())
+ assert.spy(std.download_file).was_called(1)
+ assert.is_true(match.matches "out/dir$"(download_file_cwd))
+ assert
+ .spy(std.download_file)
+ .was_called_with("https://github.com/namespace/name/releases/download/2023-03-09/file.zip", "file.zip")
+ assert.spy(std.unpack).was_called(1)
+ assert.is_true(match.matches "out/dir$"(unpack_cwd))
+ assert.spy(std.unpack).was_called_with "file.zip"
+ end)
+
+ it("should install ensure valid version when installing release asset", function()
+ local ctx = create_dummy_context {
+ version = "1.42.0",
+ }
+ local std = require "mason-core.installer.managers.std"
+ local providers = require "mason-core.providers"
+ stub(std, "download_file")
+ stub(providers.github, "get_all_release_versions", mockx.returns(Result.success { "2023-03-09" }))
+
+ local result = installer.exec_in_context(ctx, function()
+ return github.install(ctx, {
+ repo = "namespace/name",
+ asset = {
+ file = "file.zip",
+ },
+ downloads = {
+ {
+ out_file = "out/dir/file.zip",
+ download_url = "https://github.com/namespace/name/releases/download/2023-03-09/file.zip",
+ },
+ },
+ })
+ end)
+
+ assert.is_true(result:is_failure())
+ assert.same(Result.failure [[Version "1.42.0" is not available.]], result)
+ assert.spy(std.download_file).was_called(0)
+ end)
+
+ it("should install github build sources", function()
+ local ctx = create_dummy_context()
+ local std = require "mason-core.installer.managers.std"
+ local uv = require "mason-core.async.uv"
+ stub(uv, "write")
+ stub(uv, "shutdown")
+ stub(uv, "close")
+ local stdin = mock.new()
+ stub(std, "clone", mockx.returns(Result.success()))
+ stub(
+ ctx.spawn,
+ "bash", ---@param args SpawnArgs
+ function(args)
+ args.on_spawn(mock.new(), { stdin })
+ return Result.success()
+ end
+ )
+
+ local result = installer.exec_in_context(ctx, function()
+ return github.install(ctx, {
+ repo = "namespace/name",
+ rev = "2023-03-09",
+ build = {
+ run = [[npm install && npm run compile]],
+ },
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(std.clone).was_called(1)
+ assert.spy(std.clone).was_called_with("namespace/name", { rev = "2023-03-09" })
+ assert.spy(ctx.spawn.bash).was_called(1)
+ assert.spy(uv.write).was_called(2)
+ assert.spy(uv.write).was_called_with(stdin, "set -euxo pipefail;\n")
+ assert.spy(uv.write).was_called_with(stdin, "npm install && npm run compile")
+ assert.spy(uv.shutdown).was_called_with(stdin)
+ assert.spy(uv.close).was_called_with(stdin)
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/golang_spec.lua b/tests/mason-core/installer/registry/providers/golang_spec.lua
new file mode 100644
index 00000000..d7b9f448
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/golang_spec.lua
@@ -0,0 +1,68 @@
+local stub = require "luassert.stub"
+local Result = require "mason-core.result"
+local golang = require "mason-core.installer.registry.providers.golang"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:golang/namespace/package@v1.5.0"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("golang provider :: parsing", function()
+ it("should parse package", function()
+ assert.same(
+ Result.success {
+ package = "namespace/package",
+ version = "v1.5.0",
+ extra_packages = { "extra" },
+ },
+ golang.parse({ extra_packages = { "extra" } }, purl())
+ )
+ end)
+end)
+
+describe("golang provider :: installing", function()
+ it("should install golang packages", function()
+ local ctx = create_dummy_context()
+ local manager = require "mason-core.installer.managers.golang"
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return golang.install(ctx, {
+ package = "namespace/package",
+ version = "v1.5.0",
+ extra_packages = { "extra" },
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(manager.install).was_called(1)
+ assert.spy(manager.install).was_called_with("namespace/package", "v1.5.0", { extra_packages = { "extra" } })
+ end)
+
+ it("should ensure valid version", function()
+ local ctx = create_dummy_context {
+ version = "1.10.0",
+ }
+ local manager = require "mason-core.installer.managers.golang"
+ local providers = require "mason-core.providers"
+ stub(providers.golang, "get_all_versions", mockx.returns(Result.success { "1.0.0" }))
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return golang.install(ctx, {
+ package = "package",
+ version = "1.10.0",
+ })
+ end)
+
+ assert.is_true(result:is_failure())
+ assert.same(Result.failure [[Version "1.10.0" is not available.]], result)
+ assert.spy(manager.install).was_called(0)
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/luarocks_spec.lua b/tests/mason-core/installer/registry/providers/luarocks_spec.lua
new file mode 100644
index 00000000..992726eb
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/luarocks_spec.lua
@@ -0,0 +1,78 @@
+local stub = require "luassert.stub"
+local match = require "luassert.match"
+local Result = require "mason-core.result"
+local luarocks = require "mason-core.installer.registry.providers.luarocks"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:luarocks/namespace/name@1.0.0"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("luarocks provider :: parsing", function()
+ it("should parse package", function()
+ assert.same(
+ Result.success {
+ package = "namespace/name",
+ version = "1.0.0",
+ server = nil,
+ dev = false,
+ },
+ luarocks.parse({}, purl())
+ )
+ end)
+
+ it("should parse package dev flag", function()
+ assert.same(
+ Result.success {
+ package = "namespace/name",
+ version = "1.0.0",
+ server = nil,
+ dev = true,
+ },
+ luarocks.parse({}, purl { qualifiers = { dev = "true" } })
+ )
+ end)
+
+ it("should parse package server flag", function()
+ assert.same(
+ Result.success {
+ package = "namespace/name",
+ version = "1.0.0",
+ server = "https://luarocks.org/dev",
+ dev = false,
+ },
+ luarocks.parse({}, purl { qualifiers = { repository_url = "https://luarocks.org/dev" } })
+ )
+ end)
+end)
+
+describe("luarocks provider :: installing", function()
+ it("should install luarocks packages", function()
+ local ctx = create_dummy_context()
+ local manager = require "mason-core.installer.managers.luarocks"
+ local ret_val = Result.success()
+ stub(manager, "install", mockx.returns(ret_val))
+
+ local result = installer.exec_in_context(ctx, function()
+ return luarocks.install(ctx, {
+ package = "namespace/name",
+ version = "1.0.0",
+ server = "https://luarocks.org/dev",
+ dev = false,
+ })
+ end)
+
+ assert.is_true(match.is_ref(ret_val)(result))
+ assert.spy(manager.install).was_called(1)
+ assert.spy(manager.install).was_called_with("namespace/name", "1.0.0", {
+ dev = false,
+ server = "https://luarocks.org/dev",
+ })
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/npm_spec.lua b/tests/mason-core/installer/registry/providers/npm_spec.lua
new file mode 100644
index 00000000..cd20a07d
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/npm_spec.lua
@@ -0,0 +1,72 @@
+local stub = require "luassert.stub"
+local Result = require "mason-core.result"
+local npm = require "mason-core.installer.registry.providers.npm"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:npm/%40namespace/package@v1.5.0"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("npm provider :: parsing", function()
+ it("should parse package", function()
+ assert.same(
+ Result.success {
+ package = "@namespace/package",
+ version = "v1.5.0",
+ extra_packages = { "extra" },
+ },
+ npm.parse({ extra_packages = { "extra" } }, purl())
+ )
+ end)
+end)
+
+describe("npm provider :: installing", function()
+ it("should install npm packages", function()
+ local ctx = create_dummy_context()
+ local manager = require "mason-core.installer.managers.npm"
+ stub(manager, "init", mockx.returns(Result.success()))
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return npm.install(ctx, {
+ package = "@namespace/package",
+ version = "v1.5.0",
+ extra_packages = { "extra" },
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(manager.init).was_called(1)
+ assert.spy(manager.install).was_called(1)
+ assert.spy(manager.install).was_called_with("@namespace/package", "v1.5.0", { extra_packages = { "extra" } })
+ end)
+
+ it("should ensure valid version", function()
+ local ctx = create_dummy_context {
+ version = "1.10.0",
+ }
+ local manager = require "mason-core.installer.managers.npm"
+ local providers = require "mason-core.providers"
+ stub(providers.npm, "get_all_versions", mockx.returns(Result.success { "1.0.0" }))
+ stub(manager, "init", mockx.returns(Result.success()))
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return npm.install(ctx, {
+ package = "package",
+ version = "1.10.0",
+ })
+ end)
+
+ assert.is_true(result:is_failure())
+ assert.same(Result.failure [[Version "1.10.0" is not available.]], result)
+ assert.spy(manager.init).was_called(0)
+ assert.spy(manager.install).was_called(0)
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/nuget_spec.lua b/tests/mason-core/installer/registry/providers/nuget_spec.lua
new file mode 100644
index 00000000..eac96251
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/nuget_spec.lua
@@ -0,0 +1,45 @@
+local stub = require "luassert.stub"
+local Result = require "mason-core.result"
+local nuget = require "mason-core.installer.registry.providers.nuget"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:nuget/package@2.2.0"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("nuget provider :: parsing", function()
+ it("should parse package", function()
+ assert.same(
+ Result.success {
+ package = "package",
+ version = "2.2.0",
+ },
+ nuget.parse({}, purl())
+ )
+ end)
+end)
+
+describe("nuget provider :: installing", function()
+ it("should install nuget packages", function()
+ local ctx = create_dummy_context()
+ local manager = require "mason-core.installer.managers.nuget"
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return nuget.install(ctx, {
+ package = "package",
+ version = "1.5.0",
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(manager.install).was_called(1)
+ assert.spy(manager.install).was_called_with("package", "1.5.0")
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/opam_spec.lua b/tests/mason-core/installer/registry/providers/opam_spec.lua
new file mode 100644
index 00000000..53b5d767
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/opam_spec.lua
@@ -0,0 +1,45 @@
+local stub = require "luassert.stub"
+local Result = require "mason-core.result"
+local opam = require "mason-core.installer.registry.providers.opam"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:opam/package@2.2.0"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("opam provider :: parsing", function()
+ it("should parse package", function()
+ assert.same(
+ Result.success {
+ package = "package",
+ version = "2.2.0",
+ },
+ opam.parse({}, purl())
+ )
+ end)
+end)
+
+describe("opam provider :: installing", function()
+ it("should install opam packages", function()
+ local ctx = create_dummy_context()
+ local manager = require "mason-core.installer.managers.opam"
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return opam.install(ctx, {
+ package = "package",
+ version = "1.5.0",
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(manager.install).was_called(1)
+ assert.spy(manager.install).was_called_with("package", "1.5.0")
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/providers/pypi_spec.lua b/tests/mason-core/installer/registry/providers/pypi_spec.lua
new file mode 100644
index 00000000..222b473e
--- /dev/null
+++ b/tests/mason-core/installer/registry/providers/pypi_spec.lua
@@ -0,0 +1,110 @@
+local stub = require "luassert.stub"
+local settings = require "mason.settings"
+local Result = require "mason-core.result"
+local pypi = require "mason-core.installer.registry.providers.pypi"
+local Purl = require "mason-core.purl"
+local installer = require "mason-core.installer"
+
+---@param overrides Purl
+local function purl(overrides)
+ local purl = Purl.parse("pkg:pypi/package@5.5.0"):get_or_throw()
+ if not overrides then
+ return purl
+ end
+ return vim.tbl_deep_extend("force", purl, overrides)
+end
+
+describe("pypi provider :: parsing", function()
+ it("should parse package", function()
+ settings.set {
+ pip = {
+ install_args = { "--proxy", "http://localghost" },
+ upgrade_pip = true,
+ },
+ }
+
+ assert.same(
+ Result.success {
+ package = "package",
+ version = "5.5.0",
+ extra_packages = { "extra" },
+ pip = {
+ upgrade = true,
+ extra_args = { "--proxy", "http://localghost" },
+ },
+ },
+ pypi.parse({ extra_packages = { "extra" } }, purl())
+ )
+ settings.set(settings._DEFAULT_SETTINGS)
+ end)
+
+ it("should check supported platforms", function()
+ assert.same(Result.failure "PLATFORM_UNSUPPORTED", pypi.parse({ supported_platforms = { "VIC64" } }, purl()))
+ end)
+end)
+
+describe("pypi provider :: installing", function()
+ it("should install pypi packages", function()
+ local ctx = create_dummy_context()
+ local manager = require "mason-core.installer.managers.pypi"
+ stub(manager, "init", mockx.returns(Result.success()))
+ stub(manager, "install", mockx.returns(Result.success()))
+ settings.set {
+ pip = {
+ install_args = { "--proxy", "http://localghost" },
+ upgrade_pip = true,
+ },
+ }
+
+ local result = installer.exec_in_context(ctx, function()
+ return pypi.install(ctx, {
+ package = "package",
+ extra = "lsp",
+ version = "1.5.0",
+ extra_packages = { "extra" },
+ pip = {
+ upgrade = true,
+ extra_args = { "--proxy", "http://localghost" },
+ },
+ })
+ end)
+
+ assert.is_true(result:is_success())
+ assert.spy(manager.init).was_called(1)
+ assert.spy(manager.init).was_called_with {
+ upgrade_pip = true,
+ install_extra_args = { "--proxy", "http://localghost" },
+ }
+ assert.spy(manager.install).was_called(1)
+ assert.spy(manager.install).was_called_with("package", "1.5.0", { extra = "lsp", extra_packages = { "extra" } })
+ settings.set(settings._DEFAULT_SETTINGS)
+ end)
+
+ it("should ensure valid version", function()
+ local ctx = create_dummy_context {
+ version = "1.10.0",
+ }
+ local manager = require "mason-core.installer.managers.pypi"
+ local providers = require "mason-core.providers"
+ stub(providers.pypi, "get_all_versions", mockx.returns(Result.success { "1.0.0" }))
+ stub(manager, "init", mockx.returns(Result.success()))
+ stub(manager, "install", mockx.returns(Result.success()))
+
+ local result = installer.exec_in_context(ctx, function()
+ return pypi.install(ctx, {
+ package = "package",
+ version = "1.5.0",
+ extra_packages = {},
+ pip = {
+ upgrade = true,
+ extra_args = { "--proxy", "http://localghost" },
+ },
+ })
+ end)
+
+ assert.is_true(result:is_failure())
+ assert.same(Result.failure [[Version "1.10.0" is not available.]], result)
+ assert.spy(manager.init).was_called(0)
+ assert.spy(manager.install).was_called(0)
+ end)
+end)
diff --git a/tests/mason-core/installer/registry/util_spec.lua b/tests/mason-core/installer/registry/util_spec.lua
new file mode 100644
index 00000000..d6cdd6b5
--- /dev/null
+++ b/tests/mason-core/installer/registry/util_spec.lua
@@ -0,0 +1,81 @@
+local match = require "luassert.match"
+local Result = require "mason-core.result"
+local util = require "mason-core.installer.registry.util"
+local platform = require "mason-core.platform"
+local installer = require "mason-core.installer"
+
+describe("registry installer util", function()
+ it("should coalesce single target", function()
+ local source = { value = "here" }
+ local coalesced = util.coalesce_by_target(source, {}):get()
+ assert.is_true(match.is_ref(source)(coalesced))
+ end)
+
+ it("should coalesce multiple targets", function()
+ local source = { target = "VIC64", value = "here" }
+ local coalesced = util.coalesce_by_target({
+ {
+ target = "linux_arm64",
+ value = "here",
+ },
+ source,
+ }, { target = "VIC64" }):get()
+
+ assert.is_true(match.is_ref(source)(coalesced))
+ end)
+
+ it("should accept valid platform", function()
+ platform.is.VIC64 = true
+ local result = util.ensure_valid_platform {
+ "VIC64",
+ "linux_arm64",
+ }
+ assert.is_true(result:is_success())
+ platform.is.VIC64 = nil
+ end)
+
+ it("should reject invalid platform", function()
+ local result = util.ensure_valid_platform { "VIC64" }
+ assert.same(Result.failure "PLATFORM_UNSUPPORTED", result)
+ end)
+
+ it("should accept valid version", function()
+ local ctx = create_dummy_context { version = "1.0.0" }
+ local result = installer.exec_in_context(ctx, function()
+ return util.ensure_valid_version(function()
+ return Result.success { "1.0.0", "2.0.0", "3.0.0" }
+ end)
+ end)
+ assert.is_true(result:is_success())
+ end)
+
+ it("should reject invalid version", function()
+ local ctx = create_dummy_context { version = "13.3.7" }
+ local result = installer.exec_in_context(ctx, function()
+ return util.ensure_valid_version(function()
+ return Result.success { "1.0.0", "2.0.0", "3.0.0" }
+ end)
+ end)
+ assert.same(Result.failure [[Version "13.3.7" is not available.]], result)
+ end)
+
+ it("should gracefully accept version if unable to resolve available versions", function()
+ local ctx = create_dummy_context { version = "13.3.7" }
+ local result = installer.exec_in_context(ctx, function()
+ return util.ensure_valid_version(function()
+ return Result.failure()
+ end)
+ end)
+ assert.is_true(result:is_success())
+ end)
+
+ it("should accept version if in force mode", function()
+ local ctx = create_dummy_context { version = "13.3.7", force = true }
+ local result = installer.exec_in_context(ctx, function()
+ return util.ensure_valid_version(function()
+ return Result.success { "1.0.0" }
+ end)
+ end)
+ assert.is_true(result:is_success())
+ end)
+end)
diff --git a/tests/mason-core/managers/powershell_spec.lua b/tests/mason-core/managers/powershell_spec.lua
index 46e096bf..b8facacb 100644
--- a/tests/mason-core/managers/powershell_spec.lua
+++ b/tests/mason-core/managers/powershell_spec.lua
@@ -31,7 +31,9 @@ describe("powershell manager", function()
stub(vim.fn, "executable")
vim.fn.executable.on_call_with("pwsh").returns(0)
- powershell().command "echo 'Is this bash?'"
+ local powershell = powershell()
+ a.scheduler()
+ powershell.command "echo 'Is this bash?'"
assert.spy(spawn.pwsh).was_called(0)
assert.spy(spawn.powershell).was_called(1)
diff --git a/tests/mason-core/package/package_spec.lua b/tests/mason-core/package/package_spec.lua
index 1eee3ed5..6f8eb8d4 100644
--- a/tests/mason-core/package/package_spec.lua
+++ b/tests/mason-core/package/package_spec.lua
@@ -86,6 +86,7 @@ describe("package", function()
local handle = dummy:new_handle()
assert.spy(handle_handler).was_called(1)
assert.spy(handle_handler).was_called_with(match.ref(handle))
+ handle:close()
end)
it("should not create new handle if one already exists", function()
@@ -100,6 +101,7 @@ describe("package", function()
end)
assert.equals("Cannot create new handle because existing handle is not closed.", err)
assert.spy(handle_handler).was_called(0)
+ dummy.handle = nil
end)
it(
@@ -186,7 +188,6 @@ describe("package", function()
assert.wait_for(function()
assert.is_true(handle:is_closed())
- assert.is_true(dummy:is_installed())
end)
end)
)