aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/reference.md41
-rw-r--r--lua/mason-core/installer/compiler/compilers/cargo.lua (renamed from lua/mason-core/installer/registry/providers/cargo.lua)2
-rw-r--r--lua/mason-core/installer/compiler/compilers/composer.lua (renamed from lua/mason-core/installer/registry/providers/composer.lua)2
-rw-r--r--lua/mason-core/installer/compiler/compilers/gem.lua (renamed from lua/mason-core/installer/registry/providers/gem.lua)2
-rw-r--r--lua/mason-core/installer/compiler/compilers/generic/build.lua (renamed from lua/mason-core/installer/registry/providers/generic/build.lua)4
-rw-r--r--lua/mason-core/installer/compiler/compilers/generic/download.lua (renamed from lua/mason-core/installer/registry/providers/generic/download.lua)4
-rw-r--r--lua/mason-core/installer/compiler/compilers/generic/init.lua (renamed from lua/mason-core/installer/registry/providers/generic/init.lua)8
-rw-r--r--lua/mason-core/installer/compiler/compilers/github/build.lua (renamed from lua/mason-core/installer/registry/providers/github/build.lua)4
-rw-r--r--lua/mason-core/installer/compiler/compilers/github/init.lua (renamed from lua/mason-core/installer/registry/providers/github/init.lua)10
-rw-r--r--lua/mason-core/installer/compiler/compilers/github/release.lua (renamed from lua/mason-core/installer/registry/providers/github/release.lua)11
-rw-r--r--lua/mason-core/installer/compiler/compilers/golang.lua (renamed from lua/mason-core/installer/registry/providers/golang.lua)2
-rw-r--r--lua/mason-core/installer/compiler/compilers/luarocks.lua (renamed from lua/mason-core/installer/registry/providers/luarocks.lua)0
-rw-r--r--lua/mason-core/installer/compiler/compilers/mason.lua (renamed from lua/mason-core/installer/registry/providers/mason.lua)0
-rw-r--r--lua/mason-core/installer/compiler/compilers/npm.lua (renamed from lua/mason-core/installer/registry/providers/npm.lua)0
-rw-r--r--lua/mason-core/installer/compiler/compilers/nuget.lua (renamed from lua/mason-core/installer/registry/providers/nuget.lua)0
-rw-r--r--lua/mason-core/installer/compiler/compilers/opam.lua (renamed from lua/mason-core/installer/registry/providers/opam.lua)0
-rw-r--r--lua/mason-core/installer/compiler/compilers/openvsx.lua (renamed from lua/mason-core/installer/registry/providers/openvsx.lua)7
-rw-r--r--lua/mason-core/installer/compiler/compilers/pypi.lua (renamed from lua/mason-core/installer/registry/providers/pypi.lua)2
-rw-r--r--lua/mason-core/installer/compiler/expr.lua (renamed from lua/mason-core/installer/registry/expr.lua)0
-rw-r--r--lua/mason-core/installer/compiler/init.lua (renamed from lua/mason-core/installer/registry/init.lua)66
-rw-r--r--lua/mason-core/installer/compiler/link.lua (renamed from lua/mason-core/installer/registry/link.lua)2
-rw-r--r--lua/mason-core/installer/compiler/schemas.lua (renamed from lua/mason-core/installer/registry/schemas.lua)2
-rw-r--r--lua/mason-core/installer/compiler/util.lua (renamed from lua/mason-core/installer/registry/util.lua)0
-rw-r--r--lua/mason-core/installer/context/cwd.lua48
-rw-r--r--lua/mason-core/installer/context/fs.lua108
-rw-r--r--lua/mason-core/installer/context/init.lua (renamed from lua/mason-core/installer/context.lua)250
-rw-r--r--lua/mason-core/installer/context/spawn.lua46
-rw-r--r--lua/mason-core/installer/handle.lua4
-rw-r--r--lua/mason-core/installer/init.lua255
-rw-r--r--lua/mason-core/installer/location.lua63
-rw-r--r--lua/mason-core/installer/runner.lua218
-rw-r--r--lua/mason-core/package/init.lua114
-rw-r--r--lua/mason-core/receipt.lua14
-rw-r--r--lua/mason-registry/sources/util.lua4
-rw-r--r--lua/mason-test/helpers.lua33
-rw-r--r--tests/helpers/lua/luassertx.lua21
-rw-r--r--tests/helpers/lua/test_helpers.lua70
-rw-r--r--tests/mason-core/EventEmitter_spec.lua29
-rw-r--r--tests/mason-core/async/async_spec.lua210
-rw-r--r--tests/mason-core/fetch_spec.lua207
-rw-r--r--tests/mason-core/fs_spec.lua21
-rw-r--r--tests/mason-core/installer/context_spec.lua46
-rw-r--r--tests/mason-core/installer/handle_spec.lua65
-rw-r--r--tests/mason-core/installer/installer_spec.lua217
-rw-r--r--tests/mason-core/installer/linker_spec.lua212
-rw-r--r--tests/mason-core/installer/managers/cargo_spec.lua26
-rw-r--r--tests/mason-core/installer/managers/common_spec.lua17
-rw-r--r--tests/mason-core/installer/managers/composer_spec.lua10
-rw-r--r--tests/mason-core/installer/managers/gem_spec.lua20
-rw-r--r--tests/mason-core/installer/managers/golang_spec.lua14
-rw-r--r--tests/mason-core/installer/managers/luarocks_spec.lua28
-rw-r--r--tests/mason-core/installer/managers/npm_spec.lua32
-rw-r--r--tests/mason-core/installer/managers/nuget_spec.lua10
-rw-r--r--tests/mason-core/installer/managers/opam_spec.lua10
-rw-r--r--tests/mason-core/installer/managers/powershell_spec.lua34
-rw-r--r--tests/mason-core/installer/managers/pypi_spec.lua50
-rw-r--r--tests/mason-core/installer/managers/std_spec.lua56
-rw-r--r--tests/mason-core/installer/registry/compilers/cargo_spec.lua (renamed from tests/mason-core/installer/registry/providers/cargo_spec.lua)28
-rw-r--r--tests/mason-core/installer/registry/compilers/composer_spec.lua (renamed from tests/mason-core/installer/registry/providers/composer_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/compilers/gem_spec.lua (renamed from tests/mason-core/installer/registry/providers/gem_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/compilers/generic/build_spec.lua (renamed from tests/mason-core/installer/registry/providers/generic/build_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/compilers/generic/download_spec.lua (renamed from tests/mason-core/installer/registry/providers/generic/download_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/compilers/github/build_spec.lua (renamed from tests/mason-core/installer/registry/providers/github/build_spec.lua)2
-rw-r--r--tests/mason-core/installer/registry/compilers/github/release_spec.lua (renamed from tests/mason-core/installer/registry/providers/github/release_spec.lua)24
-rw-r--r--tests/mason-core/installer/registry/compilers/golang_spec.lua (renamed from tests/mason-core/installer/registry/providers/golang_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/compilers/luarocks_spec.lua (renamed from tests/mason-core/installer/registry/providers/luarocks_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/compilers/npm_spec.lua (renamed from tests/mason-core/installer/registry/providers/npm_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/compilers/nuget_spec.lua (renamed from tests/mason-core/installer/registry/providers/nuget_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/compilers/opam_spec.lua (renamed from tests/mason-core/installer/registry/providers/opam_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/compilers/openvsx_spec.lua (renamed from tests/mason-core/installer/registry/providers/openvsx_spec.lua)11
-rw-r--r--tests/mason-core/installer/registry/compilers/pypi_spec.lua (renamed from tests/mason-core/installer/registry/providers/pypi_spec.lua)18
-rw-r--r--tests/mason-core/installer/registry/expr_spec.lua2
-rw-r--r--tests/mason-core/installer/registry/installer_spec.lua103
-rw-r--r--tests/mason-core/installer/registry/link_spec.lua25
-rw-r--r--tests/mason-core/installer/registry/util_spec.lua20
-rw-r--r--tests/mason-core/installer/runner_spec.lua300
-rw-r--r--tests/mason-core/package/package_spec.lua123
-rw-r--r--tests/mason-core/platform_spec.lua10
-rw-r--r--tests/mason-core/process_spec.lua35
-rw-r--r--tests/mason-core/result_spec.lua40
-rw-r--r--tests/mason-core/spawn_spec.lua337
-rw-r--r--tests/mason-core/terminator_spec.lua167
-rw-r--r--tests/mason-core/ui_spec.lua308
-rw-r--r--tests/mason-registry/api_spec.lua10
-rw-r--r--tests/mason/api/command_spec.lua169
-rw-r--r--tests/minimal_init.vim17
-rw-r--r--vim.yml17
87 files changed, 2482 insertions, 2177 deletions
diff --git a/doc/reference.md b/doc/reference.md
index 2f23e793..ef00425c 100644
--- a/doc/reference.md
+++ b/doc/reference.md
@@ -34,7 +34,8 @@ RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as de
- [`Package.License`](#packagelicense)
- [`Package.new({spec})`](#packagenewspec)
- [`Package.spec`](#packagespec)
- - [`Package:install({opts?})`](#packageinstallopts)
+ - [`Package:is_installing()`](#packageis_installing)
+ - [`Package:install({opts?}, {callback?})`](#packageinstallopts-callback)
- [`Package:uninstall()`](#packageuninstall)
- [`Package:is_installed()`](#packageis_installed)
- [`Package:get_install_path()`](#packageget_install_path)
@@ -82,12 +83,12 @@ RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as de
The `mason-registry` Lua module extends the [EventEmitter](#eventemitter) interface and emits the following events:
-| Event | Handler signature |
-| --------------------------- | ------------------------------------------ |
-| `package:handle` | `fun(pkg: Package, handle: InstallHandle)` |
-| `package:install:success` | `fun(pkg: Package, handle: InstallHandle)` |
-| `package:install:failed` | `fun(pkg: Package, handle: InstallHandle)` |
-| `package:uninstall:success` | `fun(pkg: Package)` |
+| Event | Handler signature |
+| --------------------------- | ------------------------------------------------------ |
+| `package:handle` | `fun(pkg: Package, handle: InstallHandle)` |
+| `package:install:success` | `fun(pkg: Package, handle: InstallHandle)` |
+| `package:install:failed` | `fun(pkg: Package, handle: InstallHandle, error: any)` |
+| `package:uninstall:success` | `fun(pkg: Package)` |
The following is an example for how to register handlers for events:
@@ -135,11 +136,11 @@ The `Package` class encapsulates the installation instructions and metadata abou
This class extends the [EventEmitter](#eventemitter) interface and emits the following events:
-| Event | Handler signature |
-| ------------------- | ---------------------------- |
-| `install:success` | `fun(handle: InstallHandle)` |
-| `install:failed` | `fun(handle: InstallHandle)` |
-| `uninstall:success` | `fun()` |
+| Event | Handler signature |
+| ------------------- | ------------------------------------------------------ |
+| `install:success` | `fun(handle: InstallHandle)` |
+| `install:failed` | `fun(pkg: Package, handle: InstallHandle, error: any)` |
+| `uninstall:success` | `fun()` |
### `Package.Parse({package_identifier})`
@@ -193,22 +194,28 @@ Similar as [`Package.Lang`](#packagelang) but for SPDX license identifiers.
**Type**: [`RegistryPackageSpec`](#registrypackagespec)
-### `Package:install({opts?})`
+### `Package:is_installing()`
+
+**Returns:** `boolean`
+
+### `Package:install({opts?}, {callback?})`
**Parameters:**
- `opts?`: [`PackageInstallOpts`](#packageinstallopts-1) (optional)
+- `callback?`: `fun(success: boolean, result: any)` (optional) - Callback to be called when package installation completes. _Note: this is called before events (["package:install:success"](#registry-events), ["install:success"](#package)) are emitted._
**Returns:** [`InstallHandle`](#installhandle)
-Installs the package instance this method is being called on. Accepts an
-optional `{opts}` argument, which can be used to specify a desired version to
-install.
+Installs the package instance this method is being called on. Accepts an optional `{opts}` argument which can be used to
+for example specify which version to install (see [`PackageInstallOpts`](#packageinstallopts-1)), and an optional
+`{callback}` argument which is called when the installation finishes.
The returned [`InstallHandle`](#installhandle) can be used to observe progress and control the installation process
(e.g., cancelling).
-_Note that if the package already have an active handle registered, that handler is returned instead of a new one._
+_Note that if the package is already being installed this method will error. See
+[`Package:is_installing()`](#packageis_installing)._
### `Package:uninstall()`
diff --git a/lua/mason-core/installer/registry/providers/cargo.lua b/lua/mason-core/installer/compiler/compilers/cargo.lua
index f4904b73..e0f281c5 100644
--- a/lua/mason-core/installer/registry/providers/cargo.lua
+++ b/lua/mason-core/installer/compiler/compilers/cargo.lua
@@ -1,7 +1,7 @@
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local providers = require "mason-core.providers"
-local util = require "mason-core.installer.registry.util"
+local util = require "mason-core.installer.compiler.util"
local M = {}
diff --git a/lua/mason-core/installer/registry/providers/composer.lua b/lua/mason-core/installer/compiler/compilers/composer.lua
index d85dd2ba..259512a2 100644
--- a/lua/mason-core/installer/registry/providers/composer.lua
+++ b/lua/mason-core/installer/compiler/compilers/composer.lua
@@ -1,6 +1,6 @@
local Result = require "mason-core.result"
local providers = require "mason-core.providers"
-local util = require "mason-core.installer.registry.util"
+local util = require "mason-core.installer.compiler.util"
local M = {}
diff --git a/lua/mason-core/installer/registry/providers/gem.lua b/lua/mason-core/installer/compiler/compilers/gem.lua
index 9653f116..7a343eec 100644
--- a/lua/mason-core/installer/registry/providers/gem.lua
+++ b/lua/mason-core/installer/compiler/compilers/gem.lua
@@ -1,7 +1,7 @@
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local providers = require "mason-core.providers"
-local util = require "mason-core.installer.registry.util"
+local util = require "mason-core.installer.compiler.util"
local M = {}
diff --git a/lua/mason-core/installer/registry/providers/generic/build.lua b/lua/mason-core/installer/compiler/compilers/generic/build.lua
index a0d517d8..df97a118 100644
--- a/lua/mason-core/installer/registry/providers/generic/build.lua
+++ b/lua/mason-core/installer/compiler/compilers/generic/build.lua
@@ -1,8 +1,8 @@
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local common = require "mason-core.installer.managers.common"
-local expr = require "mason-core.installer.registry.expr"
-local util = require "mason-core.installer.registry.util"
+local expr = require "mason-core.installer.compiler.expr"
+local util = require "mason-core.installer.compiler.util"
local M = {}
diff --git a/lua/mason-core/installer/registry/providers/generic/download.lua b/lua/mason-core/installer/compiler/compilers/generic/download.lua
index 4622a844..37e54d96 100644
--- a/lua/mason-core/installer/registry/providers/generic/download.lua
+++ b/lua/mason-core/installer/compiler/compilers/generic/download.lua
@@ -1,8 +1,8 @@
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local common = require "mason-core.installer.managers.common"
-local expr = require "mason-core.installer.registry.expr"
-local util = require "mason-core.installer.registry.util"
+local expr = require "mason-core.installer.compiler.expr"
+local util = require "mason-core.installer.compiler.util"
local M = {}
diff --git a/lua/mason-core/installer/registry/providers/generic/init.lua b/lua/mason-core/installer/compiler/compilers/generic/init.lua
index 1bf79e94..8206883f 100644
--- a/lua/mason-core/installer/registry/providers/generic/init.lua
+++ b/lua/mason-core/installer/compiler/compilers/generic/init.lua
@@ -9,10 +9,10 @@ local M = {}
function M.parse(source, purl, opts)
if source.download then
source = source --[[@as GenericDownloadSource]]
- return require("mason-core.installer.registry.providers.generic.download").parse(source, purl, opts)
+ return require("mason-core.installer.compiler.compilers.generic.download").parse(source, purl, opts)
elseif source.build then
source = source --[[@as GenericBuildSource]]
- return require("mason-core.installer.registry.providers.generic.build").parse(source, purl, opts)
+ return require("mason-core.installer.compiler.compilers.generic.build").parse(source, purl, opts)
else
return Result.failure "Unknown source type."
end
@@ -24,10 +24,10 @@ end
function M.install(ctx, source)
if source.download then
source = source --[[@as ParsedGenericDownloadSource]]
- return require("mason-core.installer.registry.providers.generic.download").install(ctx, source)
+ return require("mason-core.installer.compiler.compilers.generic.download").install(ctx, source)
elseif source.build then
source = source --[[@as ParsedGenericBuildSource]]
- return require("mason-core.installer.registry.providers.generic.build").install(ctx, source)
+ return require("mason-core.installer.compiler.compilers.generic.build").install(ctx, source)
else
return Result.failure "Unknown source type."
end
diff --git a/lua/mason-core/installer/registry/providers/github/build.lua b/lua/mason-core/installer/compiler/compilers/github/build.lua
index 1c17bb1a..22f3e3cc 100644
--- a/lua/mason-core/installer/registry/providers/github/build.lua
+++ b/lua/mason-core/installer/compiler/compilers/github/build.lua
@@ -1,8 +1,8 @@
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local common = require "mason-core.installer.managers.common"
-local expr = require "mason-core.installer.registry.expr"
-local util = require "mason-core.installer.registry.util"
+local expr = require "mason-core.installer.compiler.expr"
+local util = require "mason-core.installer.compiler.util"
local M = {}
diff --git a/lua/mason-core/installer/registry/providers/github/init.lua b/lua/mason-core/installer/compiler/compilers/github/init.lua
index 0d68f3a5..d8646975 100644
--- a/lua/mason-core/installer/registry/providers/github/init.lua
+++ b/lua/mason-core/installer/compiler/compilers/github/init.lua
@@ -8,10 +8,10 @@ local M = {}
function M.parse(source, purl, opts)
if source.asset then
source = source --[[@as GitHubReleaseSource]]
- return require("mason-core.installer.registry.providers.github.release").parse(source, purl, opts)
+ return require("mason-core.installer.compiler.compilers.github.release").parse(source, purl, opts)
elseif source.build then
source = source --[[@as GitHubBuildSource]]
- return require("mason-core.installer.registry.providers.github.build").parse(source, purl, opts)
+ return require("mason-core.installer.compiler.compilers.github.build").parse(source, purl, opts)
else
return Result.failure "Unknown source type."
end
@@ -23,10 +23,10 @@ end
function M.install(ctx, source, purl)
if source.asset then
source = source--[[@as ParsedGitHubReleaseSource]]
- return require("mason-core.installer.registry.providers.github.release").install(ctx, source)
+ return require("mason-core.installer.compiler.compilers.github.release").install(ctx, source)
elseif source.build then
source = source--[[@as ParsedGitHubBuildSource]]
- return require("mason-core.installer.registry.providers.github.build").install(ctx, source)
+ return require("mason-core.installer.compiler.compilers.github.build").install(ctx, source)
else
return Result.failure "Unknown source type."
end
@@ -37,7 +37,7 @@ end
---@param source GitHubReleaseSource | GitHubBuildSource
function M.get_versions(purl, source)
if source.asset then
- return require("mason-core.installer.registry.providers.github.release").get_versions(purl)
+ return require("mason-core.installer.compiler.compilers.github.release").get_versions(purl)
elseif source.build then
-- We can't yet reliably determine the true source (release, tag, commit, etc.) for "build" sources.
return Result.failure "Unimplemented."
diff --git a/lua/mason-core/installer/registry/providers/github/release.lua b/lua/mason-core/installer/compiler/compilers/github/release.lua
index 8c8a8a8f..39f7d862 100644
--- a/lua/mason-core/installer/registry/providers/github/release.lua
+++ b/lua/mason-core/installer/compiler/compilers/github/release.lua
@@ -1,13 +1,16 @@
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local common = require "mason-core.installer.managers.common"
-local expr = require "mason-core.installer.registry.expr"
+local expr = require "mason-core.installer.compiler.expr"
local providers = require "mason-core.providers"
local settings = require "mason.settings"
-local util = require "mason-core.installer.registry.util"
+local util = require "mason-core.installer.compiler.util"
+
+---@class GitHubReleaseSourceAsset : FileDownloadSpec
+---@field target? Platform | Platform[]
---@class GitHubReleaseSource : RegistryPackageSource
----@field asset FileDownloadSpec | FileDownloadSpec[]
+---@field asset GitHubReleaseSourceAsset | GitHubReleaseSourceAsset[]
local M = {}
@@ -17,7 +20,7 @@ local M = {}
function M.parse(source, purl, opts)
return Result.try(function(try)
local expr_ctx = { version = purl.version }
- ---@type FileDownloadSpec
+ ---@type GitHubReleaseSourceAsset
local asset = try(util.coalesce_by_target(try(expr.tbl_interpolate(source.asset, expr_ctx)), opts))
local downloads = common.parse_downloads(asset, function(file)
diff --git a/lua/mason-core/installer/registry/providers/golang.lua b/lua/mason-core/installer/compiler/compilers/golang.lua
index 896d9bf9..01807088 100644
--- a/lua/mason-core/installer/registry/providers/golang.lua
+++ b/lua/mason-core/installer/compiler/compilers/golang.lua
@@ -1,7 +1,7 @@
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local providers = require "mason-core.providers"
-local util = require "mason-core.installer.registry.util"
+local util = require "mason-core.installer.compiler.util"
local M = {}
diff --git a/lua/mason-core/installer/registry/providers/luarocks.lua b/lua/mason-core/installer/compiler/compilers/luarocks.lua
index 356857c0..356857c0 100644
--- a/lua/mason-core/installer/registry/providers/luarocks.lua
+++ b/lua/mason-core/installer/compiler/compilers/luarocks.lua
diff --git a/lua/mason-core/installer/registry/providers/mason.lua b/lua/mason-core/installer/compiler/compilers/mason.lua
index 3490ebaa..3490ebaa 100644
--- a/lua/mason-core/installer/registry/providers/mason.lua
+++ b/lua/mason-core/installer/compiler/compilers/mason.lua
diff --git a/lua/mason-core/installer/registry/providers/npm.lua b/lua/mason-core/installer/compiler/compilers/npm.lua
index e8489fe8..e8489fe8 100644
--- a/lua/mason-core/installer/registry/providers/npm.lua
+++ b/lua/mason-core/installer/compiler/compilers/npm.lua
diff --git a/lua/mason-core/installer/registry/providers/nuget.lua b/lua/mason-core/installer/compiler/compilers/nuget.lua
index 370c7b95..370c7b95 100644
--- a/lua/mason-core/installer/registry/providers/nuget.lua
+++ b/lua/mason-core/installer/compiler/compilers/nuget.lua
diff --git a/lua/mason-core/installer/registry/providers/opam.lua b/lua/mason-core/installer/compiler/compilers/opam.lua
index 276686ae..276686ae 100644
--- a/lua/mason-core/installer/registry/providers/opam.lua
+++ b/lua/mason-core/installer/compiler/compilers/opam.lua
diff --git a/lua/mason-core/installer/registry/providers/openvsx.lua b/lua/mason-core/installer/compiler/compilers/openvsx.lua
index df52807a..bf31e2f9 100644
--- a/lua/mason-core/installer/registry/providers/openvsx.lua
+++ b/lua/mason-core/installer/compiler/compilers/openvsx.lua
@@ -1,16 +1,17 @@
local Result = require "mason-core.result"
local common = require "mason-core.installer.managers.common"
-local expr = require "mason-core.installer.registry.expr"
+local expr = require "mason-core.installer.compiler.expr"
local providers = require "mason-core.providers"
-local util = require "mason-core.installer.registry.util"
+local util = require "mason-core.installer.compiler.util"
local M = {}
---@class OpenVSXSourceDownload : FileDownloadSpec
+---@field target? Platform | Platform[]
---@field target_platform? string
---@class OpenVSXSource : RegistryPackageSource
----@field download FileDownloadSpec | FileDownloadSpec[]
+---@field download OpenVSXSourceDownload | OpenVSXSourceDownload[]
---@param source OpenVSXSource
---@param purl Purl
diff --git a/lua/mason-core/installer/registry/providers/pypi.lua b/lua/mason-core/installer/compiler/compilers/pypi.lua
index 3fe6f89e..c44fcfe1 100644
--- a/lua/mason-core/installer/registry/providers/pypi.lua
+++ b/lua/mason-core/installer/compiler/compilers/pypi.lua
@@ -2,7 +2,7 @@ local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local providers = require "mason-core.providers"
local settings = require "mason.settings"
-local util = require "mason-core.installer.registry.util"
+local util = require "mason-core.installer.compiler.util"
local M = {}
diff --git a/lua/mason-core/installer/registry/expr.lua b/lua/mason-core/installer/compiler/expr.lua
index a07fc00d..a07fc00d 100644
--- a/lua/mason-core/installer/registry/expr.lua
+++ b/lua/mason-core/installer/compiler/expr.lua
diff --git a/lua/mason-core/installer/registry/init.lua b/lua/mason-core/installer/compiler/init.lua
index 7376db86..e1df6784 100644
--- a/lua/mason-core/installer/registry/init.lua
+++ b/lua/mason-core/installer/compiler/init.lua
@@ -3,10 +3,10 @@ local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local a = require "mason-core.async"
-local link = require "mason-core.installer.registry.link"
+local link = require "mason-core.installer.compiler.link"
local log = require "mason-core.log"
-local schemas = require "mason-core.installer.registry.schemas"
-local util = require "mason-core.installer.registry.util"
+local schemas = require "mason-core.installer.compiler.schemas"
+local util = require "mason-core.installer.compiler.util"
local M = {}
@@ -15,35 +15,37 @@ M.SCHEMA_CAP = _.set_of {
"registry+v1",
}
----@type table<string, InstallerProvider>
-local PROVIDERS = {}
+---@type table<string, InstallerCompiler>
+local COMPILERS = {}
---@param id string
----@param provider InstallerProvider
-function M.register_provider(id, provider)
- PROVIDERS[id] = provider
+---@param compiler InstallerCompiler
+function M.register_compiler(id, compiler)
+ COMPILERS[id] = compiler
end
-M.register_provider("cargo", _.lazy_require "mason-core.installer.registry.providers.cargo")
-M.register_provider("composer", _.lazy_require "mason-core.installer.registry.providers.composer")
-M.register_provider("gem", _.lazy_require "mason-core.installer.registry.providers.gem")
-M.register_provider("generic", _.lazy_require "mason-core.installer.registry.providers.generic")
-M.register_provider("github", _.lazy_require "mason-core.installer.registry.providers.github")
-M.register_provider("golang", _.lazy_require "mason-core.installer.registry.providers.golang")
-M.register_provider("luarocks", _.lazy_require "mason-core.installer.registry.providers.luarocks")
-M.register_provider("npm", _.lazy_require "mason-core.installer.registry.providers.npm")
-M.register_provider("nuget", _.lazy_require "mason-core.installer.registry.providers.nuget")
-M.register_provider("opam", _.lazy_require "mason-core.installer.registry.providers.opam")
-M.register_provider("openvsx", _.lazy_require "mason-core.installer.registry.providers.openvsx")
-M.register_provider("pypi", _.lazy_require "mason-core.installer.registry.providers.pypi")
-M.register_provider("mason", _.lazy_require "mason-core.installer.registry.providers.mason")
+M.register_compiler("cargo", _.lazy_require "mason-core.installer.compiler.compilers.cargo")
+M.register_compiler("composer", _.lazy_require "mason-core.installer.compiler.compilers.composer")
+M.register_compiler("gem", _.lazy_require "mason-core.installer.compiler.compilers.gem")
+M.register_compiler("generic", _.lazy_require "mason-core.installer.compiler.compilers.generic")
+M.register_compiler("github", _.lazy_require "mason-core.installer.compiler.compilers.github")
+M.register_compiler("golang", _.lazy_require "mason-core.installer.compiler.compilers.golang")
+M.register_compiler("luarocks", _.lazy_require "mason-core.installer.compiler.compilers.luarocks")
+M.register_compiler("mason", _.lazy_require "mason-core.installer.compiler.compilers.mason")
+M.register_compiler("npm", _.lazy_require "mason-core.installer.compiler.compilers.npm")
+M.register_compiler("nuget", _.lazy_require "mason-core.installer.compiler.compilers.nuget")
+M.register_compiler("opam", _.lazy_require "mason-core.installer.compiler.compilers.opam")
+M.register_compiler("openvsx", _.lazy_require "mason-core.installer.compiler.compilers.openvsx")
+M.register_compiler("pypi", _.lazy_require "mason-core.installer.compiler.compilers.pypi")
---@param purl Purl
-function M.get_provider(purl)
- return Optional.of_nilable(PROVIDERS[purl.type]):ok_or(("Unknown purl type: %s"):format(purl.type))
+---@return Result # Result<InstallerCompiler>
+function M.get_compiler(purl)
+ return Optional.of_nilable(COMPILERS[purl.type])
+ :ok_or(("Current version of mason.nvim is not capable of parsing package type %q."):format(purl.type))
end
----@class InstallerProvider
+---@class InstallerCompiler
---@field parse fun(source: RegistryPackageSource, purl: Purl, opts: PackageInstallOpts): Result
---@field install async fun(ctx: InstallContext, source: ParsedPackageSource, purl: Purl): Result
---@field get_versions async fun(purl: Purl, source: RegistryPackageSource): Result # Result<string[]>
@@ -128,13 +130,13 @@ function M.parse(spec, opts)
purl.version = opts.version
end
- ---@type InstallerProvider
- local provider = try(M.get_provider(purl))
- log.trace("Found provider for purl.", source.id)
- local parsed_source = try(provider.parse(source, purl, opts))
+ ---@type InstallerCompiler
+ local compiler = try(M.get_compiler(purl))
+ log.trace("Found compiler for purl.", source.id)
+ local parsed_source = try(compiler.parse(source, purl, opts))
log.trace("Parsed source for purl.", source.id, parsed_source)
return {
- provider = provider,
+ compiler = compiler,
source = vim.tbl_extend("keep", parsed_source, source),
raw_source = source,
purl = purl,
@@ -167,7 +169,7 @@ function M.compile(spec, opts)
{ _.T, _.identity },
}
- ---@type { purl: Purl, provider: InstallerProvider, source: ParsedPackageSource, raw_source: RegistryPackageSource }
+ ---@type { purl: Purl, compiler: InstallerCompiler, source: ParsedPackageSource, raw_source: RegistryPackageSource }
local parsed = try(M.parse(spec, opts):map_err(map_parse_err))
---@async
@@ -176,13 +178,13 @@ function M.compile(spec, opts)
return Result.try(function(try)
if ctx.opts.version then
try(util.ensure_valid_version(function()
- return parsed.provider.get_versions(parsed.purl, parsed.raw_source)
+ return parsed.compiler.get_versions(parsed.purl, parsed.raw_source)
end))
end
-- Run installer
a.scheduler()
- try(parsed.provider.install(ctx, parsed.source, parsed.purl))
+ try(parsed.compiler.install(ctx, parsed.source, parsed.purl))
if spec.schemas then
local result = schemas.download(ctx, spec, parsed.purl, parsed.source):on_failure(function(err)
diff --git a/lua/mason-core/installer/registry/link.lua b/lua/mason-core/installer/compiler/link.lua
index 85e751b7..5d136322 100644
--- a/lua/mason-core/installer/registry/link.lua
+++ b/lua/mason-core/installer/compiler/link.lua
@@ -2,7 +2,7 @@ local Optional = require "mason-core.optional"
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local a = require "mason-core.async"
-local expr = require "mason-core.installer.registry.expr"
+local expr = require "mason-core.installer.compiler.expr"
local fs = require "mason-core.fs"
local log = require "mason-core.log"
local path = require "mason-core.path"
diff --git a/lua/mason-core/installer/registry/schemas.lua b/lua/mason-core/installer/compiler/schemas.lua
index f9d044af..5e578dbd 100644
--- a/lua/mason-core/installer/registry/schemas.lua
+++ b/lua/mason-core/installer/compiler/schemas.lua
@@ -1,7 +1,7 @@
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local a = require "mason-core.async"
-local expr = require "mason-core.installer.registry.expr"
+local expr = require "mason-core.installer.compiler.expr"
local fetch = require "mason-core.fetch"
local log = require "mason-core.log"
local path = require "mason-core.path"
diff --git a/lua/mason-core/installer/registry/util.lua b/lua/mason-core/installer/compiler/util.lua
index b3735c9c..b3735c9c 100644
--- a/lua/mason-core/installer/registry/util.lua
+++ b/lua/mason-core/installer/compiler/util.lua
diff --git a/lua/mason-core/installer/context/cwd.lua b/lua/mason-core/installer/context/cwd.lua
new file mode 100644
index 00000000..4f645fbb
--- /dev/null
+++ b/lua/mason-core/installer/context/cwd.lua
@@ -0,0 +1,48 @@
+local Result = require "mason-core.result"
+local fs = require "mason-core.fs"
+local path = require "mason-core.path"
+
+---@class InstallContextCwd
+---@field private location InstallLocation Defines the upper boundary for which paths are allowed as cwd.
+---@field private cwd string?
+local InstallContextCwd = {}
+InstallContextCwd.__index = InstallContextCwd
+
+---@param location InstallLocation
+function InstallContextCwd.new(location)
+ assert(location, "location not provided")
+ return setmetatable({
+ location = location,
+ cwd = nil,
+ }, InstallContextCwd)
+end
+
+---@param handle InstallHandle
+function InstallContextCwd:initialize(handle)
+ return Result.try(function(try)
+ local staging_dir = self.location:staging(handle.package.name)
+ if fs.async.dir_exists(staging_dir) then
+ try(Result.pcall(fs.async.rmrf, staging_dir))
+ end
+ try(Result.pcall(fs.async.mkdirp, staging_dir))
+ self:set(staging_dir)
+ end)
+end
+
+function InstallContextCwd:get()
+ assert(self.cwd ~= nil, "Tried to access cwd before it was set.")
+ return self.cwd
+end
+
+---@param new_abs_cwd string
+function InstallContextCwd:set(new_abs_cwd)
+ assert(type(new_abs_cwd) == "string", "new_cwd is not a string")
+ assert(
+ path.is_subdirectory(self.location:get_dir(), new_abs_cwd),
+ ("%q is not a subdirectory of %q"):format(new_abs_cwd, self.location)
+ )
+ self.cwd = new_abs_cwd
+ return self
+end
+
+return InstallContextCwd
diff --git a/lua/mason-core/installer/context/fs.lua b/lua/mason-core/installer/context/fs.lua
new file mode 100644
index 00000000..5c51fb56
--- /dev/null
+++ b/lua/mason-core/installer/context/fs.lua
@@ -0,0 +1,108 @@
+local fs = require "mason-core.fs"
+local log = require "mason-core.log"
+local path = require "mason-core.path"
+
+---@class InstallContextFs
+---@field private cwd InstallContextCwd
+local InstallContextFs = {}
+InstallContextFs.__index = InstallContextFs
+
+---@param cwd InstallContextCwd
+function InstallContextFs.new(cwd)
+ return setmetatable({ cwd = cwd }, InstallContextFs)
+end
+
+---@async
+---@param rel_path string The relative path from the current working directory to the file to append.
+---@param contents string
+function InstallContextFs:append_file(rel_path, contents)
+ return fs.async.append_file(path.concat { self.cwd:get(), rel_path }, contents)
+end
+
+---@async
+---@param rel_path string The relative path from the current working directory to the file to write.
+---@param contents string
+function InstallContextFs:write_file(rel_path, contents)
+ return fs.async.write_file(path.concat { self.cwd:get(), rel_path }, contents)
+end
+
+---@async
+---@param rel_path string The relative path from the current working directory to the file to read.
+function InstallContextFs:read_file(rel_path)
+ return fs.async.read_file(path.concat { self.cwd:get(), rel_path })
+end
+
+---@async
+---@param rel_path string The relative path from the current working directory.
+function InstallContextFs:file_exists(rel_path)
+ return fs.async.file_exists(path.concat { self.cwd:get(), rel_path })
+end
+
+---@async
+---@param rel_path string The relative path from the current working directory.
+function InstallContextFs:dir_exists(rel_path)
+ return fs.async.dir_exists(path.concat { self.cwd:get(), rel_path })
+end
+
+---@async
+---@param rel_path string The relative path from the current working directory.
+function InstallContextFs:rmrf(rel_path)
+ return fs.async.rmrf(path.concat { self.cwd:get(), rel_path })
+end
+
+---@async
+---@param rel_path string The relative path from the current working directory.
+function InstallContextFs:unlink(rel_path)
+ return fs.async.unlink(path.concat { self.cwd:get(), rel_path })
+end
+
+---@async
+---@param old_path string
+---@param new_path string
+function InstallContextFs:rename(old_path, new_path)
+ return fs.async.rename(path.concat { self.cwd:get(), old_path }, path.concat { self.cwd:get(), new_path })
+end
+
+---@async
+---@param dir_path string
+function InstallContextFs:mkdir(dir_path)
+ return fs.async.mkdir(path.concat { self.cwd:get(), dir_path })
+end
+
+---@async
+---@param dir_path string
+function InstallContextFs:mkdirp(dir_path)
+ return fs.async.mkdirp(path.concat { self.cwd:get(), dir_path })
+end
+
+---@async
+---@param file_path string
+function InstallContextFs:chmod_exec(file_path)
+ local bit = require "bit"
+ -- see chmod(2)
+ local USR_EXEC = 0x40
+ local GRP_EXEC = 0x8
+ local ALL_EXEC = 0x1
+ local EXEC = bit.bor(USR_EXEC, GRP_EXEC, ALL_EXEC)
+ local fstat = self:fstat(file_path)
+ if bit.band(fstat.mode, EXEC) ~= EXEC then
+ local plus_exec = bit.bor(fstat.mode, EXEC)
+ log.fmt_debug("Setting exec flags on file %s %o -> %o", file_path, fstat.mode, plus_exec)
+ self:chmod(file_path, plus_exec) -- chmod +x
+ end
+end
+
+---@async
+---@param file_path string
+---@param mode integer
+function InstallContextFs:chmod(file_path, mode)
+ return fs.async.chmod(path.concat { self.cwd:get(), file_path }, mode)
+end
+
+---@async
+---@param file_path string
+function InstallContextFs:fstat(file_path)
+ return fs.async.fstat(path.concat { self.cwd:get(), file_path })
+end
+
+return InstallContextFs
diff --git a/lua/mason-core/installer/context.lua b/lua/mason-core/installer/context/init.lua
index a991cd9f..0d178c4e 100644
--- a/lua/mason-core/installer/context.lua
+++ b/lua/mason-core/installer/context/init.lua
@@ -1,213 +1,37 @@
-local Optional = require "mason-core.optional"
+local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local fs = require "mason-core.fs"
local log = require "mason-core.log"
local path = require "mason-core.path"
local platform = require "mason-core.platform"
local receipt = require "mason-core.receipt"
-local spawn = require "mason-core.spawn"
-
----@class ContextualSpawn
----@field strict_mode boolean Whether spawn failures should raise an exception rather then return a Result.
----@field cwd CwdManager
----@field handle InstallHandle
----@field [string] async fun(opts: SpawnArgs): Result
-local ContextualSpawn = {}
-
----@param cwd CwdManager
----@param handle InstallHandle
----@param strict_mode boolean
-function ContextualSpawn.new(cwd, handle, strict_mode)
- return setmetatable({ cwd = cwd, handle = handle, strict_mode = strict_mode }, ContextualSpawn)
-end
-
----@param cmd string
-function ContextualSpawn:__index(cmd)
- ---@param args JobSpawnOpts
- return function(args)
- args.cwd = args.cwd or self.cwd:get()
- args.stdio_sink = args.stdio_sink or self.handle.stdio.sink
- local on_spawn = args.on_spawn
- local captured_handle
- args.on_spawn = function(handle, stdio, pid, ...)
- captured_handle = handle
- self.handle:register_spawn_handle(handle, pid, cmd, spawn._flatten_cmd_args(args))
- if on_spawn then
- on_spawn(handle, stdio, pid, ...)
- end
- end
- local function pop_spawn_stack()
- if captured_handle then
- self.handle:deregister_spawn_handle(captured_handle)
- end
- end
- local result = spawn[cmd](args):on_success(pop_spawn_stack):on_failure(pop_spawn_stack)
- if self.strict_mode then
- return result:get_or_throw()
- else
- return result
- end
- end
-end
-
----@class ContextualFs
----@field private cwd CwdManager
-local ContextualFs = {}
-ContextualFs.__index = ContextualFs
-
----@param cwd CwdManager
-function ContextualFs.new(cwd)
- return setmetatable({ cwd = cwd }, ContextualFs)
-end
-
----@async
----@param rel_path string The relative path from the current working directory to the file to append.
----@param contents string
-function ContextualFs:append_file(rel_path, contents)
- return fs.async.append_file(path.concat { self.cwd:get(), rel_path }, contents)
-end
-
----@async
----@param rel_path string The relative path from the current working directory to the file to write.
----@param contents string
-function ContextualFs:write_file(rel_path, contents)
- return fs.async.write_file(path.concat { self.cwd:get(), rel_path }, contents)
-end
-
----@async
----@param rel_path string The relative path from the current working directory to the file to read.
-function ContextualFs:read_file(rel_path)
- return fs.async.read_file(path.concat { self.cwd:get(), rel_path })
-end
-
----@async
----@param rel_path string The relative path from the current working directory.
-function ContextualFs:file_exists(rel_path)
- return fs.async.file_exists(path.concat { self.cwd:get(), rel_path })
-end
-
----@async
----@param rel_path string The relative path from the current working directory.
-function ContextualFs:dir_exists(rel_path)
- return fs.async.dir_exists(path.concat { self.cwd:get(), rel_path })
-end
-
----@async
----@param rel_path string The relative path from the current working directory.
-function ContextualFs:rmrf(rel_path)
- return fs.async.rmrf(path.concat { self.cwd:get(), rel_path })
-end
-
----@async
----@param rel_path string The relative path from the current working directory.
-function ContextualFs:unlink(rel_path)
- return fs.async.unlink(path.concat { self.cwd:get(), rel_path })
-end
-
----@async
----@param old_path string
----@param new_path string
-function ContextualFs:rename(old_path, new_path)
- return fs.async.rename(path.concat { self.cwd:get(), old_path }, path.concat { self.cwd:get(), new_path })
-end
-
----@async
----@param dir_path string
-function ContextualFs:mkdir(dir_path)
- return fs.async.mkdir(path.concat { self.cwd:get(), dir_path })
-end
-
----@async
----@param dir_path string
-function ContextualFs:mkdirp(dir_path)
- return fs.async.mkdirp(path.concat { self.cwd:get(), dir_path })
-end
-
----@async
----@param file_path string
-function ContextualFs:chmod_exec(file_path)
- local bit = require "bit"
- -- see chmod(2)
- local USR_EXEC = 0x40
- local GRP_EXEC = 0x8
- local ALL_EXEC = 0x1
- local EXEC = bit.bor(USR_EXEC, GRP_EXEC, ALL_EXEC)
- local fstat = self:fstat(file_path)
- if bit.band(fstat.mode, EXEC) ~= EXEC then
- local plus_exec = bit.bor(fstat.mode, EXEC)
- log.fmt_debug("Setting exec flags on file %s %o -> %o", file_path, fstat.mode, plus_exec)
- self:chmod(file_path, plus_exec) -- chmod +x
- end
-end
-
----@async
----@param file_path string
----@param mode integer
-function ContextualFs:chmod(file_path, mode)
- return fs.async.chmod(path.concat { self.cwd:get(), file_path }, mode)
-end
-
----@async
----@param file_path string
-function ContextualFs:fstat(file_path)
- return fs.async.fstat(path.concat { self.cwd:get(), file_path })
-end
-
----@class CwdManager
----@field private install_prefix string Defines the upper boundary for which paths are allowed as cwd.
----@field private cwd string
-local CwdManager = {}
-CwdManager.__index = CwdManager
-
-function CwdManager.new(install_prefix)
- assert(type(install_prefix) == "string", "install_prefix not provided")
- return setmetatable({
- install_prefix = install_prefix,
- cwd = nil,
- }, CwdManager)
-end
-
-function CwdManager:get()
- assert(self.cwd ~= nil, "Tried to access cwd before it was set.")
- return self.cwd
-end
-
----@param new_cwd string
-function CwdManager:set(new_cwd)
- assert(type(new_cwd) == "string", "new_cwd is not a string")
- assert(
- path.is_subdirectory(self.install_prefix, new_cwd),
- ("%q is not a subdirectory of %q"):format(new_cwd, self.install_prefix)
- )
- self.cwd = new_cwd
-end
---@class InstallContext
----@field public receipt InstallReceiptBuilder
----@field public requested_version Optional
----@field public fs ContextualFs
----@field public spawn ContextualSpawn
----@field public handle InstallHandle
----@field public package Package
----@field public cwd CwdManager
----@field public opts PackageInstallOpts
----@field public stdio_sink StdioSink
+---@field receipt InstallReceiptBuilder
+---@field fs InstallContextFs
+---@field spawn InstallContextSpawn
+---@field handle InstallHandle
+---@field package Package
+---@field cwd InstallContextCwd
+---@field opts PackageInstallOpts
+---@field stdio_sink StdioSink
---@field links { bin: table<string, string>, share: table<string, string>, opt: table<string, string> }
local InstallContext = {}
InstallContext.__index = InstallContext
---@param handle InstallHandle
+---@param cwd InstallContextCwd
+---@param spawn InstallContextSpawn
+---@param fs InstallContextFs
---@param opts PackageInstallOpts
-function InstallContext.new(handle, opts)
- local cwd_manager = CwdManager.new(path.install_prefix())
+function InstallContext.new(handle, cwd, spawn, fs, opts)
return setmetatable({
- cwd = cwd_manager,
- spawn = ContextualSpawn.new(cwd_manager, handle, false),
+ cwd = cwd,
+ spawn = spawn,
handle = handle,
package = handle.package, -- for convenience
- fs = ContextualFs.new(cwd_manager),
+ fs = fs,
receipt = receipt.InstallReceiptBuilder.new(),
- requested_version = Optional.of_nilable(opts.version),
stdio_sink = handle.stdio.sink,
links = {
bin = {},
@@ -227,8 +51,8 @@ function InstallContext:promote_cwd()
return
end
log.fmt_debug("Promoting cwd %s to %s", cwd, install_path)
- -- 1. Unlink any existing installation
- self.handle.package:unlink()
+ -- 1. Uninstall any existing installation
+ self.handle.package:uninstall()
-- 2. Prepare for renaming cwd to destination
if platform.is.unix then
-- Some Unix systems will raise an error when renaming a directory to a destination that does not already exist.
@@ -396,4 +220,42 @@ function InstallContext:link_bin(executable, rel_path)
return self
end
+InstallContext.CONTEXT_REQUEST = {}
+
+---@generic T
+---@param fn fun(context: InstallContext): T
+---@return T
+function InstallContext:execute(fn)
+ local thread = coroutine.create(function(...)
+ -- We wrap the function to allow it to be a spy instance (in which case it's not actually a function, but a
+ -- callable metatable - coroutine.create strictly expects functions only)
+ return fn(...)
+ end)
+ local step
+ local ret_val
+ step = function(...)
+ local ok, result = coroutine.resume(thread, ...)
+ if not ok then
+ error(result, 0)
+ elseif result == InstallContext.CONTEXT_REQUEST then
+ step(self)
+ elseif coroutine.status(thread) == "suspended" then
+ -- yield to parent coroutine
+ step(coroutine.yield(result))
+ else
+ ret_val = result
+ end
+ end
+ step(self)
+ return ret_val
+end
+
+---@async
+function InstallContext:build_receipt()
+ log.fmt_debug("Building receipt for %s", self.package)
+ return Result.pcall(function()
+ return self.receipt:with_name(self.package.name):with_completion_time(vim.loop.gettimeofday()):build()
+ end)
+end
+
return InstallContext
diff --git a/lua/mason-core/installer/context/spawn.lua b/lua/mason-core/installer/context/spawn.lua
new file mode 100644
index 00000000..6528c4b3
--- /dev/null
+++ b/lua/mason-core/installer/context/spawn.lua
@@ -0,0 +1,46 @@
+local spawn = require "mason-core.spawn"
+
+---@class InstallContextSpawn
+---@field strict_mode boolean Whether spawn failures should raise an exception rather then return a Result.
+---@field private cwd InstallContextCwd
+---@field private handle InstallHandle
+---@field [string] async fun(opts: SpawnArgs): Result
+local InstallContextSpawn = {}
+
+---@param cwd InstallContextCwd
+---@param handle InstallHandle
+---@param strict_mode boolean
+function InstallContextSpawn.new(cwd, handle, strict_mode)
+ return setmetatable({ cwd = cwd, handle = handle, strict_mode = strict_mode }, InstallContextSpawn)
+end
+
+---@param cmd string
+function InstallContextSpawn:__index(cmd)
+ ---@param args JobSpawnOpts
+ return function(args)
+ args.cwd = args.cwd or self.cwd:get()
+ args.stdio_sink = args.stdio_sink or self.handle.stdio.sink
+ local on_spawn = args.on_spawn
+ local captured_handle
+ args.on_spawn = function(handle, stdio, pid, ...)
+ captured_handle = handle
+ self.handle:register_spawn_handle(handle, pid, cmd, spawn._flatten_cmd_args(args))
+ if on_spawn then
+ on_spawn(handle, stdio, pid, ...)
+ end
+ end
+ local function pop_spawn_stack()
+ if captured_handle then
+ self.handle:deregister_spawn_handle(captured_handle)
+ end
+ end
+ local result = spawn[cmd](args):on_success(pop_spawn_stack):on_failure(pop_spawn_stack)
+ if self.strict_mode then
+ return result:get_or_throw()
+ else
+ return result
+ end
+ end
+end
+
+return InstallContextSpawn
diff --git a/lua/mason-core/installer/handle.lua b/lua/mason-core/installer/handle.lua
index f9b03557..96acbdd1 100644
--- a/lua/mason-core/installer/handle.lua
+++ b/lua/mason-core/installer/handle.lua
@@ -120,6 +120,10 @@ function InstallHandle:is_closed()
return self.state == "CLOSED"
end
+function InstallHandle:is_closing()
+ return self:is_closed() or self.is_terminated
+end
+
---@param new_state InstallHandleState
function InstallHandle:set_state(new_state)
local old_state = self.state
diff --git a/lua/mason-core/installer/init.lua b/lua/mason-core/installer/init.lua
index 45bba46b..37c74fcb 100644
--- a/lua/mason-core/installer/init.lua
+++ b/lua/mason-core/installer/init.lua
@@ -1,263 +1,10 @@
local InstallContext = require "mason-core.installer.context"
-local Result = require "mason-core.result"
-local _ = require "mason-core.functional"
-local a = require "mason-core.async"
-local control = require "mason-core.async.control"
-local fs = require "mason-core.fs"
-local linker = require "mason-core.installer.linker"
-local log = require "mason-core.log"
-local path = require "mason-core.path"
-local settings = require "mason.settings"
-
-local Semaphore = control.Semaphore
-
-local sem = Semaphore.new(settings.current.max_concurrent_installers)
local M = {}
----@async
-function M.create_prefix_dirs()
- return Result.try(function(try)
- for _, p in ipairs {
- path.install_prefix(),
- path.bin_prefix(),
- path.share_prefix(),
- path.package_prefix(),
- path.package_build_prefix(),
- } do
- if not fs.async.dir_exists(p) then
- try(Result.pcall(fs.async.mkdirp, p))
- end
- end
- end)
-end
-
----@async
----@param context InstallContext
-local function build_receipt(context)
- return Result.pcall(function()
- log.fmt_debug("Building receipt for %s", context.package)
- return context.receipt:with_name(context.package.name):with_completion_time(vim.loop.gettimeofday()):build()
- end)
-end
-
-local CONTEXT_REQUEST = {}
-
---@return InstallContext
function M.context()
- return coroutine.yield(CONTEXT_REQUEST)
-end
-
----@async
----@param ctx InstallContext
-local function lock_package(ctx)
- log.debug("Attempting to lock package", ctx.package)
- local lockfile = path.package_lock(ctx.package.name)
- if not ctx.opts.force and fs.async.file_exists(lockfile) then
- log.error("Lockfile already exists.", ctx.package)
- return Result.failure(
- ("Lockfile exists, installation is already running in another process (pid: %s). Run with :MasonInstall --force to bypass."):format(
- fs.sync.read_file(lockfile)
- )
- )
- end
- a.scheduler()
- fs.async.write_file(lockfile, vim.fn.getpid())
- log.debug("Wrote lockfile", ctx.package)
- return Result.success(lockfile)
-end
-
----@async
----@param context InstallContext
-function M.prepare_installer(context)
- local installer = require "mason-core.installer.registry"
- return Result.try(function(try)
- local package_build_prefix = path.package_build_prefix(context.package.name)
- if fs.async.dir_exists(package_build_prefix) then
- try(Result.pcall(fs.async.rmrf, package_build_prefix))
- end
- try(Result.pcall(fs.async.mkdirp, package_build_prefix))
- context.cwd:set(package_build_prefix)
-
- return try(installer.compile(context.handle.package.spec, context.opts))
- end)
-end
-
----@generic T
----@param context InstallContext
----@param fn fun(context: InstallContext): T
----@return T
-function M.exec_in_context(context, fn)
- local thread = coroutine.create(function(...)
- -- We wrap the function to allow it to be a spy instance (in which case it's not actually a function, but a
- -- callable metatable - coroutine.create strictly expects functions only)
- return fn(...)
- end)
- local step
- local ret_val
- step = function(...)
- local ok, result = coroutine.resume(thread, ...)
- if not ok then
- error(result, 0)
- elseif result == CONTEXT_REQUEST then
- step(context)
- elseif coroutine.status(thread) == "suspended" then
- -- yield to parent coroutine
- step(coroutine.yield(result))
- else
- ret_val = result
- end
- end
- context.receipt:with_start_time(vim.loop.gettimeofday())
- step(context)
- return ret_val
-end
-
----@async
----@param context InstallContext
----@param installer async fun(ctx: InstallContext)
-local function run_installer(context, installer)
- local handle = context.handle
- return Result.pcall(function()
- return a.wait(function(resolve, reject)
- local cancel_thread = a.run(M.exec_in_context, function(success, result)
- if success then
- resolve(result)
- else
- reject(result)
- end
- end, context, installer)
-
- handle:once("terminate", function()
- cancel_thread()
- if handle:is_closed() then
- reject "Installation was aborted."
- else
- handle:once("closed", function()
- reject "Installation was aborted."
- end)
- end
- end)
- end)
- end)
-end
-
----@async
----@param handle InstallHandle
----@param opts PackageInstallOpts
-function M.execute(handle, opts)
- if handle:is_active() or handle:is_closed() then
- log.fmt_debug("Received active or closed handle %s", handle)
- return Result.failure "Invalid handle state."
- end
-
- handle:queued()
- local permit = sem:acquire()
- if handle:is_closed() then
- permit:forget()
- log.fmt_trace("Installation was aborted %s", handle)
- return Result.failure "Installation was aborted."
- end
- log.fmt_trace("Activating handle %s", handle)
- handle:active()
-
- local pkg = handle.package
- local context = InstallContext.new(handle, opts)
- local tailed_output = {}
-
- if opts.debug then
- local function append_log(chunk)
- tailed_output[#tailed_output + 1] = chunk
- end
- handle:on("stdout", append_log)
- handle:on("stderr", append_log)
- end
-
- log.fmt_info("Executing installer for %s %s", pkg, opts)
-
- return M.create_prefix_dirs()
- :and_then(function()
- return lock_package(context)
- end)
- :and_then(function(lockfile)
- local release_lock = _.partial(pcall, fs.async.unlink, lockfile)
- return Result.try(function(try)
- -- 1. prepare directories and initialize cwd
- local installer = try(M.prepare_installer(context))
-
- -- 2. execute installer
- try(run_installer(context, installer))
-
- -- 3. promote temporary installation dir
- try(Result.pcall(function()
- context:promote_cwd()
- end))
-
- -- 4. link package
- try(linker.link(context))
-
- -- 5. build & write receipt
- ---@type InstallReceipt
- local receipt = try(build_receipt(context))
- try(Result.pcall(function()
- receipt:write(context.cwd:get())
- end))
- end)
- :on_success(function()
- release_lock()
- if opts.debug then
- context.fs:write_file("mason-debug.log", table.concat(tailed_output, ""))
- end
- end)
- :on_failure(function()
- release_lock()
- if not opts.debug then
- -- clean up installation dir
- pcall(function()
- fs.async.rmrf(context.cwd:get())
- end)
- else
- context.fs:write_file("mason-debug.log", table.concat(tailed_output, ""))
- context.stdio_sink.stdout(
- ("[debug] Installation directory retained at %q.\n"):format(context.cwd:get())
- )
- end
-
- -- unlink linked executables (in the occasion an error occurs after linking)
- build_receipt(context):on_success(function(receipt)
- linker.unlink(context.package, receipt):on_failure(function(err)
- log.error("Failed to unlink failed installation", err)
- end)
- end)
- end)
- end)
- :on_success(function()
- permit:forget()
- handle:close()
- log.fmt_info("Installation succeeded for %s", pkg)
- end)
- :on_failure(function(failure)
- permit:forget()
- log.fmt_error("Installation failed for %s error=%s", pkg, failure)
- context.stdio_sink.stderr(tostring(failure))
- context.stdio_sink.stderr "\n"
-
- if not handle:is_closed() and not handle.is_terminated then
- handle:close()
- end
- end)
-end
-
----Runs the provided async functions concurrently and returns their result, once all are resolved.
----This is really just a wrapper around a.wait_all() that makes sure to patch the coroutine context before creating the
----new async execution contexts.
----@async
----@param suspend_fns async fun(ctx: InstallContext)[]
-function M.run_concurrently(suspend_fns)
- local context = M.context()
- return a.wait_all(_.map(function(suspend_fn)
- return _.partial(M.exec_in_context, context, suspend_fn)
- end, suspend_fns))
+ return coroutine.yield(InstallContext.CONTEXT_REQUEST)
end
return M
diff --git a/lua/mason-core/installer/location.lua b/lua/mason-core/installer/location.lua
new file mode 100644
index 00000000..2cc038e4
--- /dev/null
+++ b/lua/mason-core/installer/location.lua
@@ -0,0 +1,63 @@
+local Path = require "mason-core.path"
+local Result = require "mason-core.result"
+local fs = require "mason-core.fs"
+
+---@class InstallLocation
+---@field private dir string
+local InstallLocation = {}
+InstallLocation.__index = InstallLocation
+
+---@param dir string
+function InstallLocation.new(dir)
+ return setmetatable({
+ dir = dir,
+ }, InstallLocation)
+end
+
+function InstallLocation:get_dir()
+ return self.dir
+end
+
+---@async
+function InstallLocation:initialize()
+ return Result.try(function(try)
+ for _, p in ipairs {
+ self.dir,
+ self:bin(),
+ self:share(),
+ self:package(),
+ self:staging(),
+ } do
+ if not fs.async.dir_exists(p) then
+ try(Result.pcall(fs.async.mkdirp, p))
+ end
+ end
+ end)
+end
+
+---@param path string?
+function InstallLocation:bin(path)
+ return Path.concat { self.dir, "bin", path }
+end
+
+---@param path string?
+function InstallLocation:share(path)
+ return Path.concat { self.dir, "share", path }
+end
+
+---@param path string?
+function InstallLocation:package(path)
+ return Path.concat { self.dir, "packages", path }
+end
+
+---@param path string?
+function InstallLocation:staging(path)
+ return Path.concat { self.dir, "staging", path }
+end
+
+---@param name string
+function InstallLocation:lockfile(name)
+ return self:staging(("%s.lock"):format(name))
+end
+
+return InstallLocation
diff --git a/lua/mason-core/installer/runner.lua b/lua/mason-core/installer/runner.lua
new file mode 100644
index 00000000..175610d5
--- /dev/null
+++ b/lua/mason-core/installer/runner.lua
@@ -0,0 +1,218 @@
+local Result = require "mason-core.result"
+local _ = require "mason-core.functional"
+local a = require "mason-core.async"
+local compiler = require "mason-core.installer.compiler"
+local fs = require "mason-core.fs"
+local linker = require "mason-core.installer.linker"
+local log = require "mason-core.log"
+local registry = require "mason-registry"
+
+local InstallContext = require "mason-core.installer.context"
+local InstallContextCwd = require "mason-core.installer.context.cwd"
+local InstallContextFs = require "mason-core.installer.context.fs"
+local InstallContextSpawn = require "mason-core.installer.context.spawn"
+
+---@class InstallRunner
+---@field location InstallLocation
+---@field handle InstallHandle
+---@field semaphore Semaphore
+---@field permit Permit?
+local InstallRunner = {}
+InstallRunner.__index = InstallRunner
+
+---@param location InstallLocation
+---@param handle InstallHandle
+---@param semaphore Semaphore
+function InstallRunner.new(location, handle, semaphore)
+ return setmetatable({
+ location = location,
+ semaphore = semaphore,
+ handle = handle,
+ }, InstallRunner)
+end
+
+---@param opts PackageInstallOpts
+---@param callback? fun(success: boolean, result: any)
+function InstallRunner:execute(opts, callback)
+ local handle = self.handle
+ log.fmt_info("Executing installer for %s %s", handle.package, opts)
+
+ local context_cwd = InstallContextCwd.new(self.location)
+ local context_spawn = InstallContextSpawn.new(context_cwd, handle, false)
+ local context_fs = InstallContextFs.new(context_cwd)
+ local context = InstallContext.new(handle, context_cwd, context_spawn, context_fs, opts)
+
+ local tailed_output = {}
+
+ if opts.debug then
+ local function append_log(chunk)
+ tailed_output[#tailed_output + 1] = chunk
+ end
+ handle:on("stdout", append_log)
+ handle:on("stderr", append_log)
+ end
+
+ ---@async
+ local function finalize_logs(success, result)
+ if not success then
+ context.stdio_sink.stderr(tostring(result))
+ context.stdio_sink.stderr "\n"
+ end
+
+ if opts.debug then
+ context.fs:write_file("mason-debug.log", table.concat(tailed_output, ""))
+ context.stdio_sink.stdout(("[debug] Installation directory retained at %q.\n"):format(context.cwd:get()))
+ end
+ end
+
+ ---@async
+ local finalize = a.scope(function(success, result)
+ finalize_logs(success, result)
+
+ if not opts.debug and not success then
+ -- clean up installation dir
+ pcall(function()
+ fs.async.rmrf(context.cwd:get())
+ end)
+ end
+
+ if not handle:is_closing() then
+ handle:close()
+ end
+
+ self:release_lock()
+ self:release_permit()
+
+ if callback then
+ callback(success, result)
+ end
+
+ if success then
+ log.fmt_info("Installation succeeded for %s", handle.package)
+ handle.package:emit("install:success", handle)
+ registry:emit("package:install:success", handle.package, handle)
+ else
+ log.fmt_error("Installation failed for %s error=%s", handle.package, result)
+ handle.package:emit("install:failed", handle, result)
+ registry:emit("package:install:failed", handle.package, handle, result)
+ end
+ end)
+
+ local cancel_execution = a.run(function()
+ return Result.try(function(try)
+ try(self:acquire_permit())
+ try(self.location:initialize())
+ try(self:acquire_lock(opts.force))
+
+ context.receipt:with_start_time(vim.loop.gettimeofday())
+
+ -- 1. initialize working directory
+ try(context_cwd:initialize(handle))
+
+ -- 2. run installer
+ ---@type async fun(ctx: InstallContext): Result
+ local installer = try(compiler.compile(handle.package.spec, opts))
+ try(context:execute(installer))
+
+ -- 3. promote temporary installation dir
+ try(Result.pcall(function()
+ context:promote_cwd()
+ end))
+
+ -- 4. link package & write receipt
+ return linker
+ .link(context)
+ :and_then(function()
+ return context:build_receipt(context)
+ end)
+ :and_then(
+ ---@param receipt InstallReceipt
+ function(receipt)
+ return receipt:write(context.cwd:get())
+ end
+ )
+ :on_failure(function()
+ -- unlink any links that were made before failure
+ context:build_receipt():on_success(
+ ---@param receipt InstallReceipt
+ function(receipt)
+ linker.unlink(handle.package, receipt):on_failure(function(err)
+ log.error("Failed to unlink failed installation.", err)
+ end)
+ end
+ )
+ end)
+ end):get_or_throw()
+ end, finalize)
+
+ handle:once("terminate", function()
+ cancel_execution()
+ local function on_close()
+ finalize(false, "Installation was aborted.")
+ end
+ if handle:is_closed() then
+ on_close()
+ else
+ handle:once("closed", on_close)
+ end
+ end)
+end
+
+---@async
+---@private
+function InstallRunner:release_lock()
+ pcall(fs.async.unlink, self.location:lockfile(self.handle.package.name))
+end
+
+---@async
+---@param force boolean?
+---@private
+function InstallRunner:acquire_lock(force)
+ local pkg = self.handle.package
+ log.debug("Attempting to lock package", pkg)
+ local lockfile = self.location:lockfile(pkg.name)
+ if force ~= true and fs.async.file_exists(lockfile) then
+ log.error("Lockfile already exists.", pkg)
+ return Result.failure(
+ ("Lockfile exists, installation is already running in another process (pid: %s). Run with :MasonInstall --force to bypass."):format(
+ fs.async.read_file(lockfile)
+ )
+ )
+ end
+ a.scheduler()
+ fs.async.write_file(lockfile, vim.fn.getpid())
+ log.debug("Wrote lockfile", pkg)
+ return Result.success(lockfile)
+end
+
+---@async
+---@private
+function InstallRunner:acquire_permit()
+ local handle = self.handle
+ if handle:is_active() or handle:is_closed() then
+ log.fmt_debug("Received active or closed handle %s", handle)
+ return Result.failure "Invalid handle state."
+ end
+
+ handle:queued()
+ local permit = self.semaphore:acquire()
+ if handle:is_closed() then
+ permit:forget()
+ log.fmt_trace("Installation was aborted %s", handle)
+ return Result.failure "Installation was aborted."
+ end
+ log.fmt_trace("Activating handle %s", handle)
+ handle:active()
+ self.permit = permit
+ return Result.success()
+end
+
+---@private
+function InstallRunner:release_permit()
+ if self.permit then
+ self.permit:forget()
+ self.permit = nil
+ end
+end
+
+return InstallRunner
diff --git a/lua/mason-core/package/init.lua b/lua/mason-core/package/init.lua
index bc98a72a..b0da8a61 100644
--- a/lua/mason-core/package/init.lua
+++ b/lua/mason-core/package/init.lua
@@ -1,14 +1,17 @@
local EventEmitter = require "mason-core.EventEmitter"
+local InstallLocation = require "mason-core.installer.location"
+local InstallRunner = require "mason-core.installer.runner"
local Optional = require "mason-core.optional"
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
-local a = require "mason-core.async"
local fs = require "mason-core.fs"
local log = require "mason-core.log"
local path = require "mason-core.path"
local platform = require "mason-core.platform"
local registry = require "mason-registry"
+local settings = require "mason.settings"
+local Semaphore = require("mason-core.async.control").Semaphore
---@class Package : EventEmitter
---@field name string
@@ -135,81 +138,56 @@ end
---@alias PackageInstallOpts { version?: string, debug?: boolean, target?: string, force?: boolean, strict?: boolean }
----@param opts? PackageInstallOpts
----@return InstallHandle
-function Package:install(opts)
- opts = opts or {}
+-- TODO this needs to be elsewhere
+local semaphore = Semaphore.new(settings.current.max_concurrent_installers)
+
+function Package:is_installing()
return self:get_handle()
- :map(function(handle)
- if not handle:is_closed() then
- log.fmt_debug("Handle %s already exist for package %s", handle, self)
- return handle
+ :map(
+ ---@param handle InstallHandle
+ function(handle)
+ return not handle:is_closed()
end
- end)
- :or_else_get(function()
- local handle = self:new_handle()
- a.run(
- require("mason-core.installer").execute,
- ---@param success boolean
- ---@param result Result
- function(success, result)
- if not success then
- -- Installer failed abnormally (i.e. unexpected exception in the installer code itself).
- log.error("Unexpected error", result)
- handle.stdio.sink.stderr(tostring(result))
- handle.stdio.sink.stderr "\nInstallation failed abnormally. Please report this error."
- self:emit("install:failed", handle)
- registry:emit("package:install:failed", self, handle)
+ )
+ :or_else(false)
+end
- -- We terminate _after_ emitting failure events because [termination -> failed] have different
- -- meaning than [failed -> terminate] ([termination -> failed] is interpreted as a triggered
- -- termination).
- if not handle:is_closed() and not handle.is_terminated then
- handle:terminate()
- end
- return
- end
- result
- :on_success(function()
- self:emit("install:success", handle)
- registry:emit("package:install:success", self, handle)
- end)
- :on_failure(function()
- self:emit("install:failed", handle)
- registry:emit("package:install:failed", self, handle)
- end)
- end,
- handle,
- opts
- )
- return handle
- end)
+---@param opts? PackageInstallOpts
+---@param callback? fun(success: boolean, result: any)
+---@return InstallHandle
+function Package:install(opts, callback)
+ opts = opts or {}
+ assert(not self:is_installing(), "Package is already installing.")
+ local handle = self:new_handle()
+ local runner = InstallRunner.new(InstallLocation.new(settings.current.install_root_dir), handle, semaphore)
+ runner:execute(opts, callback)
+ return handle
end
+---@return boolean
function Package:uninstall()
- local was_unlinked = self:unlink()
- if was_unlinked then
- self:emit "uninstall:success"
- registry:emit("package:uninstall:success", self)
- end
- return was_unlinked
+ return self:get_receipt()
+ :map(function(receipt)
+ self:unlink(receipt)
+ self:emit("uninstall:success", receipt)
+ registry:emit("package:uninstall:success", self, receipt)
+ return true
+ end)
+ :or_else(false)
end
-function Package:unlink()
+---@private
+---@param receipt InstallReceipt
+function Package:unlink(receipt)
log.fmt_trace("Unlinking %s", self)
local install_path = self:get_install_path()
+
-- 1. Unlink
- self:get_receipt():if_present(function(receipt)
- local linker = require "mason-core.installer.linker"
- linker.unlink(self, receipt):get_or_throw()
- end)
+ local linker = require "mason-core.installer.linker"
+ linker.unlink(self, receipt):get_or_throw()
-- 2. Remove installation artifacts
- if fs.sync.dir_exists(install_path) then
- fs.sync.rmrf(install_path)
- return true
- end
- return false
+ fs.sync.rmrf(install_path)
end
function Package:is_installed()
@@ -260,18 +238,18 @@ end
---@param opts? PackageInstallOpts
function Package:is_installable(opts)
- return require("mason-core.installer.registry").parse(self.spec, opts or {}):is_success()
+ return require("mason-core.installer.compiler").parse(self.spec, opts or {}):is_success()
end
---@return Result # Result<string[]>
function Package:get_all_versions()
- local registry_installer = require "mason-core.installer.registry"
+ local compiler = require "mason-core.installer.compiler"
return Result.try(function(try)
---@type Purl
local purl = try(Purl.parse(self.spec.source.id))
- ---@type InstallerProvider
- local provider = try(registry_installer.get_provider(purl))
- return provider.get_versions(purl, self.spec.source)
+ ---@type InstallerCompiler
+ local compiler = try(compiler.get_compiler(purl))
+ return compiler.get_versions(purl, self.spec.source)
end)
end
diff --git a/lua/mason-core/receipt.lua b/lua/mason-core/receipt.lua
index d9fe9d88..748cab38 100644
--- a/lua/mason-core/receipt.lua
+++ b/lua/mason-core/receipt.lua
@@ -1,3 +1,7 @@
+local Result = require "mason-core.result"
+local fs = require "mason-core.fs"
+local path = require "mason-core.path"
+
local M = {}
---@alias InstallReceiptSchemaVersion
@@ -56,11 +60,11 @@ function InstallReceipt:get_links()
end
---@async
----@param cwd string
-function InstallReceipt:write(cwd)
- local path = require "mason-core.path"
- local fs = require "mason-core.fs"
- fs.async.write_file(path.concat { cwd, "mason-receipt.json" }, vim.json.encode(self))
+---@param dir string
+function InstallReceipt:write(dir)
+ return Result.pcall(function()
+ fs.async.write_file(path.concat { dir, "mason-receipt.json" }, vim.json.encode(self))
+ end)
end
---@class InstallReceiptBuilder
diff --git a/lua/mason-registry/sources/util.lua b/lua/mason-registry/sources/util.lua
index 80d5f16f..04ab7845 100644
--- a/lua/mason-registry/sources/util.lua
+++ b/lua/mason-registry/sources/util.lua
@@ -1,8 +1,8 @@
local Optional = require "mason-core.optional"
local Pkg = require "mason-core.package"
local _ = require "mason-core.functional"
+local compiler = require "mason-core.installer.compiler"
local log = require "mason-core.log"
-local registry_installer = require "mason-core.installer.registry"
local M = {}
@@ -10,7 +10,7 @@ local M = {}
function M.map_registry_spec(spec)
spec.schema = spec.schema or "registry+v1"
- if not registry_installer.SCHEMA_CAP[spec.schema] then
+ if not compiler.SCHEMA_CAP[spec.schema] then
log.fmt_debug("Excluding package=%s with unsupported schema_version=%s", spec.name, spec.schema)
return Optional.empty()
end
diff --git a/lua/mason-test/helpers.lua b/lua/mason-test/helpers.lua
new file mode 100644
index 00000000..57b486ea
--- /dev/null
+++ b/lua/mason-test/helpers.lua
@@ -0,0 +1,33 @@
+local InstallContext = require "mason-core.installer.context"
+local InstallContextCwd = require "mason-core.installer.context.cwd"
+local InstallContextFs = require "mason-core.installer.context.fs"
+local InstallContextSpawn = require "mason-core.installer.context.spawn"
+local InstallHandle = require "mason-core.installer.handle"
+local InstallLocation = require "mason-core.installer.location"
+local Result = require "mason-core.result"
+local registry = require "mason-registry"
+local spy = require "luassert.spy"
+
+local M = {}
+
+---@param opts? { install_opts?: PackageInstallOpts, package?: string }
+function M.create_context(opts)
+ local pkg = registry.get_package(opts and opts.package or "dummy")
+ local handle = InstallHandle.new(pkg)
+ local location = InstallLocation.new "/tmp/install-dir"
+ local context_cwd = InstallContextCwd.new(location):set(location.dir)
+ local context_spawn = InstallContextSpawn.new(context_cwd, handle, false)
+ local context_fs = InstallContextFs.new(context_cwd)
+ local context = InstallContext.new(handle, context_cwd, context_spawn, context_fs, opts and opts.install_opts or {})
+ context.spawn = setmetatable({}, {
+ __index = function(s, cmd)
+ s[cmd] = spy.new(function()
+ return Result.success { stdout = nil, stderr = nil }
+ end)
+ return s[cmd]
+ end,
+ })
+ return context
+end
+
+return M
diff --git a/tests/helpers/lua/luassertx.lua b/tests/helpers/lua/luassertx.lua
index e9bc4e44..3de3bf15 100644
--- a/tests/helpers/lua/luassertx.lua
+++ b/tests/helpers/lua/luassertx.lua
@@ -2,6 +2,26 @@ local a = require "mason-core.async"
local assert = require "luassert"
local match = require "luassert.match"
+local function wait(_, arguments)
+ ---@type (fun()) Function to execute until it does not error.
+ local assertions_fn = arguments[1]
+ ---@type number Timeout in milliseconds. Defaults to 5000.
+ local timeout = arguments[2] or 5000
+
+ local err
+ if
+ not vim.wait(timeout, function()
+ local ok, err_ = pcall(assertions_fn)
+ err = err_
+ return ok
+ end, math.min(timeout, 100))
+ then
+ error(err)
+ end
+
+ return true
+end
+
local function wait_for(_, arguments)
---@type (fun()) Function to execute until it does not error.
local assertions_fn = arguments[1]
@@ -76,3 +96,4 @@ assert:register("matcher", "list_containing", list_containing)
assert:register("matcher", "instanceof", instanceof)
assert:register("matcher", "capture", capture)
assert:register("assertion", "wait_for", wait_for)
+assert:register("assertion", "wait", wait)
diff --git a/tests/helpers/lua/test_helpers.lua b/tests/helpers/lua/test_helpers.lua
deleted file mode 100644
index c7d6f983..00000000
--- a/tests/helpers/lua/test_helpers.lua
+++ /dev/null
@@ -1,70 +0,0 @@
----@diagnostic disable: lowercase-global
-local spy = require "luassert.spy"
-local util = require "luassert.util"
-
-local InstallContext = require "mason-core.installer.context"
-local InstallHandle = require "mason-core.installer.handle"
-local Result = require "mason-core.result"
-local a = require "mason-core.async"
-local path = require "mason-core.path"
-local registry = require "mason-registry"
-
--- selene: allow(unused_variable)
-function async_test(suspend_fn)
- return function()
- local ok, err = pcall(a.run_blocking, suspend_fn)
- if not ok then
- error(err, util.errorlevel())
- end
- end
-end
-
--- selene: allow(unscoped_variables, incorrect_standard_library_use)
-mockx = {
- just_runs = function() end,
- returns = function(val)
- return function()
- return val
- end
- end,
- throws = function(exception)
- return function()
- error(exception, 2)
- end
- end,
-}
-
----@param opts? PackageInstallOpts
-function create_dummy_context(opts)
- local ctx = InstallContextGenerator(InstallHandleGenerator "registry", opts)
- ctx.cwd:set(path.package_build_prefix "registry")
- ctx.spawn = setmetatable({}, {
- __index = function(s, cmd)
- s[cmd] = spy.new(function()
- return Result.success { stdout = nil, stderr = nil }
- end)
- return s[cmd]
- end,
- })
- return ctx
-end
-
--- selene: allow(unused_variable)
----@param package_name string
-function InstallHandleGenerator(package_name)
- return InstallHandle.new(registry.get_package(package_name))
-end
-
--- selene: allow(unused_variable)
----@param handle InstallHandle
----@param opts PackageInstallOpts?
-function InstallContextGenerator(handle, opts)
- local context = InstallContext.new(handle, opts or {})
- context.spawn = setmetatable({ strict_mode = true }, {
- __index = function(self, cmd)
- self[cmd] = spy.new(mockx.just_runs())
- return self[cmd]
- end,
- })
- return context
-end
diff --git a/tests/mason-core/EventEmitter_spec.lua b/tests/mason-core/EventEmitter_spec.lua
index caec8a80..76a9964b 100644
--- a/tests/mason-core/EventEmitter_spec.lua
+++ b/tests/mason-core/EventEmitter_spec.lua
@@ -32,26 +32,23 @@ describe("EventEmitter", function()
it("should remove registered event handlers", function()
local emitter = EventEmitter.init(setmetatable({}, { __index = EventEmitter }))
- local my_event_handler = spy.new()
- emitter:on("my:event", my_event_handler --[[@as fun()]])
- emitter:once("my:event", my_event_handler --[[@as fun()]])
+ local my_event_handler = spy.new() --[[@as fun()]]
+ emitter:on("my:event", my_event_handler)
+ emitter:once("my:event", my_event_handler)
- emitter:off("my:event", my_event_handler --[[@as fun()]])
+ emitter:off("my:event", my_event_handler)
emitter:emit("my:event", { table = "value" })
assert.spy(my_event_handler).was_called(0)
end)
- it(
- "should print errors in handlers",
- async_test(function()
- spy.on(vim.api, "nvim_err_writeln")
- local emitter = EventEmitter.init(setmetatable({}, { __index = EventEmitter }))
- emitter:on("event", mockx.throws "My error.")
- emitter:emit "event"
- a.wait(vim.schedule)
- assert.spy(vim.api.nvim_err_writeln).was_called(1)
- assert.spy(vim.api.nvim_err_writeln).was_called_with "My error."
- end)
- )
+ it("should print errors in handlers", function()
+ spy.on(vim.api, "nvim_err_writeln")
+ local emitter = EventEmitter.init(setmetatable({}, { __index = EventEmitter }))
+ emitter:on("event", mockx.throws "My error.")
+ emitter:emit "event"
+ a.run_blocking(a.wait, vim.schedule)
+ assert.spy(vim.api.nvim_err_writeln).was_called(1)
+ assert.spy(vim.api.nvim_err_writeln).was_called_with "My error."
+ end)
end)
diff --git a/tests/mason-core/async/async_spec.lua b/tests/mason-core/async/async_spec.lua
index 61eeeb1b..a4197b85 100644
--- a/tests/mason-core/async/async_spec.lua
+++ b/tests/mason-core/async/async_spec.lua
@@ -31,51 +31,39 @@ describe("async", function()
assert.equals(8, value)
end)
- it(
- "should pass arguments to .run",
- async_test(function()
- local callback = spy.new()
- local start = timestamp()
- a.run(a.sleep, callback, 100)
- assert.wait_for(function()
- assert.spy(callback).was_called(1)
- local stop = timestamp()
- local grace_ms = 25
- assert.is_true((stop - start) >= (100 - grace_ms))
- end, 150)
- end)
- )
+ it("should pass arguments to .run", function()
+ local fn = spy.new()
+ a.run(function(...)
+ fn(...)
+ end, spy.new(), 100, 200)
+ assert.spy(fn).was_called(1)
+ assert.spy(fn).was_called_with(100, 200)
+ end)
- it(
- "should wrap callback-style async functions",
- async_test(function()
- local stdio = process.in_memory_sink()
- local success, exit_code = a.promisify(process.spawn)("env", {
- args = {},
- env = { "FOO=BAR", "BAR=BAZ" },
- stdio_sink = stdio.sink,
- })
- assert.is_true(success)
- assert.equals(0, exit_code)
- assert.equals("FOO=BAR\nBAR=BAZ\n", table.concat(stdio.buffers.stdout, ""))
- end)
- )
+ it("should wrap callback-style async functions via promisify", function()
+ local async_spawn = _.compose(_.table_pack, a.promisify(process.spawn))
+ local stdio = process.in_memory_sink()
+ local success, exit_code = unpack(a.run_blocking(async_spawn, "env", {
+ args = {},
+ env = { "FOO=BAR", "BAR=BAZ" },
+ stdio_sink = stdio.sink,
+ }))
+ assert.is_true(success)
+ assert.equals(0, exit_code)
+ assert.equals("FOO=BAR\nBAR=BAZ\n", table.concat(stdio.buffers.stdout, ""))
+ end)
- it(
- "should reject callback-style functions",
- async_test(function()
- local err = assert.has_error(function()
- a.promisify(function(arg1, cb)
- cb(arg1, nil)
- end, true) "påskmust"
- end)
- assert.equals(err, "påskmust")
+ it("should propagate errors in callback-style functions via promisify", function()
+ local err = assert.has_error(function()
+ a.run_blocking(a.promisify(function(cb)
+ cb "Error message."
+ end, true))
end)
- )
+ assert.equals(err, "Error message.")
+ end)
- it(
- "should return all values",
- async_test(function()
+ it("should return all values from a.wait", function()
+ a.run_blocking(function()
local val1, val2, val3 = a.wait(function(resolve)
resolve(1, 2, 3)
end)
@@ -83,35 +71,32 @@ describe("async", function()
assert.equals(2, val2)
assert.equals(3, val3)
end)
- )
+ end)
- it(
- "should cancel coroutine",
- async_test(function()
- local james_bond = spy.new()
- local poutine = a.scope(function()
- a.sleep(100)
- james_bond()
+ it("should cancel coroutine", function()
+ local capture = spy.new()
+ a.run_blocking(function()
+ local cancel = a.scope(function()
+ a.sleep(10)
+ capture()
end)()
- poutine()
- a.sleep(200)
- assert.spy(james_bond).was_not.called()
+ cancel()
+ a.sleep(20)
end)
- )
+ assert.spy(capture).was_not.called()
+ end)
- it(
- "should raise error if async function raises error",
- async_test(function()
+ it("should raise error if async function raises error", function()
+ a.run_blocking(function()
local err = assert.has.errors(a.promisify(function()
error "something went wrong"
end))
assert.is_true(match.has_match "something went wrong$"(err))
end)
- )
+ end)
- it(
- "should raise error if async function rejects",
- async_test(function()
+ it("should raise error if async function rejects", function()
+ a.run_blocking(function()
local err = assert.has.errors(function()
a.wait(function(_, reject)
reject "This is an error"
@@ -119,18 +104,17 @@ describe("async", function()
end)
assert.equals("This is an error", err)
end)
- )
+ end)
- it(
- "should pass nil arguments to promisified functions",
- async_test(function()
- local fn = spy.new(function(_, _, _, _, _, _, _, cb)
- cb()
- end)
+ it("should pass nil arguments to promisified functions", function()
+ local fn = spy.new(function(_, _, _, _, _, _, _, cb)
+ cb()
+ end)
+ a.run_blocking(function()
a.promisify(fn)(nil, 2, nil, 4, nil, nil, 7)
- assert.spy(fn).was_called_with(nil, 2, nil, 4, nil, nil, 7, match.is_function())
end)
- )
+ assert.spy(fn).was_called_with(nil, 2, nil, 4, nil, nil, 7, match.is_function())
+ end)
it("should accept yielding non-promise values to parent coroutine context", function()
local thread = coroutine.create(function(val)
@@ -143,60 +127,56 @@ describe("async", function()
assert.equals(1337, value)
end)
- it(
- "should run all suspending functions concurrently",
- async_test(function()
- local start = timestamp()
- local function sleep(ms, ret_val)
- return function()
- a.sleep(ms)
- return ret_val
- end
+ it("should run all suspending functions concurrently", function()
+ local function sleep(ms, ret_val)
+ return function()
+ a.sleep(ms)
+ return ret_val
end
- local one, two, three, four, five = a.wait_all {
+ end
+ local start = timestamp()
+ local one, two, three, four, five = unpack(a.run_blocking(function()
+ return _.table_pack(a.wait_all {
sleep(100, 1),
sleep(100, "two"),
sleep(100, "three"),
sleep(100, 4),
sleep(100, 5),
- }
- local grace = 50
- local delta = timestamp() - start
- assert.is_true(delta <= (100 + grace))
- assert.is_true(delta >= (100 - grace))
- assert.equals(1, one)
- assert.equals("two", two)
- assert.equals("three", three)
- assert.equals(4, four)
- assert.equals(5, five)
- end)
- )
+ })
+ end))
+ local grace = 50
+ local delta = timestamp() - start
+ assert.is_true(delta <= (100 + grace))
+ assert.is_true(delta >= (100 - grace))
+ assert.equals(1, one)
+ assert.equals("two", two)
+ assert.equals("three", three)
+ assert.equals(4, four)
+ assert.equals(5, five)
+ end)
- it(
- "should run all suspending functions concurrently",
- async_test(function()
- local start = timestamp()
- local called = spy.new()
- local function sleep(ms, ret_val)
- return function()
- a.sleep(ms)
- called()
- return ret_val
- end
+ it("should run all suspending functions concurrently", function()
+ local start = timestamp()
+ local called = spy.new()
+ local function sleep(ms, ret_val)
+ return function()
+ a.sleep(ms)
+ called()
+ return ret_val
end
- local first = a.wait_first {
- sleep(150, 1),
- sleep(50, "first"),
- sleep(150, "three"),
- sleep(150, 4),
- sleep(150, 5),
- }
- local grace = 20
- local delta = timestamp() - start
- assert.is_true(delta <= (50 + grace))
- assert.equals("first", first)
- end)
- )
+ end
+ local first = a.run_blocking(a.wait_first, {
+ sleep(150, 1),
+ sleep(50, "first"),
+ sleep(150, "three"),
+ sleep(150, 4),
+ sleep(150, 5),
+ })
+ local grace = 20
+ local delta = timestamp() - start
+ assert.is_true(delta <= (50 + grace))
+ assert.equals("first", first)
+ end)
it("should yield back immediately when not providing any functions", function()
assert.is_nil(a.wait_first {})
diff --git a/tests/mason-core/fetch_spec.lua b/tests/mason-core/fetch_spec.lua
index 107b6417..5a890318 100644
--- a/tests/mason-core/fetch_spec.lua
+++ b/tests/mason-core/fetch_spec.lua
@@ -6,118 +6,115 @@ local stub = require "luassert.stub"
local version = require "mason.version"
describe("fetch", function()
- it(
- "should exhaust all candidates",
- async_test(function()
- stub(spawn, "wget")
- stub(spawn, "curl")
- spawn.wget.returns(Result.failure "wget failure")
- spawn.curl.returns(Result.failure "curl failure")
+ local snapshot
- local result = fetch("https://api.github.com", {
- headers = { ["X-Custom-Header"] = "here" },
- })
- assert.is_true(result:is_failure())
- assert.spy(spawn.wget).was_called(1)
- assert.spy(spawn.curl).was_called(1)
- assert.spy(spawn.wget).was_called_with {
- {
- ("--header=User-Agent: mason.nvim %s (+https://github.com/williamboman/mason.nvim)"):format(
- version.VERSION
- ),
- "--header=X-Custom-Header: here",
- },
- "-nv",
- "-o",
- "/dev/null",
- "-O",
- "-",
- "--timeout=30",
- "--method=GET",
- vim.NIL, -- body-data
- "https://api.github.com",
- }
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
- assert.spy(spawn.curl).was_called_with(match.tbl_containing {
- match.same {
- {
- "-H",
- ("User-Agent: mason.nvim %s (+https://github.com/williamboman/mason.nvim)"):format(
- version.VERSION
- ),
- },
- {
- "-H",
- "X-Custom-Header: here",
- },
- },
- "-fsSL",
- match.same { "-X", "GET" },
- vim.NIL, -- data
- vim.NIL, -- out file
- match.same { "--connect-timeout", 30 },
- "https://api.github.com",
- on_spawn = match.is_function(),
- })
- end)
- )
+ after_each(function()
+ snapshot:revert()
+ end)
- it(
- "should return stdout",
- async_test(function()
- stub(spawn, "wget")
- spawn.wget.returns(Result.success {
- stdout = [[{"data": "here"}]],
- })
- local result = fetch "https://api.github.com/data"
- assert.is_true(result:is_success())
- assert.equals([[{"data": "here"}]], result:get_or_throw())
- end)
- )
+ it("should exhaust all candidates", function()
+ stub(spawn, "wget")
+ stub(spawn, "curl")
+ spawn.wget.returns(Result.failure "wget failure")
+ spawn.curl.returns(Result.failure "curl failure")
- it(
- "should respect out_file opt",
- async_test(function()
- stub(spawn, "wget")
- stub(spawn, "curl")
- spawn.wget.returns(Result.failure "wget failure")
- spawn.curl.returns(Result.failure "curl failure")
- fetch("https://api.github.com/data", { out_file = "/test.json" })
+ local result = fetch("https://api.github.com", {
+ headers = { ["X-Custom-Header"] = "here" },
+ })
+ assert.is_true(result:is_failure())
+ assert.spy(spawn.wget).was_called(1)
+ assert.spy(spawn.curl).was_called(1)
+ assert.spy(spawn.wget).was_called_with {
+ {
+ ("--header=User-Agent: mason.nvim %s (+https://github.com/williamboman/mason.nvim)"):format(
+ version.VERSION
+ ),
+ "--header=X-Custom-Header: here",
+ },
+ "-nv",
+ "-o",
+ "/dev/null",
+ "-O",
+ "-",
+ "--timeout=30",
+ "--method=GET",
+ vim.NIL, -- body-data
+ "https://api.github.com",
+ }
- assert.spy(spawn.wget).was_called_with {
+ assert.spy(spawn.curl).was_called_with(match.tbl_containing {
+ match.same {
+ {
+ "-H",
+ ("User-Agent: mason.nvim %s (+https://github.com/williamboman/mason.nvim)"):format(version.VERSION),
+ },
{
- ("--header=User-Agent: mason.nvim %s (+https://github.com/williamboman/mason.nvim)"):format(
- version.VERSION
- ),
+ "-H",
+ "X-Custom-Header: here",
},
- "-nv",
- "-o",
- "/dev/null",
- "-O",
- "/test.json",
- "--timeout=30",
- "--method=GET",
- vim.NIL, -- body-data
- "https://api.github.com/data",
- }
+ },
+ "-fsSL",
+ match.same { "-X", "GET" },
+ vim.NIL, -- data
+ vim.NIL, -- out file
+ match.same { "--connect-timeout", 30 },
+ "https://api.github.com",
+ on_spawn = match.is_function(),
+ })
+ end)
- assert.spy(spawn.curl).was_called_with(match.tbl_containing {
- match.same {
- {
- "-H",
- ("User-Agent: mason.nvim %s (+https://github.com/williamboman/mason.nvim)"):format(
- version.VERSION
- ),
- },
+ it("should return stdout", function()
+ stub(spawn, "curl")
+ spawn.curl.returns(Result.success {
+ stdout = [[{"data": "here"}]],
+ })
+ local result = fetch "https://api.github.com/data"
+ assert.is_true(result:is_success())
+ assert.equals([[{"data": "here"}]], result:get_or_throw())
+ end)
+
+ it("should respect out_file opt", function()
+ stub(spawn, "wget")
+ stub(spawn, "curl")
+ spawn.wget.returns(Result.failure "wget failure")
+ spawn.curl.returns(Result.failure "curl failure")
+ fetch("https://api.github.com/data", { out_file = "/test.json" })
+
+ assert.spy(spawn.wget).was_called_with {
+ {
+ ("--header=User-Agent: mason.nvim %s (+https://github.com/williamboman/mason.nvim)"):format(
+ version.VERSION
+ ),
+ },
+ "-nv",
+ "-o",
+ "/dev/null",
+ "-O",
+ "/test.json",
+ "--timeout=30",
+ "--method=GET",
+ vim.NIL, -- body-data
+ "https://api.github.com/data",
+ }
+
+ assert.spy(spawn.curl).was_called_with(match.tbl_containing {
+ match.same {
+ {
+ "-H",
+ ("User-Agent: mason.nvim %s (+https://github.com/williamboman/mason.nvim)"):format(version.VERSION),
},
- "-fsSL",
- match.same { "-X", "GET" },
- vim.NIL, -- data
- match.same { "-o", "/test.json" },
- match.same { "--connect-timeout", 30 },
- "https://api.github.com/data",
- on_spawn = match.is_function(),
- })
- end)
- )
+ },
+ "-fsSL",
+ match.same { "-X", "GET" },
+ vim.NIL, -- data
+ match.same { "-o", "/test.json" },
+ match.same { "--connect-timeout", 30 },
+ "https://api.github.com/data",
+ on_spawn = match.is_function(),
+ })
+ end)
end)
diff --git a/tests/mason-core/fs_spec.lua b/tests/mason-core/fs_spec.lua
index 38f97eeb..bd3696da 100644
--- a/tests/mason-core/fs_spec.lua
+++ b/tests/mason-core/fs_spec.lua
@@ -8,17 +8,14 @@ describe("fs", function()
}
end)
- it(
- "refuses to rmrf paths outside of boundary",
- async_test(function()
- local e = assert.has_error(function()
- fs.async.rmrf "/thisisa/path"
- end)
-
- assert.equals(
- [[Refusing to rmrf "/thisisa/path" which is outside of the allowed boundary "/foo". Please report this error at https://github.com/williamboman/mason.nvim/issues/new]],
- e
- )
+ it("refuses to rmrf paths outside of boundary", function()
+ local e = assert.has_error(function()
+ fs.sync.rmrf "/thisisa/path"
end)
- )
+
+ assert.equals(
+ [[Refusing to rmrf "/thisisa/path" which is outside of the allowed boundary "/foo". Please report this error at https://github.com/williamboman/mason.nvim/issues/new]],
+ e
+ )
+ end)
end)
diff --git a/tests/mason-core/installer/context_spec.lua b/tests/mason-core/installer/context_spec.lua
index 646f7e30..9c1805cb 100644
--- a/tests/mason-core/installer/context_spec.lua
+++ b/tests/mason-core/installer/context_spec.lua
@@ -3,10 +3,20 @@ local path = require "mason-core.path"
local pypi = require "mason-core.installer.managers.pypi"
local registry = require "mason-registry"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
describe("installer", function()
---@module "mason-core.platform"
local platform
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
before_each(function()
package.loaded["mason-core.installer.platform"] = nil
@@ -15,8 +25,7 @@ describe("installer", function()
end)
it("should write shell exec wrapper on Unix", function()
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "write_file")
stub(ctx.fs, "file_exists")
stub(ctx.fs, "dir_exists")
@@ -44,8 +53,7 @@ exec bash -c 'echo $GREETING' "$@"]]
platform.is.unix = false
platform.is.linux = false
platform.is.win = true
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "write_file")
stub(ctx.fs, "file_exists")
stub(ctx.fs, "dir_exists")
@@ -68,8 +76,7 @@ cmd.exe /C echo %GREETING% %*]]
it("should not write shell exec wrapper if new executable path already exists", function()
local exec_rel_path = path.concat { "obscure", "path", "to", "server" }
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
stub(ctx.fs, "dir_exists")
ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), exec_rel_path).returns(true)
@@ -86,8 +93,7 @@ cmd.exe /C echo %GREETING% %*]]
it("should write Node exec wrapper", function()
local js_rel_path = path.concat { "some", "obscure", "path", "server.js" }
local dummy = registry.get_package "dummy"
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx, "write_shell_exec_wrapper")
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), js_rel_path).returns(true)
@@ -105,8 +111,7 @@ cmd.exe /C echo %GREETING% %*]]
it("should write Ruby exec wrapper", function()
local js_rel_path = path.concat { "some", "obscure", "path", "server.js" }
local dummy = registry.get_package "dummy"
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx, "write_shell_exec_wrapper")
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), js_rel_path).returns(true)
@@ -123,8 +128,7 @@ cmd.exe /C echo %GREETING% %*]]
it("should not write Node exec wrapper if the target script doesn't exist", function()
local js_rel_path = path.concat { "some", "obscure", "path", "server.js" }
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx, "write_shell_exec_wrapper")
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), js_rel_path).returns(false)
@@ -142,8 +146,7 @@ cmd.exe /C echo %GREETING% %*]]
it("should write Python exec wrapper", function()
local dummy = registry.get_package "dummy"
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx.cwd, "get")
ctx.cwd.get.returns "/tmp/placeholder"
stub(ctx, "write_shell_exec_wrapper")
@@ -159,8 +162,7 @@ cmd.exe /C echo %GREETING% %*]]
end)
it("should not write Python exec wrapper if module cannot be found", function()
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx.cwd, "get")
ctx.cwd.get.returns "/tmp/placeholder"
stub(ctx, "write_shell_exec_wrapper")
@@ -181,8 +183,7 @@ cmd.exe /C echo %GREETING% %*]]
it("should write exec wrapper", function()
local dummy = registry.get_package "dummy"
local exec_rel_path = path.concat { "obscure", "path", "to", "server" }
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx, "write_shell_exec_wrapper")
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), exec_rel_path).returns(true)
@@ -201,8 +202,7 @@ cmd.exe /C echo %GREETING% %*]]
it("should not write exec wrapper if target executable doesn't exist", function()
local exec_rel_path = path.concat { "obscure", "path", "to", "server" }
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx, "write_shell_exec_wrapper")
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), exec_rel_path).returns(false)
@@ -218,8 +218,7 @@ cmd.exe /C echo %GREETING% %*]]
it("should write PHP exec wrapper", function()
local php_rel_path = path.concat { "some", "obscure", "path", "cli.php" }
local dummy = registry.get_package "dummy"
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx, "write_shell_exec_wrapper")
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), php_rel_path).returns(true)
@@ -236,8 +235,7 @@ cmd.exe /C echo %GREETING% %*]]
it("should not write PHP exec wrapper if the target script doesn't exist", function()
local php_rel_path = path.concat { "some", "obscure", "path", "cli.php" }
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
stub(ctx, "write_shell_exec_wrapper")
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.is_ref(ctx.fs), php_rel_path).returns(false)
diff --git a/tests/mason-core/installer/handle_spec.lua b/tests/mason-core/installer/handle_spec.lua
index c301b28b..66a9a5c4 100644
--- a/tests/mason-core/installer/handle_spec.lua
+++ b/tests/mason-core/installer/handle_spec.lua
@@ -4,6 +4,16 @@ local spy = require "luassert.spy"
local stub = require "luassert.stub"
describe("installer handle", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should register spawn handle", function()
local handle = InstallHandle.new(mock.new {})
local spawn_handle_change_handler = spy.new()
@@ -72,36 +82,33 @@ describe("installer handle", function()
assert.spy(kill_handler).was_called_with(9)
end)
- it(
- "should terminate handle",
- async_test(function()
- local process = require "mason-core.process"
- stub(process, "kill")
- local uv_handle1 = {}
- local uv_handle2 = {}
- local handle = InstallHandle.new(mock.new {})
- local kill_handler = spy.new()
- local terminate_handler = spy.new()
- local closed_handler = spy.new()
+ it("should terminate handle", function()
+ local process = require "mason-core.process"
+ stub(process, "kill")
+ local uv_handle1 = {}
+ local uv_handle2 = {}
+ local handle = InstallHandle.new(mock.new {})
+ local kill_handler = spy.new()
+ local terminate_handler = spy.new()
+ local closed_handler = spy.new()
- handle:once("kill", kill_handler)
- handle:once("terminate", terminate_handler)
- handle:once("closed", closed_handler)
- handle.state = "ACTIVE"
- handle.spawn_handles = { { uv_handle = uv_handle2 }, { uv_handle = uv_handle2 } }
- handle:terminate()
+ handle:once("kill", kill_handler)
+ handle:once("terminate", terminate_handler)
+ handle:once("closed", closed_handler)
+ handle.state = "ACTIVE"
+ handle.spawn_handles = { { uv_handle = uv_handle2 }, { uv_handle = uv_handle2 } }
+ handle:terminate()
- assert.spy(process.kill).was_called(2)
- assert.spy(process.kill).was_called_with(uv_handle1, 15)
- assert.spy(process.kill).was_called_with(uv_handle2, 15)
- assert.spy(kill_handler).was_called(1)
- assert.spy(kill_handler).was_called_with(15)
- assert.spy(terminate_handler).was_called(1)
- assert.is_true(handle.is_terminated)
- assert.wait_for(function()
- assert.is_true(handle:is_closed())
- assert.spy(closed_handler).was_called(1)
- end)
+ assert.spy(process.kill).was_called(2)
+ assert.spy(process.kill).was_called_with(uv_handle1, 15)
+ assert.spy(process.kill).was_called_with(uv_handle2, 15)
+ assert.spy(kill_handler).was_called(1)
+ assert.spy(kill_handler).was_called_with(15)
+ assert.spy(terminate_handler).was_called(1)
+ assert.is_true(handle.is_terminated)
+ assert.wait(function()
+ assert.is_true(handle:is_closed())
+ assert.spy(closed_handler).was_called(1)
end)
- )
+ end)
end)
diff --git a/tests/mason-core/installer/installer_spec.lua b/tests/mason-core/installer/installer_spec.lua
deleted file mode 100644
index 3e291308..00000000
--- a/tests/mason-core/installer/installer_spec.lua
+++ /dev/null
@@ -1,217 +0,0 @@
-local InstallContext = require "mason-core.installer.context"
-local Result = require "mason-core.result"
-local a = require "mason-core.async"
-local fs = require "mason-core.fs"
-local installer = require "mason-core.installer"
-local match = require "luassert.match"
-local path = require "mason-core.path"
-local spy = require "luassert.spy"
-local stub = require "luassert.stub"
-
-local function timestamp()
- local seconds, microseconds = vim.loop.gettimeofday()
- return (seconds * 1000) + math.floor(microseconds / 1000)
-end
-
-describe("installer", function()
- before_each(function()
- package.loaded["dummy_package"] = nil
- end)
-
- it(
- "should call installer",
- async_test(function()
- spy.on(fs.async, "mkdirp")
- spy.on(fs.async, "rename")
-
- local handle = InstallHandleGenerator "dummy"
- spy.on(handle.package.spec.source, "install")
- local result = installer.execute(handle, {})
-
- assert.is_nil(result:err_or_nil())
- assert.spy(handle.package.spec.source.install).was_called(1)
- assert
- .spy(handle.package.spec.source.install)
- .was_called_with(match.instanceof(InstallContext), match.is_table())
- assert.spy(fs.async.mkdirp).was_called_with(path.package_build_prefix "dummy")
- assert.spy(fs.async.rename).was_called_with(path.package_build_prefix "dummy", path.package_prefix "dummy")
- end)
- )
-
- it(
- "should return failure if installer errors",
- async_test(function()
- spy.on(fs.async, "rmrf")
- spy.on(fs.async, "rename")
- local installer_fn = spy.new(function()
- error("something went wrong. don't try again.", 0)
- end)
- local handler = InstallHandleGenerator "dummy"
- stub(handler.package.spec.source, "install", installer_fn)
- local result = installer.execute(handler, {})
- assert.spy(installer_fn).was_called(1)
- assert.is_true(result:is_failure())
- assert.equals("something went wrong. don't try again.", result:err_or_nil())
- assert.spy(fs.async.rmrf).was_called_with(path.package_build_prefix "dummy")
- assert.spy(fs.async.rename).was_not_called()
- end)
- )
-
- it(
- "should write receipt",
- async_test(function()
- spy.on(fs.async, "write_file")
- local handle = InstallHandleGenerator "dummy"
- stub(handle.package.spec.source, "install", function(ctx)
- ctx.fs:write_file("target", "")
- ctx.fs:write_file("file.jar", "")
- ctx.fs:write_file("opt-cmd", "")
- end)
- handle.package.spec.bin = {
- ["executable"] = "target",
- }
- handle.package.spec.share = {
- ["package/file.jar"] = "file.jar",
- }
- handle.package.spec.opt = {
- ["package/bin/opt-cmd"] = "opt-cmd",
- }
- installer.execute(handle, {})
- handle.package.spec.bin = {}
- handle.package.spec.share = {}
- handle.package.spec.opt = {}
- assert.spy(fs.async.write_file).was_called_with(
- ("%s/mason-receipt.json"):format(handle.package:get_install_path()),
- match.capture(function(arg)
- ---@type InstallReceipt
- local receipt = vim.json.decode(arg)
- assert.is_true(match.tbl_containing {
- name = "dummy",
- source = match.same {
- type = handle.package.spec.schema,
- id = handle.package.spec.source.id,
- },
- schema_version = "1.2",
- metrics = match.is_table(),
- links = match.same {
- bin = { executable = "target" },
- share = { ["package/file.jar"] = "file.jar" },
- opt = { ["package/bin/opt-cmd"] = "opt-cmd" },
- },
- }(receipt))
- end)
- )
- end)
- )
-
- it(
- "should run async functions concurrently",
- async_test(function()
- spy.on(fs.async, "write_file")
- local capture = spy.new()
- local start = timestamp()
- local handle = InstallHandleGenerator "dummy"
- stub(handle.package.spec.source, "install", function(ctx)
- capture(installer.run_concurrently {
- function()
- a.sleep(100)
- return installer.context()
- end,
- function()
- a.sleep(100)
- return "two"
- end,
- function()
- a.sleep(100)
- return "three"
- end,
- })
- end)
- installer.execute(handle, {})
- local stop = timestamp()
- local grace_ms = 25
- assert.is_true((stop - start) >= (100 - grace_ms))
- assert.spy(capture).was_called_with(match.instanceof(InstallContext), "two", "three")
- end)
- )
-
- it(
- "should write log files if debug is true",
- async_test(function()
- spy.on(fs.async, "write_file")
- local handle = InstallHandleGenerator "dummy"
- stub(handle.package.spec.source, "install", function(ctx)
- ctx.stdio_sink.stdout "Hello stdout!\n"
- ctx.stdio_sink.stderr "Hello "
- ctx.stdio_sink.stderr "stderr!"
- end)
- installer.execute(handle, { debug = true })
- assert
- .spy(fs.async.write_file)
- .was_called_with(path.package_prefix "dummy/mason-debug.log", "Hello stdout!\nHello stderr!")
- end)
- )
-
- it(
- "should raise spawn errors in strict mode",
- async_test(function()
- local handle = InstallHandleGenerator "dummy"
- stub(handle.package.spec.source, "install", function(ctx)
- ctx.spawn.bash { "-c", "exit 42" }
- end)
- local result = installer.execute(handle, { debug = true })
- assert.same(
- Result.failure {
- exit_code = 42,
- signal = 0,
- },
- result
- )
- assert.equals("spawn: bash failed with exit code 42 and signal 0. ", tostring(result:err_or_nil()))
- end)
- )
-
- it(
- "should lock package",
- async_test(function()
- local handle = InstallHandleGenerator "dummy"
- local callback = spy.new()
- stub(handle.package.spec.source, "install", function()
- a.sleep(3000)
- end)
-
- a.run(function()
- return installer.execute(handle, { debug = true })
- end, callback)
-
- assert.wait_for(function()
- assert.is_true(fs.sync.file_exists(path.package_lock "dummy"))
- end)
- handle:terminate()
- assert.wait_for(function()
- assert.spy(callback).was_called(1)
- end)
- assert.is_false(fs.sync.file_exists(path.package_lock "dummy"))
- end)
- )
-
- it(
- "should not run installer if package lock exists",
- async_test(function()
- local handle = InstallHandleGenerator "dummy"
- local install = spy.new()
- stub(handle.package.spec.source, "install", install)
-
- fs.sync.write_file(path.package_lock "dummy", "dummypid")
- local result = installer.execute(handle, { debug = true })
- assert.is_true(fs.sync.file_exists(path.package_lock "dummy"))
- fs.sync.unlink(path.package_lock "dummy")
-
- assert.spy(install).was_not_called()
- assert.equals(
- "Lockfile exists, installation is already running in another process (pid: dummypid). Run with :MasonInstall --force to bypass.",
- result:err_or_nil()
- )
- end)
- )
-end)
diff --git a/tests/mason-core/installer/linker_spec.lua b/tests/mason-core/installer/linker_spec.lua
index 8bcf2607..9684f57d 100644
--- a/tests/mason-core/installer/linker_spec.lua
+++ b/tests/mason-core/installer/linker_spec.lua
@@ -1,7 +1,9 @@
+local a = require "mason-core.async"
local fs = require "mason-core.fs"
local path = require "mason-core.path"
local registry = require "mason-registry"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
local WIN_CMD_SCRIPT = [[@ECHO off
GOTO start
@@ -15,6 +17,16 @@ CALL :find_dp0
endLocal & goto #_undefined_# 2>NUL || title %%COMSPEC%% & "%s" %%*]]
describe("linker", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
---@module "mason-core.installer.linker"
local linker
---@module "mason-core.platform"
@@ -27,130 +39,119 @@ describe("linker", function()
linker = require "mason-core.installer.linker"
end)
- it(
- "should symlink executable on Unix",
- async_test(function()
- local dummy = registry.get_package "dummy"
- stub(fs.async, "file_exists")
- stub(fs.async, "symlink")
- stub(fs.async, "write_file")
+ it("should symlink executable on Unix", function()
+ local dummy = registry.get_package "dummy"
+ stub(fs.async, "file_exists")
+ stub(fs.async, "symlink")
+ stub(fs.async, "write_file")
- fs.async.file_exists.on_call_with(path.bin_prefix "my-executable").returns(false)
- fs.async.file_exists.on_call_with(path.bin_prefix "another-executable").returns(false)
- fs.async.file_exists
- .on_call_with(path.concat { dummy:get_install_path(), "nested", "path", "my-executable" })
- .returns(true)
- fs.async.file_exists
- .on_call_with(path.concat { dummy:get_install_path(), "another-executable" })
- .returns(true)
+ fs.async.file_exists.on_call_with(path.bin_prefix "my-executable").returns(false)
+ fs.async.file_exists.on_call_with(path.bin_prefix "another-executable").returns(false)
+ fs.async.file_exists
+ .on_call_with(path.concat { dummy:get_install_path(), "nested", "path", "my-executable" })
+ .returns(true)
+ fs.async.file_exists.on_call_with(path.concat { dummy:get_install_path(), "another-executable" }).returns(true)
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
- ctx:link_bin("my-executable", path.concat { "nested", "path", "my-executable" })
- ctx:link_bin("another-executable", "another-executable")
- assert.is_true(linker.link(ctx):is_success())
+ local ctx = test_helpers.create_context()
+ ctx:link_bin("my-executable", path.concat { "nested", "path", "my-executable" })
+ ctx:link_bin("another-executable", "another-executable")
+ local result = a.run_blocking(linker.link, ctx)
+ assert.is_true(result:is_success())
- assert.spy(fs.async.write_file).was_called(0)
- assert.spy(fs.async.symlink).was_called(2)
- assert
- .spy(fs.async.symlink)
- .was_called_with(path.concat { dummy:get_install_path(), "another-executable" }, path.bin_prefix "another-executable")
- assert.spy(fs.async.symlink).was_called_with(
+ assert.spy(fs.async.write_file).was_called(0)
+ assert.spy(fs.async.symlink).was_called(2)
+ assert
+ .spy(fs.async.symlink)
+ .was_called_with(path.concat { dummy:get_install_path(), "another-executable" }, path.bin_prefix "another-executable")
+ assert
+ .spy(fs.async.symlink)
+ .was_called_with(
path.concat { dummy:get_install_path(), "nested", "path", "my-executable" },
path.bin_prefix "my-executable"
)
- end)
- )
+ end)
- it(
- "should write executable wrapper on Windows",
- async_test(function()
- platform.is.darwin = false
- platform.is.mac = false
- platform.is.linux = false
- platform.is.unix = false
- platform.is.win = true
+ it("should write executable wrapper on Windows", function()
+ platform.is.darwin = false
+ platform.is.mac = false
+ platform.is.linux = false
+ platform.is.unix = false
+ platform.is.win = true
- local dummy = registry.get_package "dummy"
- stub(fs.async, "file_exists")
- stub(fs.async, "symlink")
- stub(fs.async, "write_file")
+ local dummy = registry.get_package "dummy"
+ stub(fs.async, "file_exists")
+ stub(fs.async, "symlink")
+ stub(fs.async, "write_file")
- fs.async.file_exists.on_call_with(path.bin_prefix "my-executable").returns(false)
- fs.async.file_exists.on_call_with(path.bin_prefix "another-executable").returns(false)
- fs.async.file_exists
- .on_call_with(path.concat { dummy:get_install_path(), "nested", "path", "my-executable" })
- .returns(true)
- fs.async.file_exists
- .on_call_with(path.concat { dummy:get_install_path(), "another-executable" })
- .returns(true)
+ fs.async.file_exists.on_call_with(path.bin_prefix "my-executable").returns(false)
+ fs.async.file_exists.on_call_with(path.bin_prefix "another-executable").returns(false)
+ fs.async.file_exists
+ .on_call_with(path.concat { dummy:get_install_path(), "nested", "path", "my-executable" })
+ .returns(true)
+ fs.async.file_exists.on_call_with(path.concat { dummy:get_install_path(), "another-executable" }).returns(true)
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
- ctx:link_bin("my-executable", path.concat { "nested", "path", "my-executable" })
- ctx:link_bin("another-executable", "another-executable")
- assert.is_true(linker.link(ctx):is_success())
+ local ctx = test_helpers.create_context()
+ ctx:link_bin("my-executable", path.concat { "nested", "path", "my-executable" })
+ ctx:link_bin("another-executable", "another-executable")
- assert.spy(fs.async.symlink).was_called(0)
- assert.spy(fs.async.write_file).was_called(2)
- assert.spy(fs.async.write_file).was_called_with(
- path.bin_prefix "another-executable.cmd",
- WIN_CMD_SCRIPT:format(path.concat { dummy:get_install_path(), "another-executable" })
- )
- assert.spy(fs.async.write_file).was_called_with(
- path.bin_prefix "my-executable.cmd",
- WIN_CMD_SCRIPT:format(path.concat { dummy:get_install_path(), "nested", "path", "my-executable" })
- )
- end)
- )
+ local result = a.run_blocking(linker.link, ctx)
+ assert.is_true(result:is_success())
- it(
- "should symlink share files",
- async_test(function()
- local dummy = registry.get_package "dummy"
- stub(fs.async, "mkdirp")
- stub(fs.async, "dir_exists")
- stub(fs.async, "file_exists")
- stub(fs.async, "symlink")
- stub(fs.async, "write_file")
+ assert.spy(fs.async.symlink).was_called(0)
+ assert.spy(fs.async.write_file).was_called(2)
+ assert.spy(fs.async.write_file).was_called_with(
+ path.bin_prefix "another-executable.cmd",
+ WIN_CMD_SCRIPT:format(path.concat { dummy:get_install_path(), "another-executable" })
+ )
+ assert.spy(fs.async.write_file).was_called_with(
+ path.bin_prefix "my-executable.cmd",
+ WIN_CMD_SCRIPT:format(path.concat { dummy:get_install_path(), "nested", "path", "my-executable" })
+ )
+ end)
- -- mock non-existent dest files
- fs.async.file_exists.on_call_with(path.share_prefix "share-file").returns(false)
- fs.async.file_exists.on_call_with(path.share_prefix(path.concat { "nested", "share-file" })).returns(false)
+ it("should symlink share files", function()
+ local dummy = registry.get_package "dummy"
+ stub(fs.async, "mkdirp")
+ stub(fs.async, "dir_exists")
+ stub(fs.async, "file_exists")
+ stub(fs.async, "symlink")
+ stub(fs.async, "write_file")
- fs.async.dir_exists.on_call_with(path.share_prefix()).returns(false)
- fs.async.dir_exists.on_call_with(path.share_prefix "nested/path").returns(false)
+ -- mock non-existent dest files
+ fs.async.file_exists.on_call_with(path.share_prefix "share-file").returns(false)
+ fs.async.file_exists.on_call_with(path.share_prefix(path.concat { "nested", "share-file" })).returns(false)
- -- mock existent source files
- fs.async.file_exists.on_call_with(path.concat { dummy:get_install_path(), "share-file" }).returns(true)
- fs.async.file_exists
- .on_call_with(path.concat { dummy:get_install_path(), "nested", "path", "to", "share-file" })
- .returns(true)
+ fs.async.dir_exists.on_call_with(path.share_prefix()).returns(false)
+ fs.async.dir_exists.on_call_with(path.share_prefix "nested/path").returns(false)
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
- ctx.links.share["nested/path/share-file"] = path.concat { "nested", "path", "to", "share-file" }
- ctx.links.share["share-file"] = "share-file"
+ -- mock existent source files
+ fs.async.file_exists.on_call_with(path.concat { dummy:get_install_path(), "share-file" }).returns(true)
+ fs.async.file_exists
+ .on_call_with(path.concat { dummy:get_install_path(), "nested", "path", "to", "share-file" })
+ .returns(true)
- local result = linker.link(ctx)
+ local ctx = test_helpers.create_context()
+ ctx.links.share["nested/path/share-file"] = path.concat { "nested", "path", "to", "share-file" }
+ ctx.links.share["share-file"] = "share-file"
- assert.is_true(result:is_success())
+ local result = a.run_blocking(linker.link, ctx)
- assert.spy(fs.async.write_file).was_called(0)
- assert.spy(fs.async.symlink).was_called(2)
- assert
- .spy(fs.async.symlink)
- .was_called_with(path.concat { dummy:get_install_path(), "share-file" }, path.share_prefix "share-file")
- assert.spy(fs.async.symlink).was_called_with(
- path.concat { dummy:get_install_path(), "nested", "path", "to", "share-file" },
- path.share_prefix "nested/path/share-file"
- )
+ assert.is_true(result:is_success())
- assert.spy(fs.async.mkdirp).was_called(2)
- assert.spy(fs.async.mkdirp).was_called_with(path.share_prefix())
- assert.spy(fs.async.mkdirp).was_called_with(path.share_prefix "nested/path")
- end)
- )
+ assert.spy(fs.async.write_file).was_called(0)
+ assert.spy(fs.async.symlink).was_called(2)
+ assert
+ .spy(fs.async.symlink)
+ .was_called_with(path.concat { dummy:get_install_path(), "share-file" }, path.share_prefix "share-file")
+ assert.spy(fs.async.symlink).was_called_with(
+ path.concat { dummy:get_install_path(), "nested", "path", "to", "share-file" },
+ path.share_prefix "nested/path/share-file"
+ )
+
+ assert.spy(fs.async.mkdirp).was_called(2)
+ assert.spy(fs.async.mkdirp).was_called_with(path.share_prefix())
+ assert.spy(fs.async.mkdirp).was_called_with(path.share_prefix "nested/path")
+ end)
it("should copy share files on Windows", function()
platform.is.darwin = false
@@ -178,8 +179,7 @@ describe("linker", function()
.on_call_with(path.concat { dummy:get_install_path(), "nested", "path", "to", "share-file" })
.returns(true)
- local handle = InstallHandleGenerator "dummy"
- local ctx = InstallContextGenerator(handle)
+ local ctx = test_helpers.create_context()
ctx.links.share["nested/path/share-file"] = path.concat { "nested", "path", "to", "share-file" }
ctx.links.share["share-file"] = "share-file"
diff --git a/tests/mason-core/installer/managers/cargo_spec.lua b/tests/mason-core/installer/managers/cargo_spec.lua
index 475c2c86..bc5c5f21 100644
--- a/tests/mason-core/installer/managers/cargo_spec.lua
+++ b/tests/mason-core/installer/managers/cargo_spec.lua
@@ -1,12 +1,12 @@
local cargo = require "mason-core.installer.managers.cargo"
-local installer = require "mason-core.installer"
local spy = require "luassert.spy"
+local test_helpers = require "mason-test.helpers"
describe("cargo manager", function()
it("should install", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
cargo.install("my-crate", "1.0.0")
end)
@@ -23,10 +23,10 @@ describe("cargo manager", function()
end)
it("should write output", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
spy.on(ctx.stdio_sink, "stdout")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
cargo.install("my-crate", "1.0.0")
end)
@@ -34,8 +34,8 @@ describe("cargo manager", function()
end)
it("should install locked", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
cargo.install("my-crate", "1.0.0", {
locked = true,
})
@@ -54,8 +54,8 @@ describe("cargo manager", function()
end)
it("should install provided features", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
cargo.install("my-crate", "1.0.0", {
features = "lsp,cli",
})
@@ -74,8 +74,8 @@ describe("cargo manager", function()
end)
it("should install git tag source", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
cargo.install("my-crate", "1.0.0", {
git = {
url = "https://github.com/neovim/neovim",
@@ -96,8 +96,8 @@ describe("cargo manager", function()
end)
it("should install git rev source", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
cargo.install("my-crate", "16dfc89abd413c391e5b63ae5d132c22843ce9a7", {
git = {
url = "https://github.com/neovim/neovim",
diff --git a/tests/mason-core/installer/managers/common_spec.lua b/tests/mason-core/installer/managers/common_spec.lua
index e72d7697..16d3ba52 100644
--- a/tests/mason-core/installer/managers/common_spec.lua
+++ b/tests/mason-core/installer/managers/common_spec.lua
@@ -7,6 +7,7 @@ local mock = require "luassert.mock"
local spy = require "luassert.spy"
local std = require "mason-core.installer.managers.std"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
describe("common manager :: download", function()
it("should parse download files from common structure", function()
@@ -54,11 +55,11 @@ describe("common manager :: download", function()
end)
it("should download files", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(std, "download_file", mockx.returns(Result.success()))
stub(std, "unpack", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return common.download_files(ctx, {
{ out_file = "file.jar", download_url = "https://example.com/file.jar" },
{ out_file = "LICENSE.md", download_url = "https://example.com/LICENSE" },
@@ -75,12 +76,12 @@ describe("common manager :: download", function()
end)
it("should download files to specified directory", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(std, "download_file", mockx.returns(Result.success()))
stub(std, "unpack", mockx.returns(Result.success()))
stub(ctx.fs, "mkdirp")
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return common.download_files(ctx, {
{ out_file = "lib/file.jar", download_url = "https://example.com/file.jar" },
{ out_file = "doc/LICENSE.md", download_url = "https://example.com/LICENSE" },
@@ -99,7 +100,7 @@ end)
describe("common manager :: build", function()
it("should run build instruction", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local uv = require "mason-core.async.uv"
spy.on(ctx, "promote_cwd")
stub(uv, "write")
@@ -115,7 +116,7 @@ describe("common manager :: build", function()
end
)
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return common.run_build_instruction {
run = [[npm install && npm run compile]],
env = {
@@ -143,11 +144,11 @@ describe("common manager :: build", function()
end)
it("should promote cwd if not staged", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx, "promote_cwd")
stub(ctx.spawn, "bash", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return common.run_build_instruction {
run = "make",
staged = false,
diff --git a/tests/mason-core/installer/managers/composer_spec.lua b/tests/mason-core/installer/managers/composer_spec.lua
index a8ccaffb..f3887c68 100644
--- a/tests/mason-core/installer/managers/composer_spec.lua
+++ b/tests/mason-core/installer/managers/composer_spec.lua
@@ -1,11 +1,11 @@
local composer = require "mason-core.installer.managers.composer"
-local installer = require "mason-core.installer"
local spy = require "luassert.spy"
+local test_helpers = require "mason-test.helpers"
describe("composer manager", function()
it("should install", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
composer.install("my-package", "1.0.0")
end)
@@ -22,10 +22,10 @@ describe("composer manager", function()
end)
it("should write output", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
spy.on(ctx.stdio_sink, "stdout")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
composer.install("my-package", "1.0.0")
end)
diff --git a/tests/mason-core/installer/managers/gem_spec.lua b/tests/mason-core/installer/managers/gem_spec.lua
index 7ac8c33e..83b8d96a 100644
--- a/tests/mason-core/installer/managers/gem_spec.lua
+++ b/tests/mason-core/installer/managers/gem_spec.lua
@@ -1,13 +1,15 @@
local gem = require "mason-core.installer.managers.gem"
-local installer = require "mason-core.installer"
local spy = require "luassert.spy"
+local test_helper = require "mason-test.helpers"
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")
+ local ctx = test_helper.create_context()
+
+ local result = ctx:execute(function()
+ return gem.install("my-gem", "1.0.0")
end)
+ assert.is_true(result:is_success())
assert.spy(ctx.spawn.gem).was_called(1)
assert.spy(ctx.spawn.gem).was_called_with {
@@ -20,15 +22,15 @@ describe("gem manager", function()
"my-gem:1.0.0",
vim.NIL, -- extra_packages
env = {
- GEM_HOME = ctx.cwd:get(),
+ GEM_HOME = "/tmp/install-dir",
},
}
end)
it("should write output", function()
- local ctx = create_dummy_context()
+ local ctx = test_helper.create_context()
spy.on(ctx.stdio_sink, "stdout")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
gem.install("my-gem", "1.0.0")
end)
@@ -36,8 +38,8 @@ describe("gem manager", function()
end)
it("should install extra packages", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helper.create_context()
+ ctx:execute(function()
gem.install("my-gem", "1.0.0", {
extra_packages = { "extra-gem" },
})
diff --git a/tests/mason-core/installer/managers/golang_spec.lua b/tests/mason-core/installer/managers/golang_spec.lua
index 58e4c4b8..e1a99cbd 100644
--- a/tests/mason-core/installer/managers/golang_spec.lua
+++ b/tests/mason-core/installer/managers/golang_spec.lua
@@ -1,12 +1,12 @@
local golang = require "mason-core.installer.managers.golang"
-local installer = require "mason-core.installer"
local spy = require "luassert.spy"
+local test_helpers = require "mason-test.helpers"
describe("golang manager", function()
it("should install", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
golang.install("my-golang", "1.0.0")
end)
@@ -22,10 +22,10 @@ describe("golang manager", function()
end)
it("should write output", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
spy.on(ctx.stdio_sink, "stdout")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
golang.install("my-golang", "1.0.0")
end)
@@ -33,8 +33,8 @@ describe("golang manager", function()
end)
it("should install extra packages", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
golang.install("my-golang", "1.0.0", {
extra_packages = { "extra", "package" },
})
diff --git a/tests/mason-core/installer/managers/luarocks_spec.lua b/tests/mason-core/installer/managers/luarocks_spec.lua
index 3be963a8..406c5c51 100644
--- a/tests/mason-core/installer/managers/luarocks_spec.lua
+++ b/tests/mason-core/installer/managers/luarocks_spec.lua
@@ -1,13 +1,23 @@
-local installer = require "mason-core.installer"
local luarocks = require "mason-core.installer.managers.luarocks"
local spy = require "luassert.spy"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
describe("luarocks manager", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx, "promote_cwd")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
luarocks.install("my-rock", "1.0.0")
end)
@@ -23,9 +33,9 @@ describe("luarocks manager", function()
end)
it("should install dev mode", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx, "promote_cwd")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
luarocks.install("my-rock", "1.0.0", {
dev = true,
})
@@ -43,9 +53,9 @@ describe("luarocks manager", function()
end)
it("should install using provided server", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx, "promote_cwd")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
luarocks.install("my-rock", "1.0.0", {
server = "https://luarocks.org/dev",
})
@@ -63,10 +73,10 @@ describe("luarocks manager", function()
end)
it("should write output", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx, "promote_cwd")
spy.on(ctx.stdio_sink, "stdout")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
luarocks.install("my-rock", "1.0.0")
end)
diff --git a/tests/mason-core/installer/managers/npm_spec.lua b/tests/mason-core/installer/managers/npm_spec.lua
index 59a8c84f..b2fabc80 100644
--- a/tests/mason-core/installer/managers/npm_spec.lua
+++ b/tests/mason-core/installer/managers/npm_spec.lua
@@ -1,21 +1,31 @@
local Result = require "mason-core.result"
-local installer = require "mason-core.installer"
local match = require "luassert.match"
local npm = require "mason-core.installer.managers.npm"
local spawn = require "mason-core.spawn"
local spy = require "luassert.spy"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
describe("npm manager", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should init package.json", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "append_file")
stub(spawn, "npm")
spawn.npm.returns(Result.success {})
spawn.npm.on_call_with({ "version", "--json" }).returns(Result.success {
stdout = [[ { "npm": "8.1.0" } ]],
})
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
npm.init()
end)
@@ -30,14 +40,14 @@ describe("npm manager", function()
end)
it("should use install-strategy on npm >= 9", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "append_file")
stub(spawn, "npm")
spawn.npm.returns(Result.success {})
spawn.npm.on_call_with({ "version", "--json" }).returns(Result.success {
stdout = [[ { "npm": "9.1.0" } ]],
})
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
npm.init()
end)
@@ -51,8 +61,8 @@ describe("npm manager", function()
end)
it("should install", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
npm.install("my-package", "1.0.0")
end)
@@ -65,8 +75,8 @@ describe("npm manager", function()
end)
it("should install extra packages", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
npm.install("my-package", "1.0.0", {
extra_packages = { "extra-package" },
})
@@ -81,10 +91,10 @@ describe("npm manager", function()
end)
it("should write output", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
spy.on(ctx.stdio_sink, "stdout")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
npm.install("my-package", "1.0.0")
end)
diff --git a/tests/mason-core/installer/managers/nuget_spec.lua b/tests/mason-core/installer/managers/nuget_spec.lua
index 8d4b0e87..fdfbdc82 100644
--- a/tests/mason-core/installer/managers/nuget_spec.lua
+++ b/tests/mason-core/installer/managers/nuget_spec.lua
@@ -1,11 +1,11 @@
-local installer = require "mason-core.installer"
local nuget = require "mason-core.installer.managers.nuget"
local spy = require "luassert.spy"
+local test_helpers = require "mason-test.helpers"
describe("nuget manager", function()
it("should install", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
nuget.install("nuget-package", "1.0.0")
end)
@@ -21,10 +21,10 @@ describe("nuget manager", function()
end)
it("should write output", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
spy.on(ctx.stdio_sink, "stdout")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
nuget.install("nuget-package", "1.0.0")
end)
diff --git a/tests/mason-core/installer/managers/opam_spec.lua b/tests/mason-core/installer/managers/opam_spec.lua
index cc552114..51f116e8 100644
--- a/tests/mason-core/installer/managers/opam_spec.lua
+++ b/tests/mason-core/installer/managers/opam_spec.lua
@@ -1,12 +1,12 @@
-local installer = require "mason-core.installer"
local opam = require "mason-core.installer.managers.opam"
local spy = require "luassert.spy"
+local test_helpers = require "mason-test.helpers"
describe("opam manager", function()
it("should install", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
opam.install("opam-package", "1.0.0")
end)
@@ -21,10 +21,10 @@ describe("opam manager", function()
end)
it("should write output", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
spy.on(ctx.stdio_sink, "stdout")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
opam.install("opam-package", "1.0.0")
end)
diff --git a/tests/mason-core/installer/managers/powershell_spec.lua b/tests/mason-core/installer/managers/powershell_spec.lua
index 86bbe1f9..14478305 100644
--- a/tests/mason-core/installer/managers/powershell_spec.lua
+++ b/tests/mason-core/installer/managers/powershell_spec.lua
@@ -1,3 +1,4 @@
+local a = require "mason-core.async"
local match = require "luassert.match"
local mock = require "luassert.mock"
local spawn = require "mason-core.spawn"
@@ -5,6 +6,16 @@ local spy = require "luassert.spy"
local stub = require "luassert.stub"
describe("powershell manager", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
local function powershell()
package.loaded["mason-core.installer.managers.powershell"] = nil
return require "mason-core.installer.managers.powershell"
@@ -22,21 +33,18 @@ describe("powershell manager", function()
assert.spy(spawn.powershell).was_called(0)
end)
- it(
- "should use powershell if pwsh is not available",
- async_test(function()
- stub(spawn, "pwsh", function() end)
- stub(spawn, "powershell", function() end)
- stub(vim.fn, "executable")
- vim.fn.executable.on_call_with("pwsh").returns(0)
+ it("should use powershell if pwsh is not available", function()
+ stub(spawn, "pwsh", function() end)
+ stub(spawn, "powershell", function() end)
+ stub(vim.fn, "executable")
+ vim.fn.executable.on_call_with("pwsh").returns(0)
- local powershell = powershell()
- powershell.command "echo 'Is this bash?'"
+ local powershell = powershell()
+ a.run_blocking(powershell.command, "echo 'Is this bash?'")
- assert.spy(spawn.pwsh).was_called(0)
- assert.spy(spawn.powershell).was_called(1)
- end)
- )
+ assert.spy(spawn.pwsh).was_called(0)
+ assert.spy(spawn.powershell).was_called(1)
+ end)
it("should use the provided spawner for commands", function()
spy.on(spawn, "pwsh")
diff --git a/tests/mason-core/installer/managers/pypi_spec.lua b/tests/mason-core/installer/managers/pypi_spec.lua
index 6689e350..f3a7e429 100644
--- a/tests/mason-core/installer/managers/pypi_spec.lua
+++ b/tests/mason-core/installer/managers/pypi_spec.lua
@@ -1,5 +1,4 @@
local Result = require "mason-core.result"
-local installer = require "mason-core.installer"
local match = require "luassert.match"
local path = require "mason-core.path"
local providers = require "mason-core.providers"
@@ -7,6 +6,7 @@ local pypi = require "mason-core.installer.managers.pypi"
local spawn = require "mason-core.spawn"
local spy = require "luassert.spy"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param ctx InstallContext
local function venv_py(ctx)
@@ -19,17 +19,24 @@ local function venv_py(ctx)
end
describe("pypi manager", function()
+ local snapshot
+
before_each(function()
+ snapshot = assert.snapshot()
stub(spawn, "python3", mockx.returns(Result.success()))
spawn.python3.on_call_with({ "--version" }).returns(Result.success { stdout = "Python 3.11.0" })
end)
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should init venv without upgrading pip", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx, "promote_cwd")
stub(providers.pypi, "get_supported_python_versions", mockx.returns(Result.failure()))
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
pypi.init { package = { name = "cmake-language-server", version = "0.1.10" }, upgrade_pip = false }
end)
@@ -44,13 +51,13 @@ describe("pypi manager", function()
end)
it("should init venv and upgrade pip", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx, "promote_cwd")
stub(ctx.fs, "file_exists")
stub(providers.pypi, "get_supported_python_versions", mockx.returns(Result.failure()))
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
pypi.init {
package = { name = "cmake-language-server", version = "0.1.10" },
upgrade_pip = true,
@@ -80,7 +87,7 @@ describe("pypi manager", function()
end)
it("should find versioned candidates during init", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx, "promote_cwd")
stub(ctx.fs, "file_exists")
stub(providers.pypi, "get_supported_python_versions", mockx.returns(Result.success ">=3.12"))
@@ -90,7 +97,7 @@ describe("pypi manager", function()
spawn["python3.12"].on_call_with({ "--version" }).returns(Result.success { stdout = "Python 3.12.0" })
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
pypi.init {
package = { name = "cmake-language-server", version = "0.1.10" },
upgrade_pip = false,
@@ -109,7 +116,7 @@ describe("pypi manager", function()
end)
it("should error if unable to find a suitable python3 version", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
spy.on(ctx.stdio_sink, "stderr")
stub(ctx, "promote_cwd")
stub(ctx.fs, "file_exists")
@@ -123,7 +130,7 @@ describe("pypi manager", function()
stub(spawn, "python3", mockx.returns(Result.success()))
spawn.python3.on_call_with({ "--version" }).returns(Result.success { stdout = "Python 3.5.0" })
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return pypi.init {
package = { name = "cmake-language-server", version = "0.1.10" },
upgrade_pip = false,
@@ -143,7 +150,7 @@ describe("pypi manager", function()
it(
"should default to stock version if unable to find suitable versioned candidate during init and when force=true",
function()
- local ctx = create_dummy_context { force = true }
+ local ctx = test_helpers.create_context { install_opts = { force = true } }
spy.on(ctx.stdio_sink, "stderr")
stub(ctx, "promote_cwd")
stub(ctx.fs, "file_exists")
@@ -157,7 +164,7 @@ describe("pypi manager", function()
stub(spawn, "python3", mockx.returns(Result.success()))
spawn.python3.on_call_with({ "--version" }).returns(Result.success { stdout = "Python 3.5.0" })
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
pypi.init {
package = { name = "cmake-language-server", version = "0.1.10" },
upgrade_pip = true,
@@ -180,7 +187,7 @@ describe("pypi manager", function()
)
it("should prioritize stock python", function()
- local ctx = create_dummy_context { force = true }
+ local ctx = test_helpers.create_context { install_opts = { force = true } }
spy.on(ctx.stdio_sink, "stderr")
stub(ctx, "promote_cwd")
stub(ctx.fs, "file_exists")
@@ -190,7 +197,7 @@ describe("pypi manager", function()
stub(spawn, "python3", mockx.returns(Result.success()))
spawn.python3.on_call_with({ "--version" }).returns(Result.success { stdout = "Python 3.8.0" })
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
pypi.init {
package = { name = "cmake-language-server", version = "0.1.10" },
upgrade_pip = true,
@@ -210,10 +217,11 @@ describe("pypi manager", function()
end)
it("should install", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)
- installer.exec_in_context(ctx, function()
+
+ ctx:execute(function()
pypi.install("pypi-package", "1.0.0")
end)
@@ -234,12 +242,12 @@ describe("pypi manager", function()
end)
it("should write output", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)
spy.on(ctx.stdio_sink, "stdout")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
pypi.install("pypi-package", "1.0.0")
end)
@@ -247,11 +255,11 @@ describe("pypi manager", function()
end)
it("should install extra specifier", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
pypi.install("pypi-package", "1.0.0", {
extra = "lsp",
})
@@ -274,10 +282,10 @@ describe("pypi manager", function()
end)
it("should install extra packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
pypi.install("pypi-package", "1.0.0", {
extra_packages = { "extra-package" },
install_extra_args = { "--proxy", "http://localhost:9000" },
diff --git a/tests/mason-core/installer/managers/std_spec.lua b/tests/mason-core/installer/managers/std_spec.lua
index dea342bc..20caac18 100644
--- a/tests/mason-core/installer/managers/std_spec.lua
+++ b/tests/mason-core/installer/managers/std_spec.lua
@@ -1,12 +1,22 @@
-local installer = require "mason-core.installer"
local match = require "luassert.match"
local std = require "mason-core.installer.managers.std"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
describe("std unpack [Unix]", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should unpack .gz", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
std.unpack "file.gz"
end)
@@ -21,12 +31,12 @@ describe("std unpack [Unix]", function()
end)
it("should use gtar if available", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "unlink")
stub(vim.fn, "executable")
vim.fn.executable.on_call_with("gtar").returns(1)
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
std.unpack "file.tar.gz"
end)
@@ -35,9 +45,9 @@ describe("std unpack [Unix]", function()
end)
it("should unpack .tar", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "unlink")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
std.unpack "file.tar"
end)
@@ -48,9 +58,9 @@ describe("std unpack [Unix]", function()
end)
it("should unpack .tar.bz2", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "unlink")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
std.unpack "file.tar.bz2"
end)
@@ -61,9 +71,9 @@ describe("std unpack [Unix]", function()
end)
it("should unpack .tar.gz", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "unlink")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
std.unpack "file.tar.gz"
end)
@@ -74,9 +84,9 @@ describe("std unpack [Unix]", function()
end)
it("should unpack .tar.xz", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "unlink")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
std.unpack "file.tar.xz"
end)
@@ -87,9 +97,9 @@ describe("std unpack [Unix]", function()
end)
it("should unpack .tar.zst", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "unlink")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
std.unpack "file.tar.zst"
end)
@@ -101,9 +111,9 @@ describe("std unpack [Unix]", function()
end)
it("should unpack .vsix", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "unlink")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
std.unpack "file.vsix"
end)
@@ -114,9 +124,9 @@ describe("std unpack [Unix]", function()
end)
it("should unpack .zip", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "unlink")
- installer.exec_in_context(ctx, function()
+ ctx:execute(function()
std.unpack "file.zip"
end)
@@ -129,8 +139,8 @@ end)
describe("std clone", function()
it("should clone", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
std.clone "https://github.com/williamboman/mason.nvim"
end)
@@ -146,8 +156,8 @@ describe("std clone", function()
end)
it("should clone and checkout rev", function()
- local ctx = create_dummy_context()
- installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context()
+ ctx:execute(function()
std.clone("https://github.com/williamboman/mason.nvim", {
rev = "e1fd03b1856cb5ad8425f49e18353dc524b02f91",
recursive = true,
diff --git a/tests/mason-core/installer/registry/providers/cargo_spec.lua b/tests/mason-core/installer/registry/compilers/cargo_spec.lua
index 1bdad5f4..69ac446d 100644
--- a/tests/mason-core/installer/registry/providers/cargo_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/cargo_spec.lua
@@ -1,9 +1,9 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local cargo = require "mason-core.installer.registry.providers.cargo"
-local installer = require "mason-core.installer"
+local cargo = require "mason-core.installer.compiler.compilers.cargo"
local providers = require "mason-core.providers"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -94,12 +94,22 @@ describe("cargo provider :: parsing", function()
end)
describe("cargo provider :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install cargo packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local manager = require "mason-core.installer.managers.cargo"
stub(manager, "install", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return cargo.install(ctx, {
crate = "crate-name",
version = "1.2.0",
@@ -120,6 +130,16 @@ describe("cargo provider :: installing", function()
end)
describe("cargo provider :: versions", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should recognize github cargo source", function()
stub(providers.github, "get_all_tags", function()
return Result.success { "1.0.0", "2.0.0", "3.0.0" }
diff --git a/tests/mason-core/installer/registry/providers/composer_spec.lua b/tests/mason-core/installer/registry/compilers/composer_spec.lua
index 8b771ff9..c184adf5 100644
--- a/tests/mason-core/installer/registry/providers/composer_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/composer_spec.lua
@@ -1,8 +1,8 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local composer = require "mason-core.installer.registry.providers.composer"
-local installer = require "mason-core.installer"
+local composer = require "mason-core.installer.compiler.compilers.composer"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -26,12 +26,22 @@ describe("composer provider :: parsing", function()
end)
describe("composer provider :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install composer packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local manager = require "mason-core.installer.managers.composer"
stub(manager, "install", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return composer.install(ctx, {
package = "vendor/package",
version = "1.2.0",
diff --git a/tests/mason-core/installer/registry/providers/gem_spec.lua b/tests/mason-core/installer/registry/compilers/gem_spec.lua
index 965cdbe8..b38bba33 100644
--- a/tests/mason-core/installer/registry/providers/gem_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/gem_spec.lua
@@ -1,8 +1,8 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local gem = require "mason-core.installer.registry.providers.gem"
-local installer = require "mason-core.installer"
+local gem = require "mason-core.installer.compiler.compilers.gem"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -31,12 +31,22 @@ describe("gem provider :: parsing", function()
end)
describe("gem provider :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install gem packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local manager = require "mason-core.installer.managers.gem"
stub(manager, "install", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return gem.install(ctx, {
package = "package",
version = "5.2.0",
diff --git a/tests/mason-core/installer/registry/providers/generic/build_spec.lua b/tests/mason-core/installer/registry/compilers/generic/build_spec.lua
index 443cb99a..8b8baeab 100644
--- a/tests/mason-core/installer/registry/providers/generic/build_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/generic/build_spec.lua
@@ -1,8 +1,8 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local generic = require "mason-core.installer.registry.providers.generic"
-local installer = require "mason-core.installer"
+local generic = require "mason-core.installer.compiler.compilers.generic"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -119,12 +119,22 @@ describe("generic provider :: build :: parsing", function()
end)
describe("generic provider :: build :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local common = require "mason-core.installer.managers.common"
stub(common, "run_build_instruction", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return generic.install(ctx, {
build = {
run = "make",
diff --git a/tests/mason-core/installer/registry/providers/generic/download_spec.lua b/tests/mason-core/installer/registry/compilers/generic/download_spec.lua
index 4bcb1976..4046d898 100644
--- a/tests/mason-core/installer/registry/providers/generic/download_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/generic/download_spec.lua
@@ -1,9 +1,9 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local generic = require "mason-core.installer.registry.providers.generic"
-local installer = require "mason-core.installer"
local match = require "luassert.match"
+local generic = require "mason-core.installer.compiler.compilers.generic"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -99,12 +99,22 @@ describe("generic provider :: download :: parsing", function()
end)
describe("generic provider :: download :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install generic packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local common = require "mason-core.installer.managers.common"
stub(common, "download_files", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return generic.install(ctx, {
downloads = {
{
diff --git a/tests/mason-core/installer/registry/providers/github/build_spec.lua b/tests/mason-core/installer/registry/compilers/github/build_spec.lua
index 17667d2c..0adc00fe 100644
--- a/tests/mason-core/installer/registry/providers/github/build_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/github/build_spec.lua
@@ -1,6 +1,6 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local github = require "mason-core.installer.registry.providers.github"
+local github = require "mason-core.installer.compiler.compilers.github"
---@param overrides Purl
local function purl(overrides)
diff --git a/tests/mason-core/installer/registry/providers/github/release_spec.lua b/tests/mason-core/installer/registry/compilers/github/release_spec.lua
index a6648b33..3cfbabc5 100644
--- a/tests/mason-core/installer/registry/providers/github/release_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/github/release_spec.lua
@@ -1,11 +1,11 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
local common = require "mason-core.installer.managers.common"
-local github = require "mason-core.installer.registry.providers.github"
-local installer = require "mason-core.installer"
+local compiler = require "mason-core.installer.compiler"
+local github = require "mason-core.installer.compiler.compilers.github"
local match = require "luassert.match"
-local registry_installer = require "mason-core.installer.registry"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -198,7 +198,7 @@ describe("github provider :: release :: parsing", function()
end)
it("should upsert version overrides", function()
- local result = registry_installer.parse({
+ local result = compiler.parse({
schema = "registry+v1",
source = {
id = "pkg:github/owner/repo@1.2.3",
@@ -252,7 +252,7 @@ describe("github provider :: release :: parsing", function()
end)
it("should override source if version override provides its own purl id", function()
- local result = registry_installer.parse({
+ local result = compiler.parse({
schema = "registry+v1",
source = {
id = "pkg:github/owner/repo@1.2.3",
@@ -280,14 +280,24 @@ describe("github provider :: release :: parsing", function()
end)
describe("github provider :: release :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install github release assets", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local std = require "mason-core.installer.managers.std"
stub(std, "download_file", mockx.returns(Result.success()))
stub(std, "unpack", mockx.returns(Result.success()))
stub(common, "download_files", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return github.install(ctx, {
repo = "namespace/name",
asset = {
diff --git a/tests/mason-core/installer/registry/providers/golang_spec.lua b/tests/mason-core/installer/registry/compilers/golang_spec.lua
index 6ba57272..8a3abc8a 100644
--- a/tests/mason-core/installer/registry/providers/golang_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/golang_spec.lua
@@ -1,8 +1,8 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local golang = require "mason-core.installer.registry.providers.golang"
-local installer = require "mason-core.installer"
+local golang = require "mason-core.installer.compiler.compilers.golang"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -27,12 +27,22 @@ describe("golang provider :: parsing", function()
end)
describe("golang provider :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install golang packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local manager = require "mason-core.installer.managers.golang"
stub(manager, "install", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return golang.install(ctx, {
package = "namespace/package",
version = "v1.5.0",
diff --git a/tests/mason-core/installer/registry/providers/luarocks_spec.lua b/tests/mason-core/installer/registry/compilers/luarocks_spec.lua
index 0a4ea9ad..b8642fcf 100644
--- a/tests/mason-core/installer/registry/providers/luarocks_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/luarocks_spec.lua
@@ -1,9 +1,9 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local installer = require "mason-core.installer"
-local luarocks = require "mason-core.installer.registry.providers.luarocks"
+local luarocks = require "mason-core.installer.compiler.compilers.luarocks"
local match = require "luassert.match"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -53,13 +53,23 @@ describe("luarocks provider :: parsing", function()
end)
describe("luarocks provider :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install luarocks packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_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()
+ local result = ctx:execute(function()
return luarocks.install(ctx, {
package = "namespace/name",
version = "1.0.0",
diff --git a/tests/mason-core/installer/registry/providers/npm_spec.lua b/tests/mason-core/installer/registry/compilers/npm_spec.lua
index b39d092a..680df5bc 100644
--- a/tests/mason-core/installer/registry/providers/npm_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/npm_spec.lua
@@ -1,8 +1,8 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local installer = require "mason-core.installer"
-local npm = require "mason-core.installer.registry.providers.npm"
+local npm = require "mason-core.installer.compiler.compilers.npm"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -27,13 +27,23 @@ describe("npm provider :: parsing", function()
end)
describe("npm provider :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install npm packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_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()
+ local result = ctx:execute(function()
return npm.install(ctx, {
package = "@namespace/package",
version = "v1.5.0",
diff --git a/tests/mason-core/installer/registry/providers/nuget_spec.lua b/tests/mason-core/installer/registry/compilers/nuget_spec.lua
index 2437d8de..f514e666 100644
--- a/tests/mason-core/installer/registry/providers/nuget_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/nuget_spec.lua
@@ -1,8 +1,8 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local installer = require "mason-core.installer"
-local nuget = require "mason-core.installer.registry.providers.nuget"
+local nuget = require "mason-core.installer.compiler.compilers.nuget"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -26,12 +26,22 @@ describe("nuget provider :: parsing", function()
end)
describe("nuget provider :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install nuget packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local manager = require "mason-core.installer.managers.nuget"
stub(manager, "install", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return nuget.install(ctx, {
package = "package",
version = "1.5.0",
diff --git a/tests/mason-core/installer/registry/providers/opam_spec.lua b/tests/mason-core/installer/registry/compilers/opam_spec.lua
index c0f73b02..c2c7638e 100644
--- a/tests/mason-core/installer/registry/providers/opam_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/opam_spec.lua
@@ -1,8 +1,8 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local installer = require "mason-core.installer"
-local opam = require "mason-core.installer.registry.providers.opam"
+local opam = require "mason-core.installer.compiler.compilers.opam"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -26,12 +26,22 @@ describe("opam provider :: parsing", function()
end)
describe("opam provider :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install opam packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local manager = require "mason-core.installer.managers.opam"
stub(manager, "install", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return opam.install(ctx, {
package = "package",
version = "1.5.0",
diff --git a/tests/mason-core/installer/registry/providers/openvsx_spec.lua b/tests/mason-core/installer/registry/compilers/openvsx_spec.lua
index 1452ea0f..d3868a69 100644
--- a/tests/mason-core/installer/registry/providers/openvsx_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/openvsx_spec.lua
@@ -1,10 +1,10 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
local common = require "mason-core.installer.managers.common"
-local installer = require "mason-core.installer"
local match = require "luassert.match"
-local openvsx = require "mason-core.installer.registry.providers.openvsx"
+local openvsx = require "mason-core.installer.compiler.compilers.openvsx"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -117,13 +117,10 @@ end)
describe("openvsx provider :: download :: installing", function()
it("should install openvsx 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 ctx = test_helpers.create_context()
stub(common, "download_files", mockx.returns(Result.success()))
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return openvsx.install(ctx, {
download = {
file = "file-1.10.1.jar",
diff --git a/tests/mason-core/installer/registry/providers/pypi_spec.lua b/tests/mason-core/installer/registry/compilers/pypi_spec.lua
index 539ba53b..61742b4e 100644
--- a/tests/mason-core/installer/registry/providers/pypi_spec.lua
+++ b/tests/mason-core/installer/registry/compilers/pypi_spec.lua
@@ -1,9 +1,9 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
-local installer = require "mason-core.installer"
-local pypi = require "mason-core.installer.registry.providers.pypi"
+local pypi = require "mason-core.installer.compiler.compilers.pypi"
local settings = require "mason.settings"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
---@param overrides Purl
local function purl(overrides)
@@ -44,8 +44,18 @@ describe("pypi provider :: parsing", function()
end)
describe("pypi provider :: installing", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should install pypi packages", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
local manager = require "mason-core.installer.managers.pypi"
stub(manager, "init", mockx.returns(Result.success()))
stub(manager, "install", mockx.returns(Result.success()))
@@ -56,7 +66,7 @@ describe("pypi provider :: installing", function()
},
}
- local result = installer.exec_in_context(ctx, function()
+ local result = ctx:execute(function()
return pypi.install(ctx, {
package = "package",
extra = "lsp",
diff --git a/tests/mason-core/installer/registry/expr_spec.lua b/tests/mason-core/installer/registry/expr_spec.lua
index 65994dfa..944a5983 100644
--- a/tests/mason-core/installer/registry/expr_spec.lua
+++ b/tests/mason-core/installer/registry/expr_spec.lua
@@ -1,6 +1,6 @@
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
-local expr = require "mason-core.installer.registry.expr"
+local expr = require "mason-core.installer.compiler.expr"
local match = require "luassert.match"
describe("registry expressions", function()
diff --git a/tests/mason-core/installer/registry/installer_spec.lua b/tests/mason-core/installer/registry/installer_spec.lua
index 51d9035e..93c91444 100644
--- a/tests/mason-core/installer/registry/installer_spec.lua
+++ b/tests/mason-core/installer/registry/installer_spec.lua
@@ -1,12 +1,13 @@
local Result = require "mason-core.result"
-local installer = require "mason-core.installer.registry"
+local compiler = require "mason-core.installer.compiler"
local match = require "luassert.match"
local spy = require "luassert.spy"
local stub = require "luassert.stub"
-local util = require "mason-core.installer.registry.util"
+local test_helpers = require "mason-test.helpers"
+local util = require "mason-core.installer.compiler.util"
----@type InstallerProvider
-local dummy_provider = {
+---@type InstallerCompiler
+local dummy_compiler = {
---@param source RegistryPackageSource
---@param purl Purl
---@param opts PackageInstallOpts
@@ -36,9 +37,9 @@ local dummy_provider = {
describe("registry installer :: parsing", function()
it("should parse valid package specs", function()
- installer.register_provider("dummy", dummy_provider)
+ compiler.register_compiler("dummy", dummy_compiler)
- local result = installer.parse({
+ local result = compiler.parse({
schema = "registry+v1",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -48,7 +49,7 @@ describe("registry installer :: parsing", function()
local parsed = result:get_or_nil()
assert.is_true(result:is_success())
- assert.is_true(match.is_ref(dummy_provider)(parsed.provider))
+ assert.is_true(match.is_ref(dummy_compiler)(parsed.compiler))
assert.same({
name = "package-name",
scheme = "pkg",
@@ -63,9 +64,9 @@ describe("registry installer :: parsing", function()
end)
it("should keep unmapped fields", function()
- installer.register_provider("dummy", dummy_provider)
+ compiler.register_compiler("dummy", dummy_compiler)
- local result = installer.parse({
+ local result = compiler.parse({
schema = "registry+v1",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -83,9 +84,9 @@ describe("registry installer :: parsing", function()
end)
it("should reject incompatible schema versions", function()
- installer.register_provider("dummy", dummy_provider)
+ compiler.register_compiler("dummy", dummy_compiler)
- local result = installer.parse({
+ local result = compiler.parse({
schema = "registry+v1337",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -98,9 +99,9 @@ describe("registry installer :: parsing", function()
end)
it("should use requested version", function()
- installer.register_provider("dummy", dummy_provider)
+ compiler.register_compiler("dummy", dummy_compiler)
- local result = installer.parse({
+ local result = compiler.parse({
schema = "registry+v1",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -119,9 +120,9 @@ describe("registry installer :: parsing", function()
end)
it("should handle PLATFORM_UNSUPPORTED", function()
- installer.register_provider("dummy", dummy_provider)
+ compiler.register_compiler("dummy", dummy_compiler)
- local result = installer.compile({
+ local result = compiler.compile({
schema = "registry+v1",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -133,9 +134,9 @@ describe("registry installer :: parsing", function()
end)
it("should error upon parsing failures", function()
- installer.register_provider("dummy", dummy_provider)
+ compiler.register_compiler("dummy", dummy_compiler)
- local result = installer.compile({
+ local result = compiler.compile({
schema = "registry+v1",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -148,14 +149,24 @@ describe("registry installer :: parsing", function()
end)
describe("registry installer :: compiling", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should run compiled installer function successfully", function()
- installer.register_provider("dummy", dummy_provider)
- spy.on(dummy_provider, "get_versions")
+ compiler.register_compiler("dummy", dummy_compiler)
+ spy.on(dummy_compiler, "get_versions")
---@type PackageInstallOpts
local opts = {}
- local result = installer.compile({
+ local result = compiler.compile({
schema = "registry+v1",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -165,21 +176,21 @@ describe("registry installer :: compiling", function()
assert.is_true(result:is_success())
local installer_fn = result:get_or_throw()
- local ctx = create_dummy_context(opts)
- local installer_result = require("mason-core.installer").exec_in_context(ctx, installer_fn)
+ local ctx = test_helpers.create_context()
+ local installer_result = ctx:execute(installer_fn)
assert.same(Result.success(), installer_result)
- assert.spy(dummy_provider.get_versions).was_not_called()
+ assert.spy(dummy_compiler.get_versions).was_not_called()
end)
it("should ensure valid version", function()
- installer.register_provider("dummy", dummy_provider)
- spy.on(dummy_provider, "get_versions")
+ compiler.register_compiler("dummy", dummy_compiler)
+ spy.on(dummy_compiler, "get_versions")
---@type PackageInstallOpts
local opts = { version = "v2.0.0" }
- local result = installer.compile({
+ local result = compiler.compile({
schema = "registry+v1",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -189,12 +200,12 @@ describe("registry installer :: compiling", function()
assert.is_true(result:is_success())
local installer_fn = result:get_or_throw()
- local ctx = create_dummy_context(opts)
- local installer_result = require("mason-core.installer").exec_in_context(ctx, installer_fn)
+ local ctx = test_helpers.create_context { install_opts = opts }
+ local installer_result = ctx:execute(installer_fn)
assert.same(Result.success(), installer_result)
- assert.spy(dummy_provider.get_versions).was_called(1)
- assert.spy(dummy_provider.get_versions).was_called_with({
+ assert.spy(dummy_compiler.get_versions).was_called(1)
+ assert.spy(dummy_compiler.get_versions).was_called_with({
name = "package-name",
scheme = "pkg",
type = "dummy",
@@ -205,13 +216,13 @@ describe("registry installer :: compiling", function()
end)
it("should reject invalid version", function()
- installer.register_provider("dummy", dummy_provider)
- spy.on(dummy_provider, "get_versions")
+ compiler.register_compiler("dummy", dummy_compiler)
+ spy.on(dummy_compiler, "get_versions")
---@type PackageInstallOpts
local opts = { version = "v13.3.7" }
- local result = installer.compile({
+ local result = compiler.compile({
schema = "registry+v1",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -221,14 +232,14 @@ describe("registry installer :: compiling", function()
assert.is_true(result:is_success())
local installer_fn = result:get_or_throw()
- local ctx = create_dummy_context(opts)
+ local ctx = test_helpers.create_context { install_opts = opts }
local err = assert.has_error(function()
- require("mason-core.installer").exec_in_context(ctx, installer_fn)
+ ctx:execute(installer_fn)
end)
assert.equals([[Version "v13.3.7" is not available.]], err)
- assert.spy(dummy_provider.get_versions).was_called(1)
- assert.spy(dummy_provider.get_versions).was_called_with({
+ assert.spy(dummy_compiler.get_versions).was_called(1)
+ assert.spy(dummy_compiler.get_versions).was_called_with({
name = "package-name",
scheme = "pkg",
type = "dummy",
@@ -239,12 +250,12 @@ describe("registry installer :: compiling", function()
end)
it("should raise errors upon installer failures", function()
- installer.register_provider("dummy", dummy_provider)
+ compiler.register_compiler("dummy", dummy_compiler)
---@type PackageInstallOpts
local opts = {}
- local result = installer.compile({
+ local result = compiler.compile({
schema = "registry+v1",
source = {
id = "pkg:dummy/package-name@v1.2.3",
@@ -255,16 +266,16 @@ describe("registry installer :: compiling", function()
assert.is_true(result:is_success())
local installer_fn = result:get_or_nil()
- local ctx = create_dummy_context(opts)
+ local ctx = test_helpers.create_context()
local err = assert.has_error(function()
- require("mason-core.installer").exec_in_context(ctx, installer_fn)
+ ctx:execute(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"
+ compiler.register_compiler("dummy", dummy_compiler)
+ local link = require "mason-core.installer.compiler.link"
stub(link, "bin", mockx.returns(Result.success()))
stub(link, "share", mockx.returns(Result.success()))
stub(link, "opt", mockx.returns(Result.success()))
@@ -281,13 +292,13 @@ describe("registry installer :: compiling", function()
---@type PackageInstallOpts
local opts = {}
- local result = installer.compile(spec, opts)
+ local result = compiler.compile(spec, opts)
assert.is_true(result:is_success())
local installer_fn = result:get_or_nil()
- local ctx = create_dummy_context(opts)
- local installer_result = require("mason-core.installer").exec_in_context(ctx, installer_fn)
+ local ctx = test_helpers.create_context()
+ local installer_result = ctx:execute(installer_fn)
assert.is_true(installer_result:is_success())
for _, spy in ipairs { link.bin, link.share, link.opt } do
diff --git a/tests/mason-core/installer/registry/link_spec.lua b/tests/mason-core/installer/registry/link_spec.lua
index eb6af1cc..62777bc9 100644
--- a/tests/mason-core/installer/registry/link_spec.lua
+++ b/tests/mason-core/installer/registry/link_spec.lua
@@ -1,14 +1,25 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
local fs = require "mason-core.fs"
-local link = require "mason-core.installer.registry.link"
+local link = require "mason-core.installer.compiler.link"
local match = require "luassert.match"
local path = require "mason-core.path"
local stub = require "luassert.stub"
+local test_helpers = require "mason-test.helpers"
describe("registry linker", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
it("should expand bin table", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
stub(ctx.fs, "chmod")
stub(ctx.fs, "fstat")
@@ -45,7 +56,7 @@ describe("registry linker", function()
end)
it("should chmod executable if necessary", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
stub(ctx.fs, "chmod")
stub(ctx.fs, "fstat")
@@ -74,7 +85,7 @@ describe("registry linker", function()
end)
it("should interpolate bin table", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
stub(ctx.fs, "chmod")
stub(ctx.fs, "fstat")
@@ -106,7 +117,7 @@ describe("registry linker", function()
end)
it("should delegate bin paths", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
stub(ctx.fs, "chmod")
stub(ctx.fs, "fstat")
@@ -144,7 +155,7 @@ describe("registry linker", function()
end)
it("should register share links", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
stub(fs.sync, "file_exists")
stub(vim.fn, "glob")
@@ -192,7 +203,7 @@ describe("registry linker", function()
end)
it("should register opt links", function()
- local ctx = create_dummy_context()
+ local ctx = test_helpers.create_context()
stub(ctx.fs, "file_exists")
stub(fs.sync, "file_exists")
stub(vim.fn, "glob")
diff --git a/tests/mason-core/installer/registry/util_spec.lua b/tests/mason-core/installer/registry/util_spec.lua
index 851164d0..be687f36 100644
--- a/tests/mason-core/installer/registry/util_spec.lua
+++ b/tests/mason-core/installer/registry/util_spec.lua
@@ -1,8 +1,8 @@
local Result = require "mason-core.result"
-local installer = require "mason-core.installer"
local match = require "luassert.match"
local platform = require "mason-core.platform"
-local util = require "mason-core.installer.registry.util"
+local test_helpers = require "mason-test.helpers"
+local util = require "mason-core.installer.compiler.util"
describe("registry installer util", function()
it("should coalesce single target", function()
@@ -40,8 +40,8 @@ describe("registry installer util", function()
end)
it("should accept valid version", function()
- local ctx = create_dummy_context { version = "1.0.0" }
- local result = installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context { install_opts = { version = "1.0.0" } }
+ local result = ctx:execute(function()
return util.ensure_valid_version(function()
return Result.success { "1.0.0", "2.0.0", "3.0.0" }
end)
@@ -50,8 +50,8 @@ describe("registry installer util", function()
end)
it("should reject invalid version", function()
- local ctx = create_dummy_context { version = "13.3.7" }
- local result = installer.exec_in_context(ctx, function()
+ local ctx = test_helpers.create_context { install_opts = { version = "13.3.7" } }
+ local result = ctx:execute(function()
return util.ensure_valid_version(function()
return Result.success { "1.0.0", "2.0.0", "3.0.0" }
end)
@@ -60,8 +60,8 @@ describe("registry installer util", function()
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()
+ local ctx = test_helpers.create_context { install_opts = { version = "13.3.7" } }
+ local result = ctx:execute(function()
return util.ensure_valid_version(function()
return Result.failure()
end)
@@ -70,8 +70,8 @@ describe("registry installer util", function()
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()
+ local ctx = test_helpers.create_context { install_opts = { version = "13.3.7", force = true } }
+ local result = ctx:execute(function()
return util.ensure_valid_version(function()
return Result.success { "1.0.0" }
end)
diff --git a/tests/mason-core/installer/runner_spec.lua b/tests/mason-core/installer/runner_spec.lua
new file mode 100644
index 00000000..b39a75ac
--- /dev/null
+++ b/tests/mason-core/installer/runner_spec.lua
@@ -0,0 +1,300 @@
+local InstallHandle = require "mason-core.installer.handle"
+local InstallLocation = require "mason-core.installer.location"
+local InstallRunner = require "mason-core.installer.runner"
+local fs = require "mason-core.fs"
+local match = require "luassert.match"
+local spy = require "luassert.spy"
+local stub = require "luassert.stub"
+local Semaphore = require("mason-core.async.control").Semaphore
+local a = require "mason-core.async"
+local registry = require "mason-registry"
+local settings = require "mason.settings"
+
+describe("install runner ::", function()
+ local dummy = registry.get_package "dummy"
+ local dummy2 = registry.get_package "dummy2"
+
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
+ before_each(function()
+ dummy:uninstall()
+ dummy2:uninstall()
+ end)
+
+ describe("locking ::", function()
+ it("should respect semaphore locks", function()
+ local semaphore = Semaphore.new(1)
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local dummy_handle = InstallHandle.new(dummy)
+ local runner_1 = InstallRunner.new(location, dummy_handle, semaphore)
+ local runner_2 = InstallRunner.new(location, InstallHandle.new(dummy2), semaphore)
+
+ stub(dummy.spec.source, "install", function()
+ a.sleep(10000)
+ end)
+ spy.on(dummy2.spec.source, "install")
+
+ runner_1:execute {}
+ runner_2:execute {}
+
+ assert.wait(function()
+ assert.spy(dummy.spec.source.install).was_called(1)
+ assert.spy(dummy2.spec.source.install).was_not_called()
+ end)
+
+ dummy_handle:terminate()
+
+ assert.wait(function()
+ assert.spy(dummy2.spec.source.install).was_called(1)
+ end)
+ end)
+
+ it("should write lockfile", function()
+ local semaphore = Semaphore.new(1)
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local dummy_handle = InstallHandle.new(dummy)
+ local runner = InstallRunner.new(location, dummy_handle, semaphore)
+
+ spy.on(fs.async, "write_file")
+
+ runner:execute {}
+
+ assert.wait(function()
+ assert.spy(fs.async.write_file).was_called_with(location:lockfile(dummy.name), vim.fn.getpid())
+ end)
+ end)
+
+ it("should abort installation if installation lock exists", function()
+ local semaphore = Semaphore.new(1)
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local dummy_handle = InstallHandle.new(dummy)
+ local runner = InstallRunner.new(location, dummy_handle, semaphore)
+
+ stub(fs.async, "file_exists")
+ stub(fs.async, "read_file")
+ fs.async.file_exists.on_call_with(location:lockfile(dummy.name)).returns(true)
+ fs.async.read_file.on_call_with(location:lockfile(dummy.name)).returns "1337"
+
+ local callback = spy.new()
+ runner:execute({}, callback)
+
+ assert.wait(function()
+ assert.spy(callback).was_called()
+ assert.spy(callback).was_called_with(
+ false,
+ "Lockfile exists, installation is already running in another process (pid: 1337). Run with :MasonInstall --force to bypass."
+ )
+ end)
+ end)
+
+ it("should not abort installation if installation lock exists with force=true", function()
+ local semaphore = Semaphore.new(1)
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local dummy_handle = InstallHandle.new(dummy)
+ local runner = InstallRunner.new(location, dummy_handle, semaphore)
+
+ stub(fs.async, "file_exists")
+ stub(fs.async, "read_file")
+ fs.async.file_exists.on_call_with(location:lockfile(dummy.name)).returns(true)
+ fs.async.read_file.on_call_with(location:lockfile(dummy.name)).returns "1337"
+
+ local callback = spy.new()
+ runner:execute({ force = true }, callback)
+
+ assert.wait(function()
+ assert.spy(callback).was_called()
+ assert.spy(callback).was_called_with(true, nil)
+ end)
+ end)
+
+ it("should release lock after successful installation", function()
+ local semaphore = Semaphore.new(1)
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local dummy_handle = InstallHandle.new(dummy)
+ local runner = InstallRunner.new(location, dummy_handle, semaphore)
+
+ local callback = spy.new()
+ runner:execute({}, callback)
+
+ assert.wait(function()
+ assert.is_true(fs.sync.file_exists(location:lockfile(dummy.name)))
+ end)
+ assert.wait(function()
+ assert.spy(callback).was_called()
+ end)
+ assert.is_false(fs.sync.file_exists(location:lockfile(dummy.name)))
+ end)
+ end)
+
+ it("should initialize install location", function()
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local runner = InstallRunner.new(location, InstallHandle.new(registry.get_package "dummy"), Semaphore.new(1))
+
+ spy.on(location, "initialize")
+
+ runner:execute {}
+
+ assert.wait(function()
+ assert.spy(location.initialize).was_called(1)
+ end)
+ end)
+
+ describe("receipt ::", function()
+ it("should write receipt", function()
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local runner =
+ InstallRunner.new(location, InstallHandle.new(registry.get_package "dummy"), Semaphore.new(1))
+
+ runner:execute {}
+
+ assert.wait(function()
+ local receipt_file = location:package "dummy/mason-receipt.json"
+ assert.is_true(fs.sync.file_exists(receipt_file))
+ assert.is_true(match.tbl_containing {
+ name = "dummy",
+ schema_version = "1.2",
+ metrics = match.tbl_containing {
+ completion_time = match.is_number(),
+ start_time = match.is_number(),
+ },
+ source = match.same {
+ id = "pkg:mason/dummy@1.0.0",
+ type = "registry+v1",
+ },
+ links = match.same {
+ bin = {},
+ opt = {},
+ share = {},
+ },
+ }(vim.json.decode(fs.sync.read_file(receipt_file))))
+ end)
+ end)
+ end)
+
+ it("should emit failures", function()
+ local registry_spy = spy.new()
+ local package_spy = spy.new()
+ registry:once("package:install:failed", registry_spy)
+ dummy:once("install:failed", package_spy)
+
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local handle = InstallHandle.new(registry.get_package "dummy")
+ local runner = InstallRunner.new(location, handle, Semaphore.new(1))
+
+ stub(dummy.spec.source, "install", function()
+ error("I've made a mistake.", 0)
+ end)
+
+ local callback = spy.new()
+ runner:execute({}, callback)
+
+ assert.wait(function()
+ assert.spy(registry_spy).was_called(1)
+ assert.spy(registry_spy).was_called_with(match.is_ref(dummy), match.is_ref(handle), "I've made a mistake.")
+ assert.spy(package_spy).was_called(1)
+ assert.spy(package_spy).was_called_with(match.is_ref(handle), "I've made a mistake.")
+
+ assert.spy(callback).was_called(1)
+ assert.spy(callback).was_called_with(false, "I've made a mistake.")
+ end, 10)
+ end)
+
+ it("should terminate installation", function()
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local handle = InstallHandle.new(registry.get_package "dummy")
+ local runner = InstallRunner.new(location, handle, Semaphore.new(1))
+
+ local capture = spy.new()
+ stub(dummy.spec.source, "install", function()
+ capture()
+ handle:terminate()
+ a.sleep(0)
+ capture()
+ end)
+
+ local callback = spy.new()
+
+ runner:execute({}, callback)
+
+ assert.wait(function()
+ assert.spy(callback).was_called(1)
+ assert.spy(callback).was_called_with(false, "Installation was aborted.")
+
+ assert.spy(capture).was_called(1)
+ end)
+ end)
+
+ it("should write debug logs when debug=true", function()
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local handle = InstallHandle.new(registry.get_package "dummy")
+ local runner = InstallRunner.new(location, handle, Semaphore.new(1))
+
+ stub(dummy.spec.source, "install", function(ctx)
+ ctx.stdio_sink.stdout "Hello "
+ ctx.stdio_sink.stderr "world!"
+ end)
+
+ local callback = spy.new()
+ runner:execute({ debug = true }, callback)
+
+ assert.wait(function()
+ assert.spy(callback).was_called()
+ assert.spy(callback).was_called_with(true, nil)
+ end)
+ assert.is_true(fs.sync.file_exists(location:package "dummy/mason-debug.log"))
+ assert.equals("Hello world!", fs.sync.read_file(location:package "dummy/mason-debug.log"))
+ end)
+
+ it("should not retain installation directory on failure", function()
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local handle = InstallHandle.new(registry.get_package "dummy")
+ local runner = InstallRunner.new(location, handle, Semaphore.new(1))
+
+ stub(dummy.spec.source, "install", function(ctx)
+ ctx.stdio_sink.stderr "Something will go terribly wrong.\n"
+ error("This went terribly wrong.", 0)
+ end)
+
+ local callback = spy.new()
+ runner:execute({}, callback)
+
+ assert.wait(function()
+ assert.spy(callback).was_called()
+ assert.spy(callback).was_called_with(false, "This went terribly wrong.")
+ end)
+ assert.is_false(fs.sync.dir_exists(location:staging "dummy"))
+ assert.is_false(fs.sync.dir_exists(location:package "dummy"))
+ end)
+
+ it("should retain installation directory on failure and debug=true", function()
+ local location = InstallLocation.new(settings.current.install_root_dir)
+ local handle = InstallHandle.new(registry.get_package "dummy")
+ local runner = InstallRunner.new(location, handle, Semaphore.new(1))
+
+ stub(dummy.spec.source, "install", function(ctx)
+ ctx.stdio_sink.stderr "Something will go terribly wrong.\n"
+ error("This went terribly wrong.", 0)
+ end)
+
+ local callback = spy.new()
+ runner:execute({ debug = true }, callback)
+
+ assert.wait(function()
+ assert.spy(callback).was_called()
+ assert.spy(callback).was_called_with(false, "This went terribly wrong.")
+ end)
+ assert.is_true(fs.sync.dir_exists(location:staging "dummy"))
+ assert.equals(
+ "Something will go terribly wrong.\nThis went terribly wrong.\n",
+ fs.sync.read_file(location:staging "dummy/mason-debug.log")
+ )
+ end)
+end)
diff --git a/tests/mason-core/package/package_spec.lua b/tests/mason-core/package/package_spec.lua
index 67d49387..622a2ee4 100644
--- a/tests/mason-core/package/package_spec.lua
+++ b/tests/mason-core/package/package_spec.lua
@@ -7,6 +7,16 @@ local spy = require "luassert.spy"
local stub = require "luassert.stub"
describe("package", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
before_each(function()
registry.get_package("dummy"):uninstall()
package.loaded["dummy_package"] = nil
@@ -37,7 +47,7 @@ describe("package", function()
source = {
id = "pkg:mason/package@1",
install = function() end,
- }
+ },
}
local function spec(fields)
return setmetatable(fields, { __index = valid_spec })
@@ -105,26 +115,25 @@ describe("package", function()
dummy.handle = nil
end)
- it(
- "should successfully install package",
- async_test(function()
- local dummy = registry.get_package "dummy"
- local package_install_success_handler = spy.new()
- local package_install_failed_handler = spy.new()
- local install_success_handler = spy.new()
- local install_failed_handler = spy.new()
- registry:once("package:install:success", package_install_success_handler)
- registry:once("package:install:failed", package_install_failed_handler)
- dummy:once("install:success", install_success_handler)
- dummy:once("install:failed", install_failed_handler)
+ it("should successfully install package", function()
+ local dummy = registry.get_package "dummy"
+ local package_install_success_handler = spy.new()
+ local package_install_failed_handler = spy.new()
+ local install_success_handler = spy.new()
+ local install_failed_handler = spy.new()
+ registry:once("package:install:success", package_install_success_handler)
+ registry:once("package:install:failed", package_install_failed_handler)
+ dummy:once("install:success", install_success_handler)
+ dummy:once("install:failed", install_failed_handler)
- local handle = dummy:install { version = "1337" }
+ local handle = dummy:install { version = "1337" }
- assert.wait_for(function()
- assert.is_true(handle:is_closed())
- assert.is_true(dummy:is_installed())
- end)
+ assert.wait(function()
+ assert.is_true(handle:is_closed())
+ assert.is_true(dummy:is_installed())
+ end)
+ assert.wait(function()
assert.spy(install_success_handler).was_called(1)
assert.spy(install_success_handler).was_called_with(match.is_ref(handle))
assert.spy(package_install_success_handler).was_called(1)
@@ -132,45 +141,45 @@ describe("package", function()
assert.spy(package_install_failed_handler).was_called(0)
assert.spy(install_failed_handler).was_called(0)
end)
- )
+ end)
- it(
- "should fail to install package",
- async_test(function()
- local dummy = registry.get_package "dummy"
- stub(dummy.spec.source, "install", function()
- error "I simply refuse to be installed."
- end)
- local package_install_success_handler = spy.new()
- local package_install_failed_handler = spy.new()
- local install_success_handler = spy.new()
- local install_failed_handler = spy.new()
- registry:once("package:install:success", package_install_success_handler)
- registry:once("package:install:failed", package_install_failed_handler)
- dummy:once("install:success", install_success_handler)
- dummy:once("install:failed", install_failed_handler)
+ it("should fail to install package", function()
+ local dummy = registry.get_package "dummy"
+ stub(dummy.spec.source, "install", function()
+ error("I simply refuse to be installed.", 0)
+ end)
+ local package_install_success_handler = spy.new()
+ local package_install_failed_handler = spy.new()
+ local install_success_handler = spy.new()
+ local install_failed_handler = spy.new()
+ registry:once("package:install:success", package_install_success_handler)
+ registry:once("package:install:failed", package_install_failed_handler)
+ dummy:once("install:success", install_success_handler)
+ dummy:once("install:failed", install_failed_handler)
- local handle = dummy:install { version = "1337" }
+ local handle = dummy:install { version = "1337" }
- assert.wait_for(function()
- assert.is_true(handle:is_closed())
- assert.is_false(dummy:is_installed())
- end)
+ assert.wait(function()
+ assert.is_true(handle:is_closed())
+ assert.is_false(dummy:is_installed())
+ end)
+ assert.wait(function()
assert.spy(install_failed_handler).was_called(1)
- assert.spy(install_failed_handler).was_called_with(match.is_ref(handle))
+ assert.spy(install_failed_handler).was_called_with(match.is_ref(handle), "I simply refuse to be installed.")
assert.spy(package_install_failed_handler).was_called(1)
- assert.spy(package_install_failed_handler).was_called_with(match.is_ref(dummy), match.is_ref(handle))
+ assert
+ .spy(package_install_failed_handler)
+ .was_called_with(match.is_ref(dummy), match.is_ref(handle), "I simply refuse to be installed.")
assert.spy(package_install_success_handler).was_called(0)
assert.spy(install_success_handler).was_called(0)
end)
- )
+ end)
- it(
- "should be able to start package installation outside of main loop",
- async_test(function()
- local dummy = registry.get_package "dummy"
+ it("should be able to start package installation outside of main loop", function()
+ local dummy = registry.get_package "dummy"
+ local handle = a.run_blocking(function()
-- Move outside the main loop
a.wait(function(resolve)
local timer = vim.loop.new_timer()
@@ -179,25 +188,19 @@ describe("package", function()
resolve()
end)
end)
-
assert.is_true(vim.in_fast_event())
- local handle = assert.is_not.has_error(function()
+ return assert.is_not.has_error(function()
return dummy:install()
end)
-
- assert.wait_for(function()
- assert.is_true(handle:is_closed())
- end)
end)
- )
+ end)
- it(
- "should be able to instantiate package outside of main loop",
- async_test(function()
- local dummy = registry.get_package "registry"
+ it("should be able to instantiate package outside of main loop", function()
+ local dummy = registry.get_package "registry"
- -- Move outside the main loop
+ -- Move outside the main loop
+ a.run_blocking(function ()
a.wait(function(resolve)
local timer = vim.loop.new_timer()
timer:start(0, 0, function()
@@ -207,12 +210,10 @@ describe("package", function()
end)
assert.is_true(vim.in_fast_event())
-
local pkg = assert.is_not.has_error(function()
return Pkg.new(dummy.spec)
end)
-
assert.same(dummy.spec, pkg.spec)
end)
- )
+ end)
end)
diff --git a/tests/mason-core/platform_spec.lua b/tests/mason-core/platform_spec.lua
index 48484707..88e2b42a 100644
--- a/tests/mason-core/platform_spec.lua
+++ b/tests/mason-core/platform_spec.lua
@@ -15,6 +15,16 @@ local function stub_etc_os_release(contents)
end
describe("platform", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
local function platform()
package.loaded["mason-core.platform"] = nil
return require "mason-core.platform"
diff --git a/tests/mason-core/process_spec.lua b/tests/mason-core/process_spec.lua
index 38ea94de..06330cdd 100644
--- a/tests/mason-core/process_spec.lua
+++ b/tests/mason-core/process_spec.lua
@@ -4,25 +4,22 @@ local spy = require "luassert.spy"
describe("process.spawn", function()
-- Unix only
- it(
- "should spawn command and feed output to sink",
- async_test(function()
- local stdio = process.in_memory_sink()
- local callback = spy.new()
- process.spawn("env", {
- args = {},
- env = {
- "HELLO=world",
- "MY_ENV=var",
- },
- stdio_sink = stdio.sink,
- }, callback)
+ it("should spawn command and feed output to sink", function()
+ local stdio = process.in_memory_sink()
+ local callback = spy.new()
+ process.spawn("env", {
+ args = {},
+ env = {
+ "HELLO=world",
+ "MY_ENV=var",
+ },
+ stdio_sink = stdio.sink,
+ }, callback)
- assert.wait_for(function()
- assert.spy(callback).was_called(1)
- assert.spy(callback).was_called_with(true, 0, match.is_number())
- assert.equals(table.concat(stdio.buffers.stdout, ""), "HELLO=world\nMY_ENV=var\n")
- end)
+ assert.wait(function()
+ assert.spy(callback).was_called(1)
+ assert.spy(callback).was_called_with(true, 0, match.is_number())
+ assert.equals(table.concat(stdio.buffers.stdout, ""), "HELLO=world\nMY_ENV=var\n")
end)
- )
+ end)
end)
diff --git a/tests/mason-core/result_spec.lua b/tests/mason-core/result_spec.lua
index 46f4d35c..227e53ae 100644
--- a/tests/mason-core/result_spec.lua
+++ b/tests/mason-core/result_spec.lua
@@ -250,27 +250,28 @@ describe("Result.try", function()
assert.equals("42", failure:err_or_nil())
end)
- it(
- "should allow calling async functions inside try blocks",
- async_test(function()
- assert.same(
- Result.success "Hello, world!",
- Result.try(function(try)
+ it("should allow calling async functions inside try blocks", function()
+ assert.same(
+ Result.success "Hello, world!",
+ a.run_blocking(function()
+ return Result.try(function(try)
a.sleep(10)
local hello = try(Result.success "Hello, ")
local world = try(Result.success "world!")
return hello .. world
end)
- )
- local failure = Result.try(function(try)
+ end)
+ )
+ local failure = a.run_blocking(function()
+ return Result.try(function(try)
a.sleep(10)
local err = try(Result.success "42")
error(err)
end)
- assert.is_true(failure:is_failure())
- assert.is_true(match.matches ": 42$"(failure:err_or_nil()))
end)
- )
+ assert.is_true(failure:is_failure())
+ assert.is_true(match.matches ": 42$"(failure:err_or_nil()))
+ end)
it("should not unwrap result values in try blocks", function()
assert.same(
@@ -300,12 +301,11 @@ describe("Result.try", function()
)
end)
- it(
- "should allow nesting try blocks in async scope",
- async_test(function()
- assert.same(
- Result.success "Hello from the underworld!",
- Result.try(function(try)
+ it("should allow nesting try blocks in async scope", function()
+ assert.same(
+ Result.success "Hello from the underworld!",
+ a.run_blocking(function()
+ return Result.try(function(try)
a.sleep(10)
local greeting = try(Result.success "Hello from the %s!")
a.sleep(10)
@@ -316,7 +316,7 @@ describe("Result.try", function()
return value
end)))
end)
- )
- end)
- )
+ end)
+ )
+ end)
end)
diff --git a/tests/mason-core/spawn_spec.lua b/tests/mason-core/spawn_spec.lua
index 15b9fe7d..a1432294 100644
--- a/tests/mason-core/spawn_spec.lua
+++ b/tests/mason-core/spawn_spec.lua
@@ -1,3 +1,4 @@
+local a = require "mason-core.async"
local match = require "luassert.match"
local process = require "mason-core.process"
local spawn = require "mason-core.spawn"
@@ -5,212 +6,186 @@ local spy = require "luassert.spy"
local stub = require "luassert.stub"
describe("async spawn", function()
- it(
- "should spawn commands and return stdout & stderr",
- async_test(function()
- local result = spawn.env {
- env_raw = { "FOO=bar" },
- }
- assert.is_true(result:is_success())
- assert.equals("FOO=bar\n", result:get_or_nil().stdout)
- assert.equals("", result:get_or_nil().stderr)
- end)
- )
+ local snapshot
- it(
- "should use provided stdio_sink",
- async_test(function()
- local stdio = process.in_memory_sink()
- local result = spawn.env {
- env_raw = { "FOO=bar" },
- stdio_sink = stdio.sink,
- }
- assert.is_true(result:is_success())
- assert.equals(nil, result:get_or_nil().stdout)
- assert.equals(nil, result:get_or_nil().stderr)
- assert.equals("FOO=bar\n", table.concat(stdio.buffers.stdout, ""))
- assert.equals("", table.concat(stdio.buffers.stderr, ""))
- end)
- )
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
- it(
- "should pass command arguments",
- async_test(function()
- local result = spawn.bash {
- "-c",
- 'echo "Hello $VAR"',
- env = { VAR = "world" },
- }
+ after_each(function()
+ snapshot:revert()
+ end)
- assert.is_true(result:is_success())
- assert.equals("Hello world\n", result:get_or_nil().stdout)
- assert.equals("", result:get_or_nil().stderr)
- end)
- )
+ it("should spawn commands and return stdout & stderr", function()
+ local result = a.run_blocking(spawn.env, {
+ env_raw = { "FOO=bar" },
+ })
+ assert.is_true(result:is_success())
+ assert.equals("FOO=bar\n", result:get_or_nil().stdout)
+ assert.equals("", result:get_or_nil().stderr)
+ end)
- it(
- "should ignore vim.NIL args",
- async_test(function()
- spy.on(process, "spawn")
- local result = spawn.bash {
- vim.NIL,
- vim.NIL,
- "-c",
- { vim.NIL, vim.NIL },
- 'echo "Hello $VAR"',
- env = { VAR = "world" },
- }
+ it("should use provided stdio_sink", function()
+ local stdio = process.in_memory_sink()
+ local result = a.run_blocking(spawn.env, {
+ env_raw = { "FOO=bar" },
+ stdio_sink = stdio.sink,
+ })
+ assert.is_true(result:is_success())
+ assert.equals(nil, result:get_or_nil().stdout)
+ assert.equals(nil, result:get_or_nil().stderr)
+ assert.equals("FOO=bar\n", table.concat(stdio.buffers.stdout, ""))
+ assert.equals("", table.concat(stdio.buffers.stderr, ""))
+ end)
- assert.is_true(result:is_success())
- assert.equals("Hello world\n", result:get_or_nil().stdout)
- assert.equals("", result:get_or_nil().stderr)
- assert.spy(process.spawn).was_called(1)
- assert.spy(process.spawn).was_called_with(
- "bash",
- match.tbl_containing {
- stdio_sink = match.tbl_containing {
- stdout = match.is_function(),
- stderr = match.is_function(),
- },
- env = match.list_containing "VAR=world",
- args = match.tbl_containing {
- "-c",
- 'echo "Hello $VAR"',
- },
- },
- match.is_function()
- )
- end)
- )
+ it("should pass command arguments", function()
+ local result = a.run_blocking(spawn.bash, {
+ "-c",
+ 'echo "Hello $VAR"',
+ env = { VAR = "world" },
+ })
- it(
- "should flatten table args",
- async_test(function()
- local result = spawn.bash {
- { "-c", 'echo "Hello $VAR"' },
- env = { VAR = "world" },
- }
+ assert.is_true(result:is_success())
+ assert.equals("Hello world\n", result:get_or_nil().stdout)
+ assert.equals("", result:get_or_nil().stderr)
+ end)
- assert.is_true(result:is_success())
- assert.equals("Hello world\n", result:get_or_nil().stdout)
- assert.equals("", result:get_or_nil().stderr)
- end)
- )
+ it("should ignore vim.NIL args", function()
+ spy.on(process, "spawn")
+ local result = a.run_blocking(spawn.bash, {
+ vim.NIL,
+ vim.NIL,
+ "-c",
+ { vim.NIL, vim.NIL },
+ 'echo "Hello $VAR"',
+ env = { VAR = "world" },
+ })
- it(
- "should call on_spawn",
- async_test(function()
- local on_spawn = spy.new(function(_, stdio)
- local stdin = stdio[1]
- stdin:write "im so piped rn"
- stdin:close()
- end)
+ assert.is_true(result:is_success())
+ assert.equals("Hello world\n", result:get_or_nil().stdout)
+ assert.equals("", result:get_or_nil().stderr)
+ assert.spy(process.spawn).was_called(1)
+ assert.spy(process.spawn).was_called_with(
+ "bash",
+ match.tbl_containing {
+ stdio_sink = match.tbl_containing {
+ stdout = match.is_function(),
+ stderr = match.is_function(),
+ },
+ env = match.list_containing "VAR=world",
+ args = match.tbl_containing {
+ "-c",
+ 'echo "Hello $VAR"',
+ },
+ },
+ match.is_function()
+ )
+ end)
- local result = spawn.cat {
- { "-" },
- on_spawn = on_spawn,
- }
+ it("should flatten table args", function()
+ local result = a.run_blocking(spawn.bash, {
+ { "-c", 'echo "Hello $VAR"' },
+ env = { VAR = "world" },
+ })
- assert.spy(on_spawn).was_called(1)
- assert.spy(on_spawn).was_called_with(match.is_not.is_nil(), match.is_table(), match.is_number())
- assert.is_true(result:is_success())
- assert.equals("im so piped rn", result:get_or_nil().stdout)
+ assert.is_true(result:is_success())
+ assert.equals("Hello world\n", result:get_or_nil().stdout)
+ assert.equals("", result:get_or_nil().stderr)
+ end)
+
+ it("should call on_spawn", function()
+ local on_spawn = spy.new(function(_, stdio)
+ local stdin = stdio[1]
+ stdin:write "im so piped rn"
+ stdin:close()
end)
- )
- it(
- "should not call on_spawn if spawning fails",
- async_test(function()
- local on_spawn = spy.new()
+ local result = a.run_blocking(spawn.cat, {
+ { "-" },
+ on_spawn = on_spawn,
+ })
- local result = spawn.this_cmd_doesnt_exist {
- on_spawn = on_spawn,
- }
+ assert.spy(on_spawn).was_called(1)
+ assert.spy(on_spawn).was_called_with(match.is_not.is_nil(), match.is_table(), match.is_number())
+ assert.is_true(result:is_success())
+ assert.equals("im so piped rn", result:get_or_nil().stdout)
+ end)
- assert.spy(on_spawn).was_called(0)
- assert.is_true(result:is_failure())
- end)
- )
+ it("should not call on_spawn if spawning fails", function()
+ local on_spawn = spy.new()
- it(
- "should handle failure to spawn process",
- async_test(function()
- stub(process, "spawn", function(_, _, callback)
- callback(false)
- end)
+ local result = a.run_blocking(spawn.this_cmd_doesnt_exist, {
+ on_spawn = on_spawn,
+ })
- local result = spawn.my_cmd {}
- assert.is_true(result:is_failure())
- assert.is_nil(result:err_or_nil().exit_code)
+ assert.spy(on_spawn).was_called(0)
+ assert.is_true(result:is_failure())
+ end)
+
+ it("should handle failure to spawn process", function()
+ stub(process, "spawn", function(_, _, callback)
+ callback(false)
end)
- )
- it(
- "should format failure message",
- async_test(function()
- stub(process, "spawn", function(cmd, opts, callback)
- opts.stdio_sink.stderr(("This is an error message for %s!"):format(cmd))
- callback(false, 127)
- end)
+ local result = a.run_blocking(spawn.my_cmd, {})
+ assert.is_true(result:is_failure())
+ assert.is_nil(result:err_or_nil().exit_code)
+ end)
- local result = spawn.bash {}
- assert.is_true(result:is_failure())
- assert.equals(
- "spawn: bash failed with exit code 127 and signal -. This is an error message for bash!",
- tostring(result:err_or_nil())
- )
+ it("should format failure message", function()
+ stub(process, "spawn", function(cmd, opts, callback)
+ opts.stdio_sink.stderr(("This is an error message for %s!"):format(cmd))
+ callback(false, 127)
end)
- )
- it(
- "should check whether command is executable",
- async_test(function()
- local result = spawn.my_cmd {}
- assert.is_true(result:is_failure())
- assert.equals(
- "spawn: my_cmd failed with exit code - and signal -. my_cmd is not executable",
- tostring(result:err_or_nil())
- )
- end)
- )
+ local result = a.run_blocking(spawn.bash, {})
+ assert.is_true(result:is_failure())
+ assert.equals(
+ "spawn: bash failed with exit code 127 and signal -. This is an error message for bash!",
+ tostring(result:err_or_nil())
+ )
+ end)
- it(
- "should skip checking whether command is executable",
- async_test(function()
- stub(process, "spawn", function(_, _, callback)
- callback(false, 127)
- end)
+ it("should check whether command is executable", function()
+ local result = a.run_blocking(spawn.my_cmd, {})
+ assert.is_true(result:is_failure())
+ assert.equals(
+ "spawn: my_cmd failed with exit code - and signal -. my_cmd is not executable",
+ tostring(result:err_or_nil())
+ )
+ end)
- local result = spawn.my_cmd { "arg1", check_executable = false }
- assert.is_true(result:is_failure())
- assert.spy(process.spawn).was_called(1)
- assert.spy(process.spawn).was_called_with(
- "my_cmd",
- match.tbl_containing {
- args = match.same { "arg1" },
- },
- match.is_function()
- )
+ it("should skip checking whether command is executable", function()
+ stub(process, "spawn", function(_, _, callback)
+ callback(false, 127)
end)
- )
- it(
- "should skip checking whether command is executable if with_paths is provided",
- async_test(function()
- stub(process, "spawn", function(_, _, callback)
- callback(false, 127)
- end)
+ local result = a.run_blocking(spawn.my_cmd, { "arg1", check_executable = false })
+ assert.is_true(result:is_failure())
+ assert.spy(process.spawn).was_called(1)
+ assert.spy(process.spawn).was_called_with(
+ "my_cmd",
+ match.tbl_containing {
+ args = match.same { "arg1" },
+ },
+ match.is_function()
+ )
+ end)
- local result = spawn.my_cmd { "arg1", with_paths = {} }
- assert.is_true(result:is_failure())
- assert.spy(process.spawn).was_called(1)
- assert.spy(process.spawn).was_called_with(
- "my_cmd",
- match.tbl_containing {
- args = match.same { "arg1" },
- },
- match.is_function()
- )
+ it("should skip checking whether command is executable if with_paths is provided", function()
+ stub(process, "spawn", function(_, _, callback)
+ callback(false, 127)
end)
- )
+
+ local result = a.run_blocking(spawn.my_cmd, { "arg1", with_paths = {} })
+ assert.is_true(result:is_failure())
+ assert.spy(process.spawn).was_called(1)
+ assert.spy(process.spawn).was_called_with(
+ "my_cmd",
+ match.tbl_containing {
+ args = match.same { "arg1" },
+ },
+ match.is_function()
+ )
+ end)
end)
diff --git a/tests/mason-core/terminator_spec.lua b/tests/mason-core/terminator_spec.lua
index 24c1ec25..29a3a1dd 100644
--- a/tests/mason-core/terminator_spec.lua
+++ b/tests/mason-core/terminator_spec.lua
@@ -8,112 +8,113 @@ local stub = require "luassert.stub"
local terminator = require "mason-core.terminator"
describe("terminator", function()
- it(
- "should terminate all active handles on nvim exit",
- async_test(function()
- spy.on(InstallHandle, "terminate")
- local dummy = registry.get_package "dummy"
- local dummy2 = registry.get_package "dummy2"
- for _, pkg in ipairs { dummy, dummy2 } do
- stub(pkg.spec.source, "install", function()
- a.sleep(10000)
- end)
- end
+ local snapshot
- local dummy_handle = dummy:install()
- local dummy2_handle = dummy2:install()
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
- assert.wait_for(function()
- assert.spy(dummy.spec.source.install).was_called()
- assert.spy(dummy2.spec.source.install).was_called()
+ after_each(function()
+ -- wait for scheduled calls to expire
+ a.run_blocking(a.wait, vim.schedule)
+ snapshot:revert()
+ end)
+
+ it("should terminate all active handles on nvim exit", function()
+ spy.on(InstallHandle, "terminate")
+ local dummy = registry.get_package "dummy"
+ local dummy2 = registry.get_package "dummy2"
+ for _, pkg in ipairs { dummy, dummy2 } do
+ stub(pkg.spec.source, "install", function()
+ a.sleep(10000)
end)
+ end
- terminator.terminate(5000)
+ local dummy_handle = dummy:install()
+ local dummy2_handle = dummy2:install()
- assert.spy(InstallHandle.terminate).was_called(2)
- assert.spy(InstallHandle.terminate).was_called_with(match.is_ref(dummy_handle))
- assert.spy(InstallHandle.terminate).was_called_with(match.is_ref(dummy2_handle))
- assert.wait_for(function()
- assert.is_true(dummy_handle:is_closed())
- assert.is_true(dummy2_handle:is_closed())
- end)
+ assert.wait(function()
+ assert.spy(dummy.spec.source.install).was_called()
+ assert.spy(dummy2.spec.source.install).was_called()
end)
- )
- it(
- "should print warning messages",
- async_test(function()
- spy.on(vim.api, "nvim_echo")
- spy.on(vim.api, "nvim_err_writeln")
- spy.on(InstallHandle, "terminate")
- local dummy = registry.get_package "dummy"
- local dummy2 = registry.get_package "dummy2"
- for _, pkg in ipairs { dummy, dummy2 } do
- stub(pkg.spec.source, "install", function()
- a.sleep(10000)
- end)
- end
+ terminator.terminate(5000)
- local dummy_handle = dummy:install()
- local dummy2_handle = dummy2:install()
+ assert.spy(InstallHandle.terminate).was_called(2)
+ assert.spy(InstallHandle.terminate).was_called_with(match.is_ref(dummy_handle))
+ assert.spy(InstallHandle.terminate).was_called_with(match.is_ref(dummy2_handle))
+ assert.wait(function()
+ assert.is_true(dummy_handle:is_closed())
+ assert.is_true(dummy2_handle:is_closed())
+ end)
+ end)
- assert.wait_for(function()
- assert.spy(dummy.spec.source.install).was_called()
- assert.spy(dummy2.spec.source.install).was_called()
+ it("should print warning messages", function()
+ spy.on(vim.api, "nvim_echo")
+ spy.on(vim.api, "nvim_err_writeln")
+ local dummy = registry.get_package "dummy"
+ local dummy2 = registry.get_package "dummy2"
+ for _, pkg in ipairs { dummy, dummy2 } do
+ stub(pkg.spec.source, "install", function()
+ a.sleep(10000)
end)
+ end
- terminator.terminate(5000)
+ local dummy_handle = dummy:install()
+ local dummy2_handle = dummy2:install()
- assert.spy(vim.api.nvim_echo).was_called(1)
- assert.spy(vim.api.nvim_echo).was_called_with({
- {
- "[mason.nvim] Neovim is exiting while packages are still installing. Terminating all installations…",
- "WarningMsg",
- },
- }, true, {})
+ assert.wait(function()
+ assert.spy(dummy.spec.source.install).was_called()
+ assert.spy(dummy2.spec.source.install).was_called()
+ end)
- a.wait(vim.schedule)
+ terminator.terminate(5000)
- assert.spy(vim.api.nvim_err_writeln).was_called(1)
- assert.spy(vim.api.nvim_err_writeln).was_called_with(_.dedent [[
+ assert.spy(vim.api.nvim_echo).was_called(1)
+ assert.spy(vim.api.nvim_echo).was_called_with({
+ {
+ "[mason.nvim] Neovim is exiting while packages are still installing. Terminating all installations…",
+ "WarningMsg",
+ },
+ }, true, {})
+
+ a.run_blocking(a.wait, vim.schedule)
+
+ assert.spy(vim.api.nvim_err_writeln).was_called(1)
+ assert.spy(vim.api.nvim_err_writeln).was_called_with(_.dedent [[
[mason.nvim] Neovim exited while the following packages were installing. Installation was aborted.
- dummy
- dummy2
]])
- assert.wait_for(function()
- assert.is_true(dummy_handle:is_closed())
- assert.is_true(dummy2_handle:is_closed())
- end)
+ assert.wait(function()
+ assert.is_true(dummy_handle:is_closed())
+ assert.is_true(dummy2_handle:is_closed())
end)
- )
+ end)
- it(
- "should send SIGTERM and then SIGKILL after grace period",
- async_test(function()
- spy.on(InstallHandle, "kill")
- local dummy = registry.get_package "dummy"
- stub(dummy.spec.source, "install")
- dummy.spec.source.install.invokes(function(ctx)
- -- your signals have no power here
- ctx.spawn.bash { "-c", "function noop { :; }; trap noop SIGTERM; sleep 999999;" }
- end)
+ it("should send SIGTERM and then SIGKILL after grace period", function()
+ spy.on(InstallHandle, "kill")
+ local dummy = registry.get_package "dummy"
+ stub(dummy.spec.source, "install", function(ctx)
+ -- your signals have no power here
+ ctx.spawn.bash { "-c", "function noop { :; }; trap noop SIGTERM; sleep 999999;" }
+ end)
- local handle = dummy:install()
+ local handle = dummy:install()
- assert.wait_for(function()
- assert.spy(dummy.spec.source.install).was_called()
- end)
- terminator.terminate(50)
+ assert.wait(function()
+ assert.spy(dummy.spec.source.install).was_called()
+ end)
+ terminator.terminate(50)
- assert.wait_for(function()
- assert.spy(InstallHandle.kill).was_called(2)
- assert.spy(InstallHandle.kill).was_called_with(match.is_ref(handle), 15) -- SIGTERM
- assert.spy(InstallHandle.kill).was_called_with(match.is_ref(handle), 9) -- SIGKILL
- end)
+ assert.wait(function()
+ assert.spy(InstallHandle.kill).was_called(2)
+ assert.spy(InstallHandle.kill).was_called_with(match.is_ref(handle), 15) -- SIGTERM
+ assert.spy(InstallHandle.kill).was_called_with(match.is_ref(handle), 9) -- SIGKILL
+ end)
- assert.wait_for(function()
- assert.is_true(handle:is_closed())
- end)
+ assert.wait(function()
+ assert.is_true(handle:is_closed())
end)
- )
+ end)
end)
diff --git a/tests/mason-core/ui_spec.lua b/tests/mason-core/ui_spec.lua
index 17087045..efd60712 100644
--- a/tests/mason-core/ui_spec.lua
+++ b/tests/mason-core/ui_spec.lua
@@ -142,187 +142,177 @@ describe("ui", function()
end)
describe("integration test", function()
- it(
- "calls vim APIs as expected during rendering",
- async_test(function()
- local window = display.new_view_only_win("test", "my-filetype")
+ it("calls vim APIs as expected during rendering", function()
+ local window = display.new_view_only_win("test", "my-filetype")
- window.view(function(state)
- return Ui.Node {
- Ui.Keybind("U", "EFFECT", nil, true),
- Ui.Text {
- "Line number 1!",
- state.text,
- },
- Ui.Keybind("R", "R_EFFECT", { state.text }),
- Ui.HlTextNode {
- {
- { "My highlighted text", "MyHighlightGroup" },
- },
- },
- }
- end)
-
- local mutate_state = window.state { text = "Initial state" }
-
- local clear_namespace = spy.on(vim.api, "nvim_buf_clear_namespace")
- local buf_set_option = spy.on(vim.api, "nvim_buf_set_option")
- local win_set_option = spy.on(vim.api, "nvim_win_set_option")
- local set_lines = spy.on(vim.api, "nvim_buf_set_lines")
- local set_extmark = spy.on(vim.api, "nvim_buf_set_extmark")
- local add_highlight = spy.on(vim.api, "nvim_buf_add_highlight")
- local set_keymap = spy.on(vim.keymap, "set")
-
- window.init {
- effects = {
- ["EFFECT"] = function() end,
- ["R_EFFECT"] = function() end,
+ window.view(function(state)
+ return Ui.Node {
+ Ui.Keybind("U", "EFFECT", nil, true),
+ Ui.Text {
+ "Line number 1!",
+ state.text,
},
- winhighlight = {
- "NormalFloat:MasonNormal",
- "CursorLine:MasonCursorLine",
+ Ui.Keybind("R", "R_EFFECT", { state.text }),
+ Ui.HlTextNode {
+ {
+ { "My highlighted text", "MyHighlightGroup" },
+ },
},
}
- window.open()
+ end)
- -- Initial window and buffer creation + initial render
- a.wait(vim.schedule)
+ local mutate_state = window.state { text = "Initial state" }
- assert.spy(win_set_option).was_called(9)
- assert.spy(win_set_option).was_called_with(match.is_number(), "number", false)
- assert.spy(win_set_option).was_called_with(match.is_number(), "relativenumber", false)
- assert.spy(win_set_option).was_called_with(match.is_number(), "wrap", false)
- assert.spy(win_set_option).was_called_with(match.is_number(), "spell", false)
- assert.spy(win_set_option).was_called_with(match.is_number(), "foldenable", false)
- assert.spy(win_set_option).was_called_with(match.is_number(), "signcolumn", "no")
- assert.spy(win_set_option).was_called_with(match.is_number(), "colorcolumn", "")
- assert.spy(win_set_option).was_called_with(match.is_number(), "cursorline", true)
- assert
- .spy(win_set_option)
- .was_called_with(match.is_number(), "winhighlight", "NormalFloat:MasonNormal,CursorLine:MasonCursorLine")
+ local clear_namespace = spy.on(vim.api, "nvim_buf_clear_namespace")
+ local buf_set_option = spy.on(vim.api, "nvim_buf_set_option")
+ local win_set_option = spy.on(vim.api, "nvim_win_set_option")
+ local set_lines = spy.on(vim.api, "nvim_buf_set_lines")
+ local set_extmark = spy.on(vim.api, "nvim_buf_set_extmark")
+ local add_highlight = spy.on(vim.api, "nvim_buf_add_highlight")
+ local set_keymap = spy.on(vim.keymap, "set")
- assert.spy(buf_set_option).was_called(10)
- assert.spy(buf_set_option).was_called_with(match.is_number(), "modifiable", false)
- assert.spy(buf_set_option).was_called_with(match.is_number(), "swapfile", false)
- assert.spy(buf_set_option).was_called_with(match.is_number(), "textwidth", 0)
- assert.spy(buf_set_option).was_called_with(match.is_number(), "buftype", "nofile")
- assert.spy(buf_set_option).was_called_with(match.is_number(), "bufhidden", "wipe")
- assert.spy(buf_set_option).was_called_with(match.is_number(), "buflisted", false)
- assert.spy(buf_set_option).was_called_with(match.is_number(), "filetype", "my-filetype")
- assert.spy(buf_set_option).was_called_with(match.is_number(), "undolevels", -1)
+ window.init {
+ effects = {
+ ["EFFECT"] = function() end,
+ ["R_EFFECT"] = function() end,
+ },
+ winhighlight = {
+ "NormalFloat:MasonNormal",
+ "CursorLine:MasonCursorLine",
+ },
+ }
+ window.open()
- assert.spy(set_lines).was_called(1)
- assert
- .spy(set_lines)
- .was_called_with(match.is_number(), 0, -1, false, { "Line number 1!", "Initial state", "My highlighted text" })
+ -- Initial window and buffer creation + initial render
+ a.run_blocking(a.wait, vim.schedule)
- assert.spy(set_extmark).was_called(0)
+ assert.spy(win_set_option).was_called(9)
+ assert.spy(win_set_option).was_called_with(match.is_number(), "number", false)
+ assert.spy(win_set_option).was_called_with(match.is_number(), "relativenumber", false)
+ assert.spy(win_set_option).was_called_with(match.is_number(), "wrap", false)
+ assert.spy(win_set_option).was_called_with(match.is_number(), "spell", false)
+ assert.spy(win_set_option).was_called_with(match.is_number(), "foldenable", false)
+ assert.spy(win_set_option).was_called_with(match.is_number(), "signcolumn", "no")
+ assert.spy(win_set_option).was_called_with(match.is_number(), "colorcolumn", "")
+ assert.spy(win_set_option).was_called_with(match.is_number(), "cursorline", true)
+ assert
+ .spy(win_set_option)
+ .was_called_with(match.is_number(), "winhighlight", "NormalFloat:MasonNormal,CursorLine:MasonCursorLine")
- assert.spy(add_highlight).was_called(1)
- assert
- .spy(add_highlight)
- .was_called_with(match.is_number(), match.is_number(), "MyHighlightGroup", 2, 0, 19)
+ assert.spy(buf_set_option).was_called(10)
+ assert.spy(buf_set_option).was_called_with(match.is_number(), "modifiable", false)
+ assert.spy(buf_set_option).was_called_with(match.is_number(), "swapfile", false)
+ assert.spy(buf_set_option).was_called_with(match.is_number(), "textwidth", 0)
+ assert.spy(buf_set_option).was_called_with(match.is_number(), "buftype", "nofile")
+ assert.spy(buf_set_option).was_called_with(match.is_number(), "bufhidden", "wipe")
+ assert.spy(buf_set_option).was_called_with(match.is_number(), "buflisted", false)
+ assert.spy(buf_set_option).was_called_with(match.is_number(), "filetype", "my-filetype")
+ assert.spy(buf_set_option).was_called_with(match.is_number(), "undolevels", -1)
- assert.spy(set_keymap).was_called(2)
- assert.spy(set_keymap).was_called_with(
- "n",
- "U",
- match.is_function(),
- match.tbl_containing { nowait = true, silent = true, buffer = match.is_number() }
- )
- assert.spy(set_keymap).was_called_with(
- "n",
- "R",
- match.is_function(),
- match.tbl_containing { nowait = true, silent = true, buffer = match.is_number() }
- )
+ assert.spy(set_lines).was_called(1)
+ assert
+ .spy(set_lines)
+ .was_called_with(match.is_number(), 0, -1, false, { "Line number 1!", "Initial state", "My highlighted text" })
- assert.spy(clear_namespace).was_called(1)
- assert.spy(clear_namespace).was_called_with(match.is_number(), match.is_number(), 0, -1)
+ assert.spy(set_extmark).was_called(0)
- mutate_state(function(state)
- state.text = "New state"
- end)
+ assert.spy(add_highlight).was_called(1)
+ assert.spy(add_highlight).was_called_with(match.is_number(), match.is_number(), "MyHighlightGroup", 2, 0, 19)
- assert.spy(set_lines).was_called(1)
- a.wait(vim.schedule)
- assert.spy(set_lines).was_called(2)
+ assert.spy(set_keymap).was_called(2)
+ assert.spy(set_keymap).was_called_with(
+ "n",
+ "U",
+ match.is_function(),
+ match.tbl_containing { nowait = true, silent = true, buffer = match.is_number() }
+ )
+ assert.spy(set_keymap).was_called_with(
+ "n",
+ "R",
+ match.is_function(),
+ match.tbl_containing { nowait = true, silent = true, buffer = match.is_number() }
+ )
+
+ assert.spy(clear_namespace).was_called(1)
+ assert.spy(clear_namespace).was_called_with(match.is_number(), match.is_number(), 0, -1)
- assert
- .spy(set_lines)
- .was_called_with(match.is_number(), 0, -1, false, { "Line number 1!", "New state", "My highlighted text" })
+ mutate_state(function(state)
+ state.text = "New state"
end)
- )
- it(
- "anchors to sticky cursor",
- async_test(function()
- local window = display.new_view_only_win("test", "my-filetype")
- window.view(function(state)
- local extra_lines = state.show_extra_lines
- and Ui.Text {
- "More",
- "Lines",
- "Here",
- }
- or Ui.Node {}
- return Ui.Node {
- extra_lines,
- Ui.Text {
- "Line 1",
- "Line 2",
- "Line 3",
- "Line 4",
- "Special line",
- },
- Ui.StickyCursor { id = "special" },
- Ui.Text {
- "Line 6",
- "Line 7",
- "Line 8",
- "Line 9",
- "Line 10",
- },
- }
- end)
- local mutate_state = window.state { show_extra_lines = false }
- window.init {}
- window.open()
- a.wait(vim.schedule)
- window.set_cursor { 5, 3 } -- move cursor to sticky line
- mutate_state(function(state)
- state.show_extra_lines = true
- end)
- a.wait(vim.schedule)
- local cursor = window.get_cursor()
- assert.same({ 8, 3 }, cursor)
+ assert.spy(set_lines).was_called(1)
+ a.run_blocking(a.wait, vim.schedule)
+ assert.spy(set_lines).was_called(2)
+
+ assert
+ .spy(set_lines)
+ .was_called_with(match.is_number(), 0, -1, false, { "Line number 1!", "New state", "My highlighted text" })
+ end)
+
+ it("anchors to sticky cursor", function()
+ local window = display.new_view_only_win("test", "my-filetype")
+ window.view(function(state)
+ local extra_lines = state.show_extra_lines
+ and Ui.Text {
+ "More",
+ "Lines",
+ "Here",
+ }
+ or Ui.Node {}
+ return Ui.Node {
+ extra_lines,
+ Ui.Text {
+ "Line 1",
+ "Line 2",
+ "Line 3",
+ "Line 4",
+ "Special line",
+ },
+ Ui.StickyCursor { id = "special" },
+ Ui.Text {
+ "Line 6",
+ "Line 7",
+ "Line 8",
+ "Line 9",
+ "Line 10",
+ },
+ }
end)
- )
- it(
- "should respect border ui setting",
- async_test(function()
- local nvim_open_win = spy.on(vim.api, "nvim_open_win")
+ local mutate_state = window.state { show_extra_lines = false }
+ window.init {}
+ window.open()
+ a.run_blocking(a.wait, vim.schedule)
+ window.set_cursor { 5, 3 } -- move cursor to sticky line
+ mutate_state(function(state)
+ state.show_extra_lines = true
+ end)
+ a.run_blocking(a.wait, vim.schedule)
+ local cursor = window.get_cursor()
+ assert.same({ 8, 3 }, cursor)
+ end)
- local window = display.new_view_only_win("test", "my-filetype")
- window.view(function()
- return Ui.Node {}
- end)
- window.state {}
- window.init { border = "rounded" }
- window.open()
- a.wait(vim.schedule)
+ it("should respect border ui setting", function()
+ local nvim_open_win = spy.on(vim.api, "nvim_open_win")
- assert.spy(nvim_open_win).was_called(1)
- assert.spy(nvim_open_win).was_called_with(
- match.is_number(),
- true,
- match.tbl_containing {
- border = "rounded",
- }
- )
+ local window = display.new_view_only_win("test", "my-filetype")
+ window.view(function()
+ return Ui.Node {}
end)
- )
+ window.state {}
+ window.init { border = "rounded" }
+ window.open()
+ a.run_blocking(a.wait, vim.schedule)
+
+ assert.spy(nvim_open_win).was_called(1)
+ assert.spy(nvim_open_win).was_called_with(
+ match.is_number(),
+ true,
+ match.tbl_containing {
+ border = "rounded",
+ }
+ )
+ end)
it("should not apply cascading styles to empty lines", function()
local render_output = display._render_node(
diff --git a/tests/mason-registry/api_spec.lua b/tests/mason-registry/api_spec.lua
index 039d0959..8164c901 100644
--- a/tests/mason-registry/api_spec.lua
+++ b/tests/mason-registry/api_spec.lua
@@ -3,6 +3,16 @@ local match = require "luassert.match"
local stub = require "luassert.stub"
describe("mason-registry API", function()
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
---@module "mason-registry.api"
local api
local fetch
diff --git a/tests/mason/api/command_spec.lua b/tests/mason/api/command_spec.lua
index 6cae3e0c..6945340d 100644
--- a/tests/mason/api/command_spec.lua
+++ b/tests/mason/api/command_spec.lua
@@ -9,73 +9,56 @@ local api = require "mason.api.command"
local registry = require "mason-registry"
describe(":Mason", function()
- it(
- "should open the UI window",
- async_test(function()
- api.Mason()
- a.wait(vim.schedule)
- local win = vim.api.nvim_get_current_win()
- local buf = vim.api.nvim_win_get_buf(win)
- assert.equals("mason", vim.api.nvim_buf_get_option(buf, "filetype"))
- end)
- )
+ it("should open the UI window", function()
+ api.Mason()
+ a.run_blocking(a.wait, vim.schedule)
+ local win = vim.api.nvim_get_current_win()
+ local buf = vim.api.nvim_win_get_buf(win)
+ assert.equals("mason", vim.api.nvim_buf_get_option(buf, "filetype"))
+ end)
end)
describe(":MasonInstall", function()
- it(
- "should install the provided packages",
- async_test(function()
- local dummy = registry.get_package "dummy"
- local dummy2 = registry.get_package "dummy2"
- spy.on(Pkg, "install")
- api.MasonInstall { "dummy@1.0.0", "dummy2" }
- assert.spy(Pkg.install).was_called(2)
- assert.spy(Pkg.install).was_called_with(match.is_ref(dummy), { version = "1.0.0" })
- assert
- .spy(Pkg.install)
- .was_called_with(match.is_ref(dummy2), match.tbl_containing { version = match.is_nil() })
- end)
- )
+ it("should install the provided packages", function()
+ local dummy = registry.get_package "dummy"
+ local dummy2 = registry.get_package "dummy2"
+ spy.on(Pkg, "install")
+ api.MasonInstall { "dummy@1.0.0", "dummy2" }
+ assert.spy(Pkg.install).was_called(2)
+ assert.spy(Pkg.install).was_called_with(match.is_ref(dummy), { version = "1.0.0" })
+ assert.spy(Pkg.install).was_called_with(match.is_ref(dummy2), match.tbl_containing { version = match.is_nil() })
+ end)
- it(
- "should install provided packages in debug mode",
- async_test(function()
- local dummy = registry.get_package "dummy"
- local dummy2 = registry.get_package "dummy2"
- spy.on(Pkg, "install")
- vim.cmd [[MasonInstall --debug dummy dummy2]]
- assert.spy(Pkg.install).was_called(2)
- assert.spy(Pkg.install).was_called_with(match.is_ref(dummy), { version = nil, debug = true })
- assert.spy(Pkg.install).was_called_with(match.is_ref(dummy2), { version = nil, debug = true })
- end)
- )
+ it("should install provided packages in debug mode", function()
+ local dummy = registry.get_package "dummy"
+ local dummy2 = registry.get_package "dummy2"
+ spy.on(Pkg, "install")
+ vim.cmd [[MasonInstall --debug dummy dummy2]]
+ assert.spy(Pkg.install).was_called(2)
+ assert.spy(Pkg.install).was_called_with(match.is_ref(dummy), { version = nil, debug = true })
+ assert.spy(Pkg.install).was_called_with(match.is_ref(dummy2), { version = nil, debug = true })
+ end)
- it(
- "should open the UI window",
- async_test(function()
- local dummy = registry.get_package "dummy"
- spy.on(dummy, "install")
- api.MasonInstall { "dummy" }
- local win = vim.api.nvim_get_current_win()
- local buf = vim.api.nvim_win_get_buf(win)
- assert.equals("mason", vim.api.nvim_buf_get_option(buf, "filetype"))
- end)
- )
+ it("should open the UI window", function()
+ local dummy = registry.get_package "dummy"
+ spy.on(dummy, "install")
+ api.MasonInstall { "dummy" }
+ local win = vim.api.nvim_get_current_win()
+ local buf = vim.api.nvim_win_get_buf(win)
+ assert.equals("mason", vim.api.nvim_buf_get_option(buf, "filetype"))
+ end)
end)
describe(":MasonUninstall", function()
- it(
- "should uninstall the provided packages",
- async_test(function()
- local dummy = registry.get_package "dummy"
- local dummy2 = registry.get_package "dummy"
- spy.on(Pkg, "uninstall")
- api.MasonUninstall { "dummy", "dummy2" }
- assert.spy(Pkg.uninstall).was_called(2)
- assert.spy(Pkg.uninstall).was_called_with(match.is_ref(dummy))
- assert.spy(Pkg.uninstall).was_called_with(match.is_ref(dummy2))
- end)
- )
+ it("should uninstall the provided packages", function()
+ local dummy = registry.get_package "dummy"
+ local dummy2 = registry.get_package "dummy"
+ spy.on(Pkg, "uninstall")
+ api.MasonUninstall { "dummy", "dummy2" }
+ assert.spy(Pkg.uninstall).was_called(2)
+ assert.spy(Pkg.uninstall).was_called_with(match.is_ref(dummy))
+ assert.spy(Pkg.uninstall).was_called_with(match.is_ref(dummy2))
+ end)
end)
describe(":MasonLog", function()
@@ -91,39 +74,43 @@ describe(":MasonLog", function()
end)
describe(":MasonUpdate", function()
- it(
- "should update registries",
- async_test(function()
- stub(registry, "update", function(cb)
- cb(true, { {} })
- end)
- spy.on(vim, "notify")
- api.MasonUpdate()
- assert.spy(vim.notify).was_called(2)
- assert.spy(vim.notify).was_called_with("Updating registries…", vim.log.levels.INFO, {
- title = "mason.nvim",
- })
- assert.spy(vim.notify).was_called_with("Successfully updated 1 registry.", vim.log.levels.INFO, {
- title = "mason.nvim",
- })
+ local snapshot
+
+ before_each(function()
+ snapshot = assert.snapshot()
+ end)
+
+ after_each(function()
+ snapshot:revert()
+ end)
+
+ it("should update registries", function()
+ stub(registry, "update", function(cb)
+ cb(true, { {} })
end)
- )
+ spy.on(vim, "notify")
+ api.MasonUpdate()
+ assert.spy(vim.notify).was_called(2)
+ assert.spy(vim.notify).was_called_with("Updating registries…", vim.log.levels.INFO, {
+ title = "mason.nvim",
+ })
+ assert.spy(vim.notify).was_called_with("Successfully updated 1 registry.", vim.log.levels.INFO, {
+ title = "mason.nvim",
+ })
+ end)
- it(
- "should notify errors",
- async_test(function()
- stub(registry, "update", function(cb)
- cb(false, "Some error.")
- end)
- spy.on(vim, "notify")
- api.MasonUpdate()
- assert.spy(vim.notify).was_called(2)
- assert.spy(vim.notify).was_called_with("Updating registries…", vim.log.levels.INFO, {
- title = "mason.nvim",
- })
- assert.spy(vim.notify).was_called_with("Failed to update registries: Some error.", vim.log.levels.ERROR, {
- title = "mason.nvim",
- })
+ it("should notify errors", function()
+ stub(registry, "update", function(cb)
+ cb(false, "Some error.")
end)
- )
+ spy.on(vim, "notify")
+ api.MasonUpdate()
+ assert.spy(vim.notify).was_called(2)
+ assert.spy(vim.notify).was_called_with("Updating registries…", vim.log.levels.INFO, {
+ title = "mason.nvim",
+ })
+ assert.spy(vim.notify).was_called_with("Failed to update registries: Some error.", vim.log.levels.ERROR, {
+ title = "mason.nvim",
+ })
+ end)
end)
diff --git a/tests/minimal_init.vim b/tests/minimal_init.vim
index abd07fa3..43e8367f 100644
--- a/tests/minimal_init.vim
+++ b/tests/minimal_init.vim
@@ -13,7 +13,22 @@ set packpath=$dependencies
packloadall
lua require("luassertx")
-lua require("test_helpers")
+
+lua <<EOF
+mockx = {
+ just_runs = function() end,
+ returns = function(val)
+ return function()
+ return val
+ end
+ end,
+ throws = function(exception)
+ return function()
+ error(exception, 2)
+ end
+ end,
+}
+EOF
lua <<EOF
local path = require "mason-core.path"
diff --git a/vim.yml b/vim.yml
index 1b348cf0..b0dc6796 100644
--- a/vim.yml
+++ b/vim.yml
@@ -8,23 +8,10 @@ globals:
property: read-only
vim:
any: true
- async_test:
+ assert.wait:
args:
- type: function
- assert.wait_for:
- args:
- - type: function
- create_dummy_context:
- args:
- - type: table
- required: false
- InstallHandleGenerator:
- args:
- - type: string
- InstallContextGenerator:
- args:
- - type: any
- - type: table
+ - type: number
required: false
mockx.throws:
args: