Skip to content

Commit 466efb2

Browse files
authored
feat: modernize testing infrastructure with plenary.nvim (#12)
Replace custom test runner with plenary.nvim framework for better maintainability and standard Neovim plugin testing patterns. Add justfile for development tasks, luacheck configuration, and matrix CI testing for stable/nightly Neovim versions.
1 parent f378f14 commit 466efb2

File tree

9 files changed

+548
-222
lines changed

9 files changed

+548
-222
lines changed

.github/workflows/test.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ on:
88

99
jobs:
1010
test:
11+
strategy:
12+
matrix:
13+
neovim-version: ['stable', 'nightly']
1114
runs-on: ubuntu-latest
1215

1316
steps:
@@ -17,7 +20,14 @@ jobs:
1720
uses: rhysd/action-setup-vim@v1
1821
with:
1922
neovim: true
20-
version: stable
23+
version: ${{ matrix.neovim-version }}
24+
25+
- name: Install plenary.nvim
26+
run: |
27+
mkdir -p ~/.local/share/nvim/lazy/plenary.nvim
28+
git clone --depth=1 https://github.com/nvim-lua/plenary.nvim.git ~/.local/share/nvim/lazy/plenary.nvim
2129
2230
- name: Run tests
23-
run: nvim --headless -c "luafile tests/integration_test.lua" -c "qa!"
31+
run: |
32+
nvim --headless --noplugin -u tests/minimal_init.lua \
33+
-c "lua require('plenary.test_harness').test_directory('tests', {minimal_init = 'tests/minimal_init.lua'})"

.luacheckrc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
std = "luajit"
2+
3+
globals = {
4+
"vim",
5+
}
6+
7+
read_globals = {
8+
"vim",
9+
}
10+
11+
exclude_files = {
12+
".luarocks",
13+
"lua_modules",
14+
"tests/minimal_init.lua",
15+
}
16+
17+
ignore = {
18+
"212", -- Unused argument
19+
"213", -- Unused loop variable
20+
"431", -- Shadowing upvalue
21+
"432", -- Shadowing upvalue argument
22+
}
23+
24+
max_line_length = 100
25+
max_cyclomatic_complexity = 15
26+
27+
files = {
28+
"lua/marksman/",
29+
"tests/",
30+
}
31+
32+
files["tests/"] = {
33+
ignore = {
34+
"211", -- Unused local variable
35+
"212", -- Unused argument
36+
"213", -- Unused loop variable
37+
},
38+
}

CONTRIBUTING.md

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,27 @@ Thank you for your interest in contributing to Marksman.nvim! This document prov
1414
### Prerequisites
1515
- Neovim >= 0.8.0
1616
- Git
17-
- Lua 5.1+ (for testing outside Neovim)
17+
- [just](https://github.com/casey/just) command runner (or make)
18+
- [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) for testing
19+
20+
### Quick Start
21+
```bash
22+
# Install dependencies
23+
just install-deps
24+
25+
# Run tests
26+
just test
27+
28+
# Run specific test
29+
just test-file tests/marksman_spec.lua
30+
31+
# Watch tests (requires entr)
32+
just test-watch
33+
34+
# Lint and format
35+
just lint
36+
just format
37+
```
1838

1939
### Code Quality Tools
2040
```bash
@@ -25,10 +45,10 @@ luarocks install luacheck
2545
cargo install stylua
2646

2747
# Run linting
28-
luacheck lua/
48+
just lint
2949

3050
# Run formatting
31-
stylua lua/
51+
just format
3252
```
3353

3454
## Code Style
@@ -64,6 +84,10 @@ lua/marksman/
6484
├── storage.lua -- Mark persistence and project management
6585
├── ui.lua -- Floating window and interface
6686
└── utils.lua -- Utilities and validation
87+
88+
tests/
89+
├── minimal_init.lua -- Test environment setup
90+
└── marksman_spec.lua -- Main test suite
6791
```
6892

6993
## Contribution Types
@@ -77,7 +101,7 @@ lua/marksman/
77101
### New Features
78102
1. **Discuss the feature** in an issue first
79103
2. **Ensure it aligns** with the plugin's focused scope
80-
3. **Write comprehensive documentation**
104+
3. **Write comprehensive tests**
81105
4. **Add configuration options** if needed
82106

83107
### Documentation
@@ -87,11 +111,35 @@ lua/marksman/
87111

88112
## Testing Guidelines
89113

90-
### Manual Testing
91-
- Test with **multiple projects**
92-
- Verify **mark persistence** across sessions
93-
- Test **edge cases** (empty files, special characters)
94-
- Check **memory usage** with large mark sets
114+
### Test Framework
115+
We use [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) for testing with a describe/it structure:
116+
117+
```lua
118+
describe("feature", function()
119+
before_each(function()
120+
-- Setup code
121+
end)
122+
123+
it("does something", function()
124+
assert.is_true(some_condition)
125+
end)
126+
end)
127+
```
128+
129+
### Running Tests
130+
```bash
131+
# Run all tests
132+
just test
133+
134+
# Run specific test file
135+
just test-file tests/marksman_spec.lua
136+
137+
# Watch tests (auto-run on file changes)
138+
just test-watch
139+
140+
# Clean test artifacts
141+
just clean
142+
```
95143

96144
### Test Scenarios
97145
1. **Basic Operations**:
@@ -113,6 +161,12 @@ lua/marksman/
113161
- Keyboard navigation
114162
- Search and filtering
115163

164+
### Writing Tests
165+
- Use descriptive test names
166+
- Test both success and failure cases
167+
- Clean up resources in `after_each`
168+
- Mock external dependencies when needed
169+
116170
## Performance Considerations
117171

118172
### Memory Efficiency
@@ -190,9 +244,10 @@ require("marksman").setup({
190244

191245
### Before Submitting
192246
1. **Test thoroughly** on your system
193-
2. **Run linting** and fix issues
194-
3. **Update documentation** if needed
195-
4. **Rebase on main** branch
247+
2. **Run linting** and fix issues: `just lint`
248+
3. **Format code**: `just format`
249+
4. **Update documentation** if needed
250+
5. **Rebase on main** branch
196251

197252
### PR Description Template
198253
```markdown

justfile

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Install plenary.nvim if not present
2+
install-deps:
3+
#!/usr/bin/env bash
4+
if [ ! -d "$HOME/.local/share/nvim/lazy/plenary.nvim" ]; then
5+
echo "Installing plenary.nvim..."
6+
mkdir -p "$HOME/.local/share/nvim/lazy/plenary.nvim"
7+
git clone --depth=1 https://github.com/nvim-lua/plenary.nvim.git "$HOME/.local/share/nvim/lazy/plenary.nvim"
8+
fi
9+
10+
# Run all tests
11+
test: install-deps
12+
nvim --headless --noplugin -u tests/minimal_init.lua \
13+
-c "lua require('plenary.test_harness').test_directory('tests', {minimal_init = 'tests/minimal_init.lua'})"
14+
15+
# Run specific test file
16+
test-file FILE: install-deps
17+
nvim --headless --noplugin -u tests/minimal_init.lua \
18+
-c "lua require('plenary.busted').run('{{FILE}}')"
19+
20+
# Watch tests (requires entr: brew install entr or apt install entr)
21+
test-watch:
22+
find lua/ tests/ -name "*.lua" | entr -c just test
23+
24+
# Clean test artifacts
25+
clean:
26+
rm -rf /tmp/*marksman_test*
27+
28+
# Lint code
29+
lint:
30+
#!/usr/bin/env bash
31+
if command -v luacheck >/dev/null; then
32+
luacheck lua/
33+
else
34+
echo "luacheck not found. Install with: luarocks install luacheck"
35+
fi
36+
37+
# Format code
38+
format:
39+
#!/usr/bin/env bash
40+
if command -v stylua >/dev/null; then
41+
stylua lua/ tests/
42+
else
43+
echo "stylua not found. Install with: cargo install stylua"
44+
fi

lua/marksman/storage.lua

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ end
2929
---@return string project_root The project root directory
3030
local function get_project_root()
3131
local current_dir = vim.fn.expand("%:p:h")
32-
32+
3333
-- Check cache first (expires after 30 seconds)
3434
local cache_key = current_dir
3535
local now = os.time()
@@ -103,13 +103,13 @@ local function get_marks_file()
103103
if not project then
104104
error("Could not determine project root")
105105
end
106-
106+
107107
local hash = vim.fn.sha256(project):sub(1, 8)
108108
local data_path = vim.fn.stdpath("data")
109109
if not data_path then
110110
error("Could not get Neovim data directory")
111111
end
112-
112+
113113
return data_path .. "/marksman_" .. hash .. ".json"
114114
end
115115

@@ -174,26 +174,26 @@ local function validate_marks_data(data)
174174
if type(name) ~= "string" or name == "" then
175175
return false, "Mark names must be non-empty strings"
176176
end
177-
177+
178178
if type(mark) ~= "table" then
179179
return false, "Mark data must be a table"
180180
end
181-
181+
182182
local required_fields = { "file", "line", "col" }
183183
for _, field in ipairs(required_fields) do
184184
if not mark[field] then
185185
return false, "Missing required field: " .. field
186186
end
187187
end
188-
188+
189189
if type(mark.line) ~= "number" or mark.line < 1 then
190190
return false, "Line must be a positive number"
191191
end
192-
192+
193193
if type(mark.col) ~= "number" or mark.col < 1 then
194194
return false, "Column must be a positive number"
195195
end
196-
196+
197197
if type(mark.file) ~= "string" or mark.file == "" then
198198
return false, "File must be a non-empty string"
199199
end
@@ -298,7 +298,7 @@ function M.save_marks()
298298
saved_at = os.date("%Y-%m-%d %H:%M:%S"),
299299
project = current_project,
300300
}
301-
301+
302302
local json = vim.json.encode(data)
303303
if not json then
304304
error("Failed to encode marks data")
@@ -608,7 +608,7 @@ function M.import_marks()
608608
for name, mark in pairs(data.marks) do
609609
marks_data[name] = mark
610610
end
611-
611+
612612
-- Merge order arrays, avoiding duplicates
613613
if data.mark_order then
614614
for _, name in ipairs(data.mark_order) do
@@ -665,7 +665,7 @@ function M.cleanup()
665665
-- Clear caches
666666
project_root_cache = {}
667667
cache_expiry = {}
668-
668+
669669
-- Reset state
670670
marks = {}
671671
mark_order = {}

0 commit comments

Comments
 (0)