---@diagnostic disable: undefined-field, need-check-nil, param-type-mismatch local version = require('fff.utils.version') describe('fff.utils.version', function() local repo_root before_each(function() repo_root = vim.fn.fnamemodify(debug.getinfo(1, 'S').source:sub(2), ':h:h') if vim.fn.isdirectory(repo_root) ~= 1 then repo_root = vim.fn.getcwd() end end) describe('read_base_version', function() it('should read version from Cargo.toml', function() local ver = version.read_base_version(repo_root) assert.is_not_nil(ver) assert.is_string(ver) assert.is_truthy(ver:match('^%d+%.%d+%.%d+'), 'expected semver, got: ' .. ver) end) it( 'should return nil for missing directory', function() assert.is_nil(version.read_base_version('/nonexistent_path_12345')) end ) it('should parse version from a temp Cargo.toml', function() local tmp = vim.fn.tempname() vim.fn.mkdir(tmp .. '/crates/fff-core', 'p') local f = io.open(tmp .. '/crates/fff-core/Cargo.toml', 'w') f:write('[package]\nname = "test"\nversion = "1.2.3"\n') f:close() assert.are.equal('1.2.3', version.read_base_version(tmp)) vim.fn.delete(tmp, 'rf') end) end) describe('current_release_tag', function() it('should return a string or nil for the real repo', function() local tag = version.current_release_tag(repo_root) -- On CI the commit has a tag; locally it might not if tag then assert.is_string(tag) else assert.is_nil(tag) end end) it('should return nil for a repo with no tags', function() local tmp = vim.fn.tempname() vim.fn.mkdir(tmp, 'p') vim.fn.system({ 'git', 'init', '-q', tmp }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.email', 'test@test.com' }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.name', 'Test' }) local f = io.open(tmp .. '/file.txt', 'w') f:write('hello') f:close() vim.fn.system({ 'git', '-C', tmp, 'add', '.' }) vim.fn.system({ 'git', '-C', tmp, 'commit', '-q', '-m', 'init' }) assert.is_nil(version.current_release_tag(tmp)) vim.fn.delete(tmp, 'rf') end) it('should prefer v* tags over nightly/dev/legacy', function() local tmp = vim.fn.tempname() vim.fn.mkdir(tmp, 'p') vim.fn.system({ 'git', 'init', '-q', tmp }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.email', 'test@test.com' }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.name', 'Test' }) local f = io.open(tmp .. '/file.txt', 'w') f:write('hello') f:close() vim.fn.system({ 'git', '-C', tmp, 'add', '.' }) vim.fn.system({ 'git', '-C', tmp, 'commit', '-q', '-m', 'init' }) -- Add multiple tags on the same commit vim.fn.system({ 'git', '-C', tmp, 'tag', '0.4.0-dev.abc1234' }) vim.fn.system({ 'git', '-C', tmp, 'tag', '0.4.0-nightly.abc1234' }) vim.fn.system({ 'git', '-C', tmp, 'tag', 'v0.4.0' }) vim.fn.system({ 'git', '-C', tmp, 'tag', 'deadbeef' }) assert.are.equal('v0.4.0', version.current_release_tag(tmp)) vim.fn.delete(tmp, 'rf') end) it('should prefer nightly over dev', function() local tmp = vim.fn.tempname() vim.fn.mkdir(tmp, 'p') vim.fn.system({ 'git', 'init', '-q', tmp }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.email', 'test@test.com' }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.name', 'Test' }) local f = io.open(tmp .. '/file.txt', 'w') f:write('hello') f:close() vim.fn.system({ 'git', '-C', tmp, 'add', '.' }) vim.fn.system({ 'git', '-C', tmp, 'commit', '-q', '-m', 'init' }) vim.fn.system({ 'git', '-C', tmp, 'tag', '0.4.0-dev.abc1234' }) vim.fn.system({ 'git', '-C', tmp, 'tag', '0.4.0-nightly.abc1234' }) assert.are.equal('0.4.0-nightly.abc1234', version.current_release_tag(tmp)) vim.fn.delete(tmp, 'rf') end) end) describe('resolve', function() it('should resolve a version from the real repo', function() local info, err = version.resolve(repo_root) assert.is_nil(err) assert.is_not_nil(info) assert.is_string(info.version) assert.is_string(info.release_tag) assert.is_string(info.npm_tag) assert.is_not_nil(info.is_release) end) it('should produce a version higher than Cargo.toml base', function() local info = version.resolve(repo_root) local base = version.read_base_version(repo_root) assert.is_not_nil(info) assert.is_not_nil(base) -- For prereleases, patch is bumped: 0.4.0 → 0.4.1-nightly.{sha} if not info.is_release then local base_major, base_minor, base_patch = base:match('^(%d+)%.(%d+)%.(%d+)') local expected_patch = tostring(tonumber(base_patch) + 1) assert.is_truthy( info.version:find(base_major .. '%.' .. base_minor .. '%.' .. expected_patch), 'version "' .. info.version .. '" should have bumped patch from base "' .. base .. '"' ) end end) it('should return dev on a non-main branch', function() local tmp = vim.fn.tempname() vim.fn.mkdir(tmp .. '/crates/fff-core', 'p') vim.fn.system({ 'git', 'init', '-q', tmp }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.email', 'test@test.com' }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.name', 'Test' }) local f = io.open(tmp .. '/crates/fff-core/Cargo.toml', 'w') f:write('[package]\nname = "test"\nversion = "1.0.0"\nedition = "2024"\n') f:close() vim.fn.system({ 'git', '-C', tmp, 'add', '.' }) vim.fn.system({ 'git', '-C', tmp, 'commit', '-q', '-m', 'init' }) vim.fn.system({ 'git', '-C', tmp, 'checkout', '-b', 'feature-x' }) local info = version.resolve(tmp) assert.is_not_nil(info) assert.are.equal('dev', info.npm_tag) assert.is_false(info.is_release) assert.is_truthy(info.version:find('-dev%.'), 'expected dev prerelease, got: ' .. info.version) assert.is_truthy(info.version:find('^1%.0%.1%-'), 'expected bumped patch 1.0.1, got: ' .. info.version) vim.fn.delete(tmp, 'rf') end) it('should return nightly on main branch', function() local tmp = vim.fn.tempname() vim.fn.mkdir(tmp .. '/crates/fff-core', 'p') vim.fn.system({ 'git', 'init', '-q', '-b', 'main', tmp }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.email', 'test@test.com' }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.name', 'Test' }) local f = io.open(tmp .. '/crates/fff-core/Cargo.toml', 'w') f:write('[package]\nname = "test"\nversion = "2.0.0"\nedition = "2024"\n') f:close() vim.fn.system({ 'git', '-C', tmp, 'add', '.' }) vim.fn.system({ 'git', '-C', tmp, 'commit', '-q', '-m', 'init' }) local info = version.resolve(tmp) assert.is_not_nil(info) assert.are.equal('nightly', info.npm_tag) assert.is_false(info.is_release) assert.is_truthy(info.version:find('2%.0%.1%-nightly%.'), 'expected 2.0.1-nightly, got: ' .. info.version) vim.fn.delete(tmp, 'rf') end) it('should return stable release for v* tagged commit', function() local tmp = vim.fn.tempname() vim.fn.mkdir(tmp .. '/crates/fff-core', 'p') vim.fn.system({ 'git', 'init', '-q', tmp }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.email', 'test@test.com' }) vim.fn.system({ 'git', '-C', tmp, 'config', 'user.name', 'Test' }) local f = io.open(tmp .. '/crates/fff-core/Cargo.toml', 'w') f:write('[package]\nname = "test"\nversion = "3.0.0"\nedition = "2024"\n') f:close() vim.fn.system({ 'git', '-C', tmp, 'add', '.' }) vim.fn.system({ 'git', '-C', tmp, 'commit', '-q', '-m', 'release' }) vim.fn.system({ 'git', '-C', tmp, 'tag', 'v3.0.0' }) local info = version.resolve(tmp) assert.is_not_nil(info) assert.are.equal('v3.0.0', info.release_tag) assert.are.equal('3.0.0', info.version) assert.are.equal('latest', info.npm_tag) assert.is_true(info.is_release) vim.fn.delete(tmp, 'rf') end) it('should fail for a non-git directory', function() local tmp = vim.fn.tempname() vim.fn.mkdir(tmp .. '/crates/fff-core', 'p') local f = io.open(tmp .. '/crates/fff-core/Cargo.toml', 'w') f:write('[package]\nname = "test"\nversion = "1.0.0"\n') f:close() local info, err = version.resolve(tmp) assert.is_nil(info) assert.is_not_nil(err) vim.fn.delete(tmp, 'rf') end) end) end)