also looking at this
test: give the exported VersionResolver its first tests
#1438
1 file
+97
-0
| @@ -0,0 +1,97 @@ | ||
| 1 | import { describe, expect, it } from 'bun:test' | |
| 2 | import { VersionResolver } from '../src/version/version-resolver' | |
| 3 | ||
| 4 | /** | |
| 5 | * Publicly exported from the package root and referenced by no test — the | |
| 6 | * last module on the dossier's zero-coverage list. Nothing inside buddy | |
| 7 | * calls it either (the scanner classifies versions through | |
| 8 | * `utils/helpers.getUpdateType`), so these tests are the only thing standing | |
| 9 | * between the exported API and silent breakage. | |
| 10 | */ | |
| 11 | describe('VersionResolver', () => { | |
| 12 | describe('compareVersions', () => { | |
| 13 | it('success case - orders versions numerically, not lexically', () => { | |
| 14 | // '1.10.0' sorts after '1.2.3' as a version and before it as a string. | |
| 15 | expect(VersionResolver.compareVersions('1.2.3', '1.10.0')).toBe(-1) | |
| 16 | expect(VersionResolver.compareVersions('1.10.0', '1.2.3')).toBe(1) | |
| 17 | expect(VersionResolver.compareVersions('1.2.3', '1.2.3')).toBe(0) | |
| 18 | }) | |
| 19 | }) | |
| 20 | ||
| 21 | describe('satisfiesRange', () => { | |
| 22 | it('success case - honours caret and tilde semantics', () => { | |
| 23 | expect(VersionResolver.satisfiesRange('1.4.2', '^1.0.0')).toBe(true) | |
| 24 | expect(VersionResolver.satisfiesRange('2.0.0', '^1.0.0')).toBe(false) | |
| 25 | expect(VersionResolver.satisfiesRange('1.2.9', '~1.2.3')).toBe(true) | |
| 26 | expect(VersionResolver.satisfiesRange('1.3.0', '~1.2.3')).toBe(false) | |
| 27 | }) | |
| 28 | }) | |
| 29 | ||
| 30 | describe('getLatestInRange', () => { | |
| 31 | it('success case - picks the highest satisfying version', () => { | |
| 32 | const versions = ['1.0.0', '1.4.2', '1.10.0', '2.0.0'] | |
| 33 | ||
| 34 | expect(VersionResolver.getLatestInRange(versions, '^1.0.0')).toBe('1.10.0') | |
| 35 | }) | |
| 36 | ||
| 37 | it('failure case - returns null when nothing satisfies', () => { | |
| 38 | expect(VersionResolver.getLatestInRange(['1.0.0', '1.4.2'], '^3.0.0')).toBeNull() | |
| 39 | }) | |
| 40 | ||
| 41 | it('edge case - an empty list has no latest', () => { | |
| 42 | expect(VersionResolver.getLatestInRange([], '^1.0.0')).toBeNull() | |
| 43 | }) | |
| 44 | }) | |
| 45 | ||
| 46 | describe('createRange', () => { | |
| 47 | it('success case - a caret range parses with its operator stripped', () => { | |
| 48 | const range = VersionResolver.createRange('^1.2.3') | |
| 49 | ||
| 50 | expect(range.raw).toBe('^1.2.3') | |
| 51 | expect(range.range).toBe('1.2.3') | |
| 52 | expect(range.isExact).toBe(false) | |
| 53 | }) | |
| 54 | ||
| 55 | it('success case - an operatorless version is exact', () => { | |
| 56 | expect(VersionResolver.createRange('1.2.3').isExact).toBe(true) | |
| 57 | }) | |
| 58 | ||
| 59 | it('success case - the closures resolve against the raw range', () => { | |
| 60 | const range = VersionResolver.createRange('^1.0.0') | |
| 61 | ||
| 62 | expect(range.satisfies('1.4.2')).toBe(true) | |
| 63 | expect(range.satisfies('2.0.0')).toBe(false) | |
| 64 | expect(range.getLatest(['1.0.0', '1.4.2', '2.0.0'])).toBe('1.4.2') | |
| 65 | }) | |
| 66 | }) | |
| 67 | ||
| 68 | describe('getUpdateType', () => { | |
| 69 | it('success case - classifies by the first component that grew', () => { | |
| 70 | expect(VersionResolver.getUpdateType('1.2.3', '2.0.0')).toBe('major') | |
| 71 | expect(VersionResolver.getUpdateType('1.2.3', '1.3.0')).toBe('minor') | |
| 72 | expect(VersionResolver.getUpdateType('1.2.3', '1.2.4')).toBe('patch') | |
| 73 | }) | |
| 74 | ||
| 75 | it('success case - range operators on either side are ignored', () => { | |
| 76 | expect(VersionResolver.getUpdateType('^1.2.3', '2.0.0')).toBe('major') | |
| 77 | expect(VersionResolver.getUpdateType('~1.2.3', '1.2.9')).toBe('patch') | |
| 78 | }) | |
| 79 | ||
| 80 | it('edge case - short versions pad to major.minor.patch', () => { | |
| 81 | expect(VersionResolver.getUpdateType('1.2', '1.3')).toBe('minor') | |
| 82 | expect(VersionResolver.getUpdateType('1', '2')).toBe('major') | |
| 83 | }) | |
| 84 | }) | |
| 85 | ||
| 86 | describe('isSafeUpdate', () => { | |
| 87 | it('success case - safe means the new version stays inside the range', () => { | |
| 88 | expect(VersionResolver.isSafeUpdate('^1.0.0', '1.9.9')).toBe(true) | |
| 89 | expect(VersionResolver.isSafeUpdate('^1.0.0', '2.0.0')).toBe(false) | |
| 90 | }) | |
| 91 | ||
| 92 | it('edge case - an exact pin admits nothing else', () => { | |
| 93 | expect(VersionResolver.isSafeUpdate('1.2.3', '1.2.4')).toBe(false) | |
| 94 | expect(VersionResolver.isSafeUpdate('1.2.3', '1.2.3')).toBe(true) | |
| 95 | }) | |
| 96 | }) | |
| 97 | }) | |