diff --git a/.busted b/.busted new file mode 100644 index 0000000..67e23d2 --- /dev/null +++ b/.busted @@ -0,0 +1,13 @@ +return { + _all = { + coverage = false, + lpath = "lua/?.lua;lua/?/init.lua", + }, + default = { + verbose = true, + ROOT = {"tests"}, + }, + tests = { + verbose = true, + }, +} diff --git a/flake.lock b/flake.lock index f76438e..068d7a8 100644 --- a/flake.lock +++ b/flake.lock @@ -48,77 +48,68 @@ "type": "github" } }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": [ - "neovim-nightly-overlay", - "nixpkgs" - ] - }, + "flake-compat_4": { + "flake": false, "locked": { - "lastModified": 1696343447, - "narHash": "sha256-B2xAZKLkkeRFG5XcHHSXXcP7To9Xzr59KXeZiRf4vdQ=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "c9afaba3dfa4085dbd2ccb38dfade5141e33d9d4", + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", "type": "github" }, "original": { - "owner": "hercules-ci", - "repo": "flake-parts", + "owner": "edolstra", + "repo": "flake-compat", "type": "github" } }, - "flake-parts_2": { + "flake-utils": { "inputs": { - "nixpkgs-lib": "nixpkgs-lib" + "systems": "systems" }, "locked": { - "lastModified": 1688466019, - "narHash": "sha256-VeM2akYrBYMsb4W/MmBo1zmaMfgbL4cH3Pu8PGyIwJ0=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "8e8d955c22df93dbe24f19ea04f47a74adbdc5ec", + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", "type": "github" }, "original": { - "id": "flake-parts", - "type": "indirect" + "owner": "numtide", + "repo": "flake-utils", + "type": "github" } }, - "flake-parts_3": { + "flake-utils_2": { "inputs": { - "nixpkgs-lib": [ - "neovim-nightly-overlay", - "hercules-ci-effects", - "hercules-ci-agent", - "nixpkgs" - ] + "systems": "systems_2" }, "locked": { - "lastModified": 1688466019, - "narHash": "sha256-VeM2akYrBYMsb4W/MmBo1zmaMfgbL4cH3Pu8PGyIwJ0=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "8e8d955c22df93dbe24f19ea04f47a74adbdc5ec", + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", "type": "github" }, "original": { - "owner": "hercules-ci", - "repo": "flake-parts", + "owner": "numtide", + "repo": "flake-utils", "type": "github" } }, - "flake-utils": { + "flake-utils_3": { "inputs": { - "systems": "systems" + "systems": "systems_3" }, "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", "owner": "numtide", "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", "type": "github" }, "original": { @@ -127,9 +118,9 @@ "type": "github" } }, - "flake-utils_2": { + "flake-utils_4": { "inputs": { - "systems": "systems_2" + "systems": "systems_4" }, "locked": { "lastModified": 1685518550, @@ -145,9 +136,9 @@ "type": "github" } }, - "flake-utils_3": { + "flake-utils_5": { "inputs": { - "systems": "systems_3" + "systems": "systems_5" }, "locked": { "lastModified": 1685518550, @@ -166,6 +157,7 @@ "gitignore": { "inputs": { "nixpkgs": [ + "neorocks", "pre-commit-hooks", "nixpkgs" ] @@ -184,61 +176,24 @@ "type": "github" } }, - "haskell-flake": { - "locked": { - "lastModified": 1684780604, - "narHash": "sha256-2uMZsewmRn7rRtAnnQNw1lj0uZBMh4m6Cs/7dV5YF08=", - "owner": "srid", - "repo": "haskell-flake", - "rev": "74210fa80a49f1b6f67223debdbf1494596ff9f2", - "type": "github" - }, - "original": { - "owner": "srid", - "ref": "0.3.0", - "repo": "haskell-flake", - "type": "github" - } - }, - "hercules-ci-agent": { - "inputs": { - "flake-parts": "flake-parts_3", - "haskell-flake": "haskell-flake", - "nixpkgs": "nixpkgs" - }, - "locked": { - "lastModified": 1688568579, - "narHash": "sha256-ON0M56wtY/TIIGPkXDlJboAmuYwc73Hi8X9iJGtxOhM=", - "owner": "hercules-ci", - "repo": "hercules-ci-agent", - "rev": "367dd8cd649b57009a6502e878005a1e54ad78c5", - "type": "github" - }, - "original": { - "id": "hercules-ci-agent", - "type": "indirect" - } - }, - "hercules-ci-effects": { + "gitignore_2": { "inputs": { - "flake-parts": "flake-parts_2", - "hercules-ci-agent": "hercules-ci-agent", "nixpkgs": [ - "neovim-nightly-overlay", + "pre-commit-hooks", "nixpkgs" ] }, "locked": { - "lastModified": 1697898004, - "narHash": "sha256-xjGFwLQBVnumMZT9qSLndJViKh5M9tIKZAVCUiveiwQ=", + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", "owner": "hercules-ci", - "repo": "hercules-ci-effects", - "rev": "f925e00919fbf248aef3d1e89781b72dd89a6eb0", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", "type": "github" }, "original": { "owner": "hercules-ci", - "repo": "hercules-ci-effects", + "repo": "gitignore.nix", "type": "github" } }, @@ -258,6 +213,28 @@ "type": "github" } }, + "neorocks": { + "inputs": { + "flake-compat": "flake-compat_2", + "flake-utils": "flake-utils_2", + "neovim-nightly": "neovim-nightly", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1698470714, + "narHash": "sha256-QhIzRWfyU1otL36F5adyh1BEPfWp5v5L3N9opPSCm0Q=", + "owner": "nvim-neorocks", + "repo": "neorocks", + "rev": "76fccbd50534fccab7ab244cdb4a08eddb78b9bc", + "type": "github" + }, + "original": { + "owner": "nvim-neorocks", + "repo": "neorocks", + "type": "github" + } + }, "neotest": { "flake": false, "locked": { @@ -274,21 +251,21 @@ "type": "github" } }, - "neovim-flake": { + "neovim-nightly": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils_3", "nixpkgs": [ - "neovim-nightly-overlay", + "neorocks", "nixpkgs" ] }, "locked": { "dir": "contrib", - "lastModified": 1697918051, - "narHash": "sha256-fMlw0rw3sO5GsjQVowSo79fSnZQAMT+w1gAkuKuNxw0=", + "lastModified": 1698460938, + "narHash": "sha256-+IDg4xXSooalZAin/zuY3dSY+zX8Sid65MfN+CWRq1Y=", "owner": "neovim", "repo": "neovim", - "rev": "3a3e0251267a99eec6cfb2a058f9e992d01107fd", + "rev": "ac353e87aecf02315d82a3ad22725d2bc8140f0c", "type": "github" }, "original": { @@ -298,58 +275,18 @@ "type": "github" } }, - "neovim-nightly-overlay": { - "inputs": { - "flake-compat": "flake-compat_2", - "flake-parts": "flake-parts", - "hercules-ci-effects": "hercules-ci-effects", - "neovim-flake": "neovim-flake", - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1697932859, - "narHash": "sha256-L16iGfZGLQoy/uwGT4x1+rXAUggvuxQWIBkdetD2MLc=", - "owner": "nix-community", - "repo": "neovim-nightly-overlay", - "rev": "81e741020dcaa4b5ba87b109f0ea23b14851cc31", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "neovim-nightly-overlay", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1688322751, - "narHash": "sha256-eW62dC5f33oKZL7VWlomttbUnOTHrAbte9yNUNW8rbk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "0fbe93c5a7cac99f90b60bdf5f149383daaa615f", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-lib": { - "locked": { - "dir": "lib", - "lastModified": 1688049487, - "narHash": "sha256-100g4iaKC9MalDjUW9iN6Jl/OocTDtXdeAj7pEGIRh4=", - "owner": "NixOS", + "lastModified": 1698336494, + "narHash": "sha256-sO72WDBKyijYD1GcKPlGsycKbMBiTJMBCnmOxLAs880=", + "owner": "nixos", "repo": "nixpkgs", - "rev": "4bc72cae107788bf3f24f30db2e2f685c9298dc9", + "rev": "808c0d8c53c7ae50f82aca8e7df263225cf235bf", "type": "github" }, "original": { - "dir": "lib", - "owner": "NixOS", - "ref": "nixos-unstable", + "owner": "nixos", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } @@ -370,23 +307,23 @@ "type": "github" } }, - "nixpkgs_2": { + "nixpkgs-stable_2": { "locked": { - "lastModified": 1697793076, - "narHash": "sha256-02e7sCuqLtkyRgrZmdOyvAcQTQdcXj+vpyp9bca6cY4=", + "lastModified": 1685801374, + "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "038b2922be3fc096e1d456f93f7d0f4090628729", + "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-unstable", + "ref": "nixos-23.05", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs_3": { + "nixpkgs_2": { "locked": { "lastModified": 1697793076, "narHash": "sha256-02e7sCuqLtkyRgrZmdOyvAcQTQdcXj+vpyp9bca6cY4=", @@ -421,13 +358,38 @@ "pre-commit-hooks": { "inputs": { "flake-compat": "flake-compat_3", - "flake-utils": "flake-utils_3", + "flake-utils": "flake-utils_4", "gitignore": "gitignore", "nixpkgs": [ + "neorocks", "nixpkgs" ], "nixpkgs-stable": "nixpkgs-stable" }, + "locked": { + "lastModified": 1698227354, + "narHash": "sha256-Fi5H9jbaQLmLw9qBi/mkR33CoFjNbobo5xWdX4tKz1Q=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "bd38df3d508dfcdff52cd243d297f218ed2257bf", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks_2": { + "inputs": { + "flake-compat": "flake-compat_4", + "flake-utils": "flake-utils_5", + "gitignore": "gitignore_2", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_2" + }, "locked": { "lastModified": 1697746376, "narHash": "sha256-gu77VkgdfaHgNCVufeb6WP9oqFLjwK4jHcoPZmBVF3E=", @@ -447,11 +409,11 @@ "flake-compat": "flake-compat", "flake-utils": "flake-utils", "neodev-nvim": "neodev-nvim", + "neorocks": "neorocks", "neotest": "neotest", - "neovim-nightly-overlay": "neovim-nightly-overlay", - "nixpkgs": "nixpkgs_3", + "nixpkgs": "nixpkgs_2", "plenary-nvim": "plenary-nvim", - "pre-commit-hooks": "pre-commit-hooks" + "pre-commit-hooks": "pre-commit-hooks_2" } }, "systems": { @@ -498,6 +460,36 @@ "repo": "default", "type": "github" } + }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_5": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 3509b5d..81e02bd 100644 --- a/flake.nix +++ b/flake.nix @@ -4,8 +4,8 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; - neovim-nightly-overlay = { - url = "github:nix-community/neovim-nightly-overlay"; + neorocks = { + url = "github:nvim-neorocks/neorocks"; }; pre-commit-hooks = { @@ -41,7 +41,7 @@ self, nixpkgs, flake-utils, - neovim-nightly-overlay, + neorocks, pre-commit-hooks, neodev-nvim, plenary-nvim, @@ -70,7 +70,7 @@ overlays = [ ci-overlay nvim-plugin-overlay - neovim-nightly-overlay.overlay + neorocks.overlays.default ]; }; diff --git a/lua/neotest-haskell/compat.lua b/lua/neotest-haskell/compat.lua index 2265d73..e430952 100644 --- a/lua/neotest-haskell/compat.lua +++ b/lua/neotest-haskell/compat.lua @@ -13,4 +13,29 @@ compat.joinpath = vim.fs.joinpath or function(...) return (table.concat({ ... }, '/'):gsub('//+', '/')) end +-- TODO: Make `nio` compatible with luassert/busted +-- and then remove this workaround +compat.with_timeout = function(func, timeout) + local tasks = require('nio.tasks') + local success, err + return function() + local task = tasks.run(func, function(success_, err_) + success = success_ + if not success_ then + err = err_ + end + end) + + vim.wait(timeout or 2000, function() + return success ~= nil + end, 20, false) + + if success == nil then + error(string.format('Test task timed out\n%s', task.trace())) + elseif not success then + error(string.format('Test task failed with message:\n%s', err)) + end + end +end + return compat diff --git a/neotest-haskell-scm-1.rockspec b/neotest-haskell-scm-1.rockspec new file mode 100644 index 0000000..bb80b67 --- /dev/null +++ b/neotest-haskell-scm-1.rockspec @@ -0,0 +1,30 @@ +-- NOTE: This rockspec is used for running busted tests only, +-- not for publishing to LuaRocks.org + +local _MODREV, _SPECREV = 'scm', '-1' +rockspec_format = '3.0' +package = 'neotest-haskell' +version = _MODREV .. _SPECREV + +dependencies = { + 'lua >= 5.1', + -- 'neotest', TODO: neotest hasn't been packaged yet +} + +test_dependencies = { + 'lua >= 5.1', + -- 'neotest', + 'busted', +} + +source = { + url = 'git://github.com/mrcjkb/' .. package, +} + +build = { + type = 'builtin', + copy_directories = { + 'doc', + 'queries', + }, +} diff --git a/nix/ci-overlay.nix b/nix/ci-overlay.nix index 0f789e4..3199159 100644 --- a/nix/ci-overlay.nix +++ b/nix/ci-overlay.nix @@ -24,70 +24,54 @@ with final.stdenv; let src = neotest; }; + # NOTE: Only the haskell parser is required nvim-treesitter-plugin = final.pkgs.vimPlugins.nvim-treesitter.withPlugins (p: [p.haskell]); - mkPlenaryTest = { - nvim ? final.neovim-unwrapped, + mkNeorocksTest = { name, + nvim ? final.neovim-unwrapped, + extraPkgs ? [], }: let nvim-wrapped = final.pkgs.wrapNeovim nvim { configure = { - customRC = '' - lua << EOF - vim.cmd('runtime! plugin/plenary.vim') - EOF - ''; packages.myVimPackage = { start = [ - final.neotest-haskell-dev - plenary-plugin - nvim-treesitter-plugin + # Add plugin dependencies that aren't on LuaRocks here neotest-plugin + plenary-plugin # NOTE: dependency of neotest + nvim-treesitter-plugin ]; }; }; }; in - mkDerivation { + final.pkgs.neorocksTest { inherit name; - - phases = [ - "unpackPhase" - "buildPhase" - "checkPhase" - ]; - + pname = "neotest-haskell"; src = self; + neovim = nvim-wrapped; - doCheck = true; + # luaPackages = ps: with ps; []; - buildInputs = with final; [ - nvim-wrapped - makeWrapper - ]; + preCheck = '' + export HOME=$(realpath .) + export TEST_CWD=$(realpath ./tests) + ''; buildPhase = '' mkdir -p $out cp -r tests $out ''; - - checkPhase = '' - export HOME=$(realpath .) - export TEST_CWD=$(realpath $out/tests) - cd $out - nvim --headless --noplugin -c "PlenaryBustedDirectory tests {nvim_cmd = 'nvim'}" - ''; }; in { - nvim-stable-test = mkPlenaryTest {name = "nvim-stable-test";}; - nvim-nightly-test = mkPlenaryTest { - name = "nvim-nightly-test"; + nvim-stable-test = mkNeorocksTest {name = "neovim-stable-tests";}; + nvim-nightly-test = mkNeorocksTest { + name = "neovim-nightly-tests"; nvim = nvim-nightly; }; inherit neodev-plugin plenary-plugin neotest-plugin - nvim-treesitter-plugin ; } diff --git a/tests/hspec_spec.lua b/tests/hspec_spec.lua index 1d01a07..96158f1 100644 --- a/tests/hspec_spec.lua +++ b/tests/hspec_spec.lua @@ -1,6 +1,5 @@ local compat = require('neotest-haskell.compat') local hspec = require('neotest-haskell.hspec') -local async = require('nio').tests local test_cwd = os.getenv('TEST_CWD') @@ -24,122 +23,137 @@ local parse_positions = hspec.parse_positions describe('hspec', function() describe('parse positions', function() - async.it('unqualified imports 0', function() - local test_file = compat.joinpath(test_cwd, 'fixtures/hspec/cabal/simple/test/FirstSpec.hs') + it( + 'unqualified imports 0', + compat.with_timeout(function() + local test_file = compat.joinpath(test_cwd, 'fixtures/hspec/cabal/simple/test/FirstSpec.hs') + local filename = test_file + local result = parse_positions(filename) + local file_pos_id = filename + assert_has_position(result, file_pos_id) + local ns_1_pos_id = file_pos_id .. '::"section 1"' + assert_has_position(result, ns_1_pos_id) + assert_has_position(result, ns_1_pos_id .. '::"is a tautology"') + assert_has_position(result, ns_1_pos_id .. '::"assumes that 2 is 1"') + local ns_2_pos_id = file_pos_id .. '::"section 2"' + assert_has_position(result, ns_2_pos_id) + assert_has_position(result, ns_2_pos_id .. '::"only contains one test"') + end) + ) + end) + it( + 'unqualified imports 1', + compat.with_timeout(function() + local test_file = + compat.joinpath(test_cwd, 'fixtures/hspec/cabal/multi-package/subpackage1/test/Fix1/FixtureSpec.hs') local filename = test_file local result = parse_positions(filename) - local file_pos_id = filename - assert_has_position(result, file_pos_id) - local ns_1_pos_id = file_pos_id .. '::"section 1"' + local filename_pos_id = filename + assert_has_position(result, filename_pos_id) + local ns_1_pos_id = filename_pos_id .. '::"oneOf successful tests"' assert_has_position(result, ns_1_pos_id) - assert_has_position(result, ns_1_pos_id .. '::"is a tautology"') - assert_has_position(result, ns_1_pos_id .. '::"assumes that 2 is 1"') - local ns_2_pos_id = file_pos_id .. '::"section 2"' + assert_has_position(result, ns_1_pos_id .. '::"returns one of the thing"') + assert_has_position(result, ns_1_pos_id .. '::"always has length 1"') + local ns_2_pos_id = ns_1_pos_id .. '::"oneOf failing tests"' assert_has_position(result, ns_2_pos_id) - assert_has_position(result, ns_2_pos_id .. '::"only contains one test"') + assert_has_position(result, ns_2_pos_id .. '::"returns two of the thing"') + assert_has_position(result, ns_1_pos_id .. '::"skipped it"') + assert_has_position(result, ns_1_pos_id .. '::"skipped prop"') + local ns_3_pos_id = ns_1_pos_id .. '::"skipped describe"' + assert_has_position(result, ns_3_pos_id .. '::"implicitly skipped it"') end) - end) - async.it('unqualified imports 1', function() - local test_file = - compat.joinpath(test_cwd, 'fixtures/hspec/cabal/multi-package/subpackage1/test/Fix1/FixtureSpec.hs') - local filename = test_file - local result = parse_positions(filename) - local filename_pos_id = filename - assert_has_position(result, filename_pos_id) - local ns_1_pos_id = filename_pos_id .. '::"oneOf successful tests"' - assert_has_position(result, ns_1_pos_id) - assert_has_position(result, ns_1_pos_id .. '::"returns one of the thing"') - assert_has_position(result, ns_1_pos_id .. '::"always has length 1"') - local ns_2_pos_id = ns_1_pos_id .. '::"oneOf failing tests"' - assert_has_position(result, ns_2_pos_id) - assert_has_position(result, ns_2_pos_id .. '::"returns two of the thing"') - assert_has_position(result, ns_1_pos_id .. '::"skipped it"') - assert_has_position(result, ns_1_pos_id .. '::"skipped prop"') - local ns_3_pos_id = ns_1_pos_id .. '::"skipped describe"' - assert_has_position(result, ns_3_pos_id .. '::"implicitly skipped it"') - end) - async.it('unqualified imports 2', function() - local test_file = - compat.joinpath(test_cwd, 'fixtures/hspec/stack/multi-package/subpackage1/test/Fix1/FixtureSpec.hs') - local filename = test_file - local result = parse_positions(filename) - local filename_pos_id = filename - assert_has_position(result, filename_pos_id) - local ns_1_pos_id = filename_pos_id .. '::"Prelude.head"' - assert_has_position(result, ns_1_pos_id) - assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of a list"') - assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of an arbitrary list"') - local ns_2_pos_id = ns_1_pos_id .. '::"Empty list"' - assert_has_position(result, ns_2_pos_id) - assert_has_position(result, ns_2_pos_id .. '::"Throws on empty list"') - local ns_3_pos_id = filename_pos_id .. '::"Prelude.tail"' - assert_has_position(result, ns_3_pos_id) - local ns_4_pos_id = ns_3_pos_id .. '::"Single element list"' - assert_has_position(result, ns_4_pos_id) - assert_has_position(result, ns_4_pos_id .. '::"Returns the empty list"') - end) - async.it('qualified imports', function() - local test_file = - compat.joinpath(test_cwd, 'fixtures/hspec/cabal/multi-package/subpackage2/test/Fix2/FixtureSpec.hs') - local filename = test_file - local result = parse_positions(filename) - local filename_pos_id = filename - assert_has_position(result, filename_pos_id) - local ns_1_pos_id = filename_pos_id .. '::"twoOf successful tests"' - assert_has_position(result, ns_1_pos_id) - assert_has_position(result, ns_1_pos_id .. '::"returns two of the thing"') - assert_has_position(result, ns_1_pos_id .. '::"always has length 2"') - local ns_2_pos_id = ns_1_pos_id .. '::"twoOf failing tests"' - assert_has_position(result, ns_2_pos_id) - assert_has_position(result, ns_2_pos_id .. '::"returns one of the thing"') - assert_has_position(result, ns_1_pos_id .. '::"skipped it"') - assert_has_position(result, ns_1_pos_id .. '::"skipped prop"') - local ns_3_pos_id = ns_1_pos_id .. '::"skipped describe"' - assert_has_position(result, ns_3_pos_id .. '::"implicitly skipped it"') - end) - - describe('parse results', function() - async.it('test failure', function() + ) + it( + 'unqualified imports 2', + compat.with_timeout(function() local test_file = compat.joinpath(test_cwd, 'fixtures/hspec/stack/multi-package/subpackage1/test/Fix1/FixtureSpec.hs') local filename = test_file - local tree = parse_positions(filename) - local test_result_file = compat.joinpath(test_cwd, 'fixtures/results/hspec_test_file_fail.txt') - local result_filename = test_result_file - local context = { - file = filename, - pos_id = filename, - type = 'file', - } - local results = hspec.parse_results(context, result_filename, tree) - local failure = { - status = 'failed', - errors = { - { - message = 'Falsifiable (after 1 test):\n0\n[]\nexpected: 5\nbut got: 0\n', - }, - }, - } - assert.same(failure, results[filename]) - assert.same({ - status = 'failed', - }, results[filename .. '::"Prelude.head"']) - assert.same({ - status = 'passed', - }, results[filename .. '::"Prelude.head"::"Empty list"']) - assert.same({ - status = 'passed', - }, results[filename .. '::"Prelude.head"::"Empty list"::"Throws on empty list"']) - assert.same({ - status = 'skipped', - }, results[filename .. '::"Prelude.head"::"Returns the first element of a list"']) - assert.same(failure, results[filename .. '::"Prelude.head"::"Returns the first element of an arbitrary list"']) - assert.same({ - status = 'passed', - }, results[filename .. '::"Prelude.tail"']) - assert.same({ - status = 'passed', - }, results[filename .. '::"Prelude.tail"::"Single element list"::"Returns the empty list"']) + local result = parse_positions(filename) + local filename_pos_id = filename + assert_has_position(result, filename_pos_id) + local ns_1_pos_id = filename_pos_id .. '::"Prelude.head"' + assert_has_position(result, ns_1_pos_id) + assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of a list"') + assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of an arbitrary list"') + local ns_2_pos_id = ns_1_pos_id .. '::"Empty list"' + assert_has_position(result, ns_2_pos_id) + assert_has_position(result, ns_2_pos_id .. '::"Throws on empty list"') + local ns_3_pos_id = filename_pos_id .. '::"Prelude.tail"' + assert_has_position(result, ns_3_pos_id) + local ns_4_pos_id = ns_3_pos_id .. '::"Single element list"' + assert_has_position(result, ns_4_pos_id) + assert_has_position(result, ns_4_pos_id .. '::"Returns the empty list"') + end) + ) + it( + 'qualified imports', + compat.with_timeout(function() + local test_file = + compat.joinpath(test_cwd, 'fixtures/hspec/cabal/multi-package/subpackage2/test/Fix2/FixtureSpec.hs') + local filename = test_file + local result = parse_positions(filename) + local filename_pos_id = filename + assert_has_position(result, filename_pos_id) + local ns_1_pos_id = filename_pos_id .. '::"twoOf successful tests"' + assert_has_position(result, ns_1_pos_id) + assert_has_position(result, ns_1_pos_id .. '::"returns two of the thing"') + assert_has_position(result, ns_1_pos_id .. '::"always has length 2"') + local ns_2_pos_id = ns_1_pos_id .. '::"twoOf failing tests"' + assert_has_position(result, ns_2_pos_id) + assert_has_position(result, ns_2_pos_id .. '::"returns one of the thing"') + assert_has_position(result, ns_1_pos_id .. '::"skipped it"') + assert_has_position(result, ns_1_pos_id .. '::"skipped prop"') + local ns_3_pos_id = ns_1_pos_id .. '::"skipped describe"' + assert_has_position(result, ns_3_pos_id .. '::"implicitly skipped it"') end) + ) + + describe('parse results', function() + it( + 'test failure', + compat.with_timeout(function() + local test_file = + compat.joinpath(test_cwd, 'fixtures/hspec/stack/multi-package/subpackage1/test/Fix1/FixtureSpec.hs') + local filename = test_file + local tree = parse_positions(filename) + local test_result_file = compat.joinpath(test_cwd, 'fixtures/results/hspec_test_file_fail.txt') + local result_filename = test_result_file + local context = { + file = filename, + pos_id = filename, + type = 'file', + } + local results = hspec.parse_results(context, result_filename, tree) + local failure = { + status = 'failed', + errors = { + { + message = 'Falsifiable (after 1 test):\n0\n[]\nexpected: 5\nbut got: 0\n', + }, + }, + } + assert.same(failure, results[filename]) + assert.same({ + status = 'failed', + }, results[filename .. '::"Prelude.head"']) + assert.same({ + status = 'passed', + }, results[filename .. '::"Prelude.head"::"Empty list"']) + assert.same({ + status = 'passed', + }, results[filename .. '::"Prelude.head"::"Empty list"::"Throws on empty list"']) + assert.same({ + status = 'skipped', + }, results[filename .. '::"Prelude.head"::"Returns the first element of a list"']) + assert.same(failure, results[filename .. '::"Prelude.head"::"Returns the first element of an arbitrary list"']) + assert.same({ + status = 'passed', + }, results[filename .. '::"Prelude.tail"']) + assert.same({ + status = 'passed', + }, results[filename .. '::"Prelude.tail"::"Single element list"::"Returns the empty list"']) + end) + ) end) end) diff --git a/tests/runner_spec.lua b/tests/runner_spec.lua index 1ba7aeb..98e6282 100644 --- a/tests/runner_spec.lua +++ b/tests/runner_spec.lua @@ -1,5 +1,5 @@ local runner = require('neotest-haskell.runner') -local async = require('nio').tests +local compat = require('neotest-haskell.compat') local simple_cabal_hspec_test_file = 'tests/fixtures/hspec/cabal/simple/test/FirstSpec.hs' local multi_package_cabal_hspec_test_file = @@ -18,35 +18,50 @@ local sydtest = require('neotest-haskell.sydtest') describe('runner', function() describe('select_framework', function() - async.it('selects hspec for hspec file', function() - assert.equals( - hspec, - runner.select_framework(multi_package_cabal_hspec_test_file, { 'sydtest', 'tasty', 'hspec' }) - ) - end) - async.it('selects tasty for tasty file if tasty is specified before hspec', function() - assert.equals( - tasty, - runner.select_framework(multi_package_cabal_tasty_test_file, { 'sydtest', 'tasty', 'hspec' }) - ) - end) - async.it('selects sydtest for sydtest file if sydtest is specified before hspec', function() - assert.equals(sydtest, runner.select_framework(simple_cabal_sydtest_test_file, { 'sydtest', 'tasty', 'hspec' })) - end) - async.it('errors for hspec file if hspec is not specified', function() - assert.errors(function() - runner.select_framework(multi_package_cabal_hspec_test_file, { 'tasty' }) + it( + 'selects hspec for hspec file', + compat.with_timeout(function() + assert.equals( + hspec, + runner.select_framework(multi_package_cabal_hspec_test_file, { 'sydtest', 'tasty', 'hspec' }) + ) end) - end) - async.it('can detect framework by qualified module name', function() - assert.equals( - hspec, - runner.select_framework( - multi_package_cabal_hspec_test_file, - { { framework = 'hspec', modules = { 'Fix1.FixtureSpec' } } } + ) + it( + 'selects tasty for tasty file if tasty is specified before hspec', + compat.with_timeout(function() + assert.equals( + tasty, + runner.select_framework(multi_package_cabal_tasty_test_file, { 'sydtest', 'tasty', 'hspec' }) ) - ) - end) + end) + ) + it( + 'selects sydtest for sydtest file if sydtest is specified before hspec', + compat.with_timeout(function() + assert.equals(sydtest, runner.select_framework(simple_cabal_sydtest_test_file, { 'sydtest', 'tasty', 'hspec' })) + end) + ) + it( + 'errors for hspec file if hspec is not specified', + compat.with_timeout(function() + assert.errors(function() + runner.select_framework(multi_package_cabal_hspec_test_file, { 'tasty' }) + end) + end) + ) + it( + 'can detect framework by qualified module name', + compat.with_timeout(function() + assert.equals( + hspec, + runner.select_framework( + multi_package_cabal_hspec_test_file, + { { framework = 'hspec', modules = { 'Fix1.FixtureSpec' } } } + ) + ) + end) + ) end) describe('select_build_tool', function() diff --git a/tests/sydtest_spec.lua b/tests/sydtest_spec.lua index d520b10..0d33efb 100644 --- a/tests/sydtest_spec.lua +++ b/tests/sydtest_spec.lua @@ -1,6 +1,5 @@ local sydtest = require('neotest-haskell.sydtest') local compat = require('neotest-haskell.compat') -local async = require('nio').tests local test_cwd = os.getenv('TEST_CWD') @@ -24,48 +23,54 @@ local parse_positions = sydtest.parse_positions describe('sydtest', function() local test_file = compat.joinpath(test_cwd, 'fixtures/sydtest/cabal/simple/test/SydtestFixtureSpec.hs') - async.it('parse positions', function() - local filename = test_file - local result = parse_positions(filename) - local file_pos_id = filename - assert_has_position(result, file_pos_id) - local ns_1_pos_id = file_pos_id .. '::"Prelude.head"' - assert_has_position(result, ns_1_pos_id) - assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of a list"') - assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of an arbitrary list"') - local ns_2_pos_id = ns_1_pos_id .. '::"Empty list"' - assert_has_position(result, ns_2_pos_id) - assert_has_position(result, ns_2_pos_id .. '::"Throws on empty list"') - local ns_3_pos_id = file_pos_id .. '::"Prelude.tail"' - assert_has_position(result, ns_3_pos_id) - local ns_4_pos_id = ns_3_pos_id .. '::"Single element list"' - assert_has_position(result, ns_4_pos_id) - assert_has_position(result, ns_4_pos_id .. '::"Returns the empty list"') - end) - describe('parse results', function() - async.it('test failure', function() + it( + 'parse positions', + compat.with_timeout(function() local filename = test_file - local tree = parse_positions(filename) - local test_result_file = compat.joinpath(test_cwd, 'fixtures/sydtest/results/failure.txt') - local result_filename = test_result_file - local context = { - file = filename, - pos_id = filename, - type = 'file', - } - local results = sydtest.parse_results(context, result_filename, tree) - assert.same('failed', results[filename].status) - assert.same('failed', results[filename .. '::"Prelude.head"'].status) - assert.same({ - status = 'skipped', - }, results[filename .. '::"Prelude.head"::"Returns the first element of a list"']) - assert.same( - 'failed', - results[filename .. '::"Prelude.head"::"Returns the first element of an arbitrary list"'].status - ) - assert.same({ - status = 'passed', - }, results[filename .. '::"Prelude.head"::"Empty list"::"Throws on empty list"']) + local result = parse_positions(filename) + local file_pos_id = filename + assert_has_position(result, file_pos_id) + local ns_1_pos_id = file_pos_id .. '::"Prelude.head"' + assert_has_position(result, ns_1_pos_id) + assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of a list"') + assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of an arbitrary list"') + local ns_2_pos_id = ns_1_pos_id .. '::"Empty list"' + assert_has_position(result, ns_2_pos_id) + assert_has_position(result, ns_2_pos_id .. '::"Throws on empty list"') + local ns_3_pos_id = file_pos_id .. '::"Prelude.tail"' + assert_has_position(result, ns_3_pos_id) + local ns_4_pos_id = ns_3_pos_id .. '::"Single element list"' + assert_has_position(result, ns_4_pos_id) + assert_has_position(result, ns_4_pos_id .. '::"Returns the empty list"') end) + ) + describe('parse results', function() + it( + 'test failure', + compat.with_timeout(function() + local filename = test_file + local tree = parse_positions(filename) + local test_result_file = compat.joinpath(test_cwd, 'fixtures/sydtest/results/failure.txt') + local result_filename = test_result_file + local context = { + file = filename, + pos_id = filename, + type = 'file', + } + local results = sydtest.parse_results(context, result_filename, tree) + assert.same('failed', results[filename].status) + assert.same('failed', results[filename .. '::"Prelude.head"'].status) + assert.same({ + status = 'skipped', + }, results[filename .. '::"Prelude.head"::"Returns the first element of a list"']) + assert.same( + 'failed', + results[filename .. '::"Prelude.head"::"Returns the first element of an arbitrary list"'].status + ) + assert.same({ + status = 'passed', + }, results[filename .. '::"Prelude.head"::"Empty list"::"Throws on empty list"']) + end) + ) end) end) diff --git a/tests/tasty_spec.lua b/tests/tasty_spec.lua index 7090493..5f25a3f 100644 --- a/tests/tasty_spec.lua +++ b/tests/tasty_spec.lua @@ -1,7 +1,6 @@ local tasty = require('neotest-haskell.tasty') local compat = require('neotest-haskell.compat') local has_position = require('neotest-haskell.position').has_position -local async = require('nio').tests local test_cwd = os.getenv('TEST_CWD') @@ -15,98 +14,104 @@ local test_file = compat.joinpath(test_cwd, 'fixtures/tasty/cabal/multi-package/ local test_filename = test_file describe('tasty', function() - async.it('parse positions', function() - local result = parse_positions(test_filename) - local file_pos_id = test_filename - assert_has_position(result, file_pos_id) - local smallcheck_ns = test_filename .. '::"(checked by SmallCheck)"' - assert_has_position(result, smallcheck_ns) - assert_has_position(result, smallcheck_ns .. '::"sort == sort . reverse"') - assert_has_position(result, smallcheck_ns .. '::"Fermat\'s little theorem"') - assert_has_position(result, smallcheck_ns .. '::"Fermat\'s last theorem"') - local quickcheck_ns = test_filename .. '::"(checked by QuickCheck)"' - assert_has_position(result, quickcheck_ns) - assert_has_position(result, quickcheck_ns .. '::"sort == sort . reverse"') - assert_has_position(result, quickcheck_ns .. '::"Fermat\'s little theorem"') - assert_has_position(result, quickcheck_ns .. '::"Fermat\'s last theorem"') - local unit_ns = test_filename .. '::"Unit tests"' - assert_has_position(result, unit_ns) - assert_has_position(result, unit_ns .. '::"List comparison (different length)"') - assert_has_position(result, unit_ns .. '::"List comparison (same length)"') - local hspec_ns = test_filename .. '::"Hspec specs"' - assert_has_position(result, hspec_ns) - assert_has_position(result, hspec_ns .. '::"Prelude.head"') - assert_has_position(result, hspec_ns .. '::"Prelude.head"::"returns the first element of a list"') - local hedgehog_ns = test_filename .. '::"Hedgehog tests"' - assert_has_position(result, hedgehog_ns) - assert_has_position(result, hedgehog_ns .. '::"reverse involutive"') - assert_has_position(result, hedgehog_ns .. '::"badReverse involutive fails"') - local leancheck_ns = test_filename .. '::"LeanCheck tests"' - assert_has_position(result, leancheck_ns) - assert_has_position(result, leancheck_ns .. '::"sort == sort . reverse"') - assert_has_position(result, leancheck_ns .. '::"Fermat\'s little theorem"') - assert_has_position(result, leancheck_ns .. '::"Fermat\'s last theorem"') - local program_ns = test_filename .. '::"Compilation with GHC"' - assert_has_position(result, program_ns) - assert_has_position(result, program_ns .. '::"Foo"') - local wai_ns = test_filename .. '::"Tasty-Wai Tests"' - assert_has_position(result, wai_ns) - assert_has_position(result, wai_ns .. '::"Hello to World"') - assert_has_position(result, wai_ns .. '::"Echo to thee"') - assert_has_position(result, wai_ns .. '::"Echo to thee (json)"') - assert_has_position(result, wai_ns .. '::"Will die!"') - local golden_ns = test_filename .. '::"Golden tests"' - assert_has_position(result, golden_ns) - assert_has_position(result, golden_ns .. '::"goldenVsFile"') - assert_has_position(result, golden_ns .. '::"goldenVsString"') - assert_has_position(result, golden_ns .. '::"goldenVsFileDiff"') - assert_has_position(result, golden_ns .. '::"goldenVsStringDiff"') - end) + it( + 'parse positions', + compat.with_timeout(function() + local result = parse_positions(test_filename) + local file_pos_id = test_filename + assert_has_position(result, file_pos_id) + local smallcheck_ns = test_filename .. '::"(checked by SmallCheck)"' + assert_has_position(result, smallcheck_ns) + assert_has_position(result, smallcheck_ns .. '::"sort == sort . reverse"') + assert_has_position(result, smallcheck_ns .. '::"Fermat\'s little theorem"') + assert_has_position(result, smallcheck_ns .. '::"Fermat\'s last theorem"') + local quickcheck_ns = test_filename .. '::"(checked by QuickCheck)"' + assert_has_position(result, quickcheck_ns) + assert_has_position(result, quickcheck_ns .. '::"sort == sort . reverse"') + assert_has_position(result, quickcheck_ns .. '::"Fermat\'s little theorem"') + assert_has_position(result, quickcheck_ns .. '::"Fermat\'s last theorem"') + local unit_ns = test_filename .. '::"Unit tests"' + assert_has_position(result, unit_ns) + assert_has_position(result, unit_ns .. '::"List comparison (different length)"') + assert_has_position(result, unit_ns .. '::"List comparison (same length)"') + local hspec_ns = test_filename .. '::"Hspec specs"' + assert_has_position(result, hspec_ns) + assert_has_position(result, hspec_ns .. '::"Prelude.head"') + assert_has_position(result, hspec_ns .. '::"Prelude.head"::"returns the first element of a list"') + local hedgehog_ns = test_filename .. '::"Hedgehog tests"' + assert_has_position(result, hedgehog_ns) + assert_has_position(result, hedgehog_ns .. '::"reverse involutive"') + assert_has_position(result, hedgehog_ns .. '::"badReverse involutive fails"') + local leancheck_ns = test_filename .. '::"LeanCheck tests"' + assert_has_position(result, leancheck_ns) + assert_has_position(result, leancheck_ns .. '::"sort == sort . reverse"') + assert_has_position(result, leancheck_ns .. '::"Fermat\'s little theorem"') + assert_has_position(result, leancheck_ns .. '::"Fermat\'s last theorem"') + local program_ns = test_filename .. '::"Compilation with GHC"' + assert_has_position(result, program_ns) + assert_has_position(result, program_ns .. '::"Foo"') + local wai_ns = test_filename .. '::"Tasty-Wai Tests"' + assert_has_position(result, wai_ns) + assert_has_position(result, wai_ns .. '::"Hello to World"') + assert_has_position(result, wai_ns .. '::"Echo to thee"') + assert_has_position(result, wai_ns .. '::"Echo to thee (json)"') + assert_has_position(result, wai_ns .. '::"Will die!"') + local golden_ns = test_filename .. '::"Golden tests"' + assert_has_position(result, golden_ns) + assert_has_position(result, golden_ns .. '::"goldenVsFile"') + assert_has_position(result, golden_ns .. '::"goldenVsString"') + assert_has_position(result, golden_ns .. '::"goldenVsFileDiff"') + assert_has_position(result, golden_ns .. '::"goldenVsStringDiff"') + end) + ) describe('parse results', function() - async.it('test failure', function() - local tree = parse_positions(test_filename) - local test_result_file = compat.joinpath(test_cwd, 'fixtures/results/tasty_test_file_fail.txt') - local result_filename = test_result_file - local context = { - file = test_filename, - pos_id = test_filename, - type = 'file', - } - local results = tasty.parse_results(context, result_filename, tree) - assert.same('failed', results[test_filename].status) - assert.same({ - status = 'passed', - }, results[test_filename .. '::"(checked by SmallCheck)"::"sort == sort . reverse"']) - assert.same({ - status = 'passed', - }, results[test_filename .. '::"(checked by SmallCheck)"::"Fermat\'s little theorem"']) - assert.same({ - status = 'failed', - errors = { - { - message = 'there exist 0 0 0 3 such that\ncondition is false', + it( + 'test failure', + compat.with_timeout(function() + local tree = parse_positions(test_filename) + local test_result_file = compat.joinpath(test_cwd, 'fixtures/results/tasty_test_file_fail.txt') + local result_filename = test_result_file + local context = { + file = test_filename, + pos_id = test_filename, + type = 'file', + } + local results = tasty.parse_results(context, result_filename, tree) + assert.same('failed', results[test_filename].status) + assert.same({ + status = 'passed', + }, results[test_filename .. '::"(checked by SmallCheck)"::"sort == sort . reverse"']) + assert.same({ + status = 'passed', + }, results[test_filename .. '::"(checked by SmallCheck)"::"Fermat\'s little theorem"']) + assert.same({ + status = 'failed', + errors = { + { + message = 'there exist 0 0 0 3 such that\ncondition is false', + }, }, - }, - }, results[test_filename .. '::"(checked by SmallCheck)"::"Fermat\'s last theorem"']) - assert.same({ - status = 'passed', - }, results[test_filename .. '::"(checked by QuickCheck)"::"Fermat\'s little theorem"']) - assert.same('failed', results[test_filename .. '::"Hedgehog tests"::"badReverse involutive fails"'].status) - assert.same({ - status = 'passed', - }, results[test_filename .. '::"Hedgehog tests"::"reverse involutive"']) - assert.same({ - status = 'skipped', - }, results[test_filename .. '::"Hspec specs"::"Prelude.head"::"returns the first element of a list"']) - assert.same({ - status = 'failed', - errors = { - { - message = 'Program /run/current-system/sw/bin/ghc failed with code 1', + }, results[test_filename .. '::"(checked by SmallCheck)"::"Fermat\'s last theorem"']) + assert.same({ + status = 'passed', + }, results[test_filename .. '::"(checked by QuickCheck)"::"Fermat\'s little theorem"']) + assert.same('failed', results[test_filename .. '::"Hedgehog tests"::"badReverse involutive fails"'].status) + assert.same({ + status = 'passed', + }, results[test_filename .. '::"Hedgehog tests"::"reverse involutive"']) + assert.same({ + status = 'skipped', + }, results[test_filename .. '::"Hspec specs"::"Prelude.head"::"returns the first element of a list"']) + assert.same({ + status = 'failed', + errors = { + { + message = 'Program /run/current-system/sw/bin/ghc failed with code 1', + }, }, - }, - }, results[test_filename .. '::"Compilation with GHC"::"Foo"']) - end) + }, results[test_filename .. '::"Compilation with GHC"::"Foo"']) + end) + ) end) end)