Skip to content

Commit 47827aa

Browse files
test: add 22 edge case tests for scoring functions (#16)
* Update README.md * Update README.md * Update README.md * Change commitment issues badge in README Updated badge for commitment issues with a new design. * Update README.md * Update README.md * Update README.md * Add badges for commitment issues to README * test: add 22 edge case tests for scoring functions Cover computeDeathIndex, getDeathLabel, determineCauseOfDeath, generateLastWords, computeAge, and formatDate with edge cases including archived repos, known repos, forks, missing descriptions, commit message patterns, long message truncation, and date boundaries. Closes #12 --------- Co-authored-by: Dot <dot.systems@proton.me> Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
1 parent 313bfc0 commit 47827aa

2 files changed

Lines changed: 192 additions & 2 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
[![commitmentissues](https://img.shields.io/badge/%E2%9A%B0%20commitmentissues-declared%20dead-cc0000?style=for-the-badge&labelColor=1a0f06)](https://commitmentissues.dev/?repo=atom%2Fatom)
2+
3+
[![atom — Certificate of Death](https://commitmentissues.dev/api/certificate-image/atom/atom)](https://commitmentissues.dev/?repo=atom%2Fatom)
4+
15
# Commitment Issues
26

37
Your abandoned repos deserve a proper funeral.

src/lib/scoring.test.ts

Lines changed: 188 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import test from 'node:test'
22
import assert from 'node:assert/strict'
3-
import { computeDeathIndex } from './scoring'
3+
import {
4+
computeDeathIndex,
5+
getDeathLabel,
6+
determineCauseOfDeath,
7+
generateLastWords,
8+
computeAge,
9+
formatDate,
10+
} from './scoring'
411
import type { RepoData } from './types'
512

613
function buildRepo(overrides: Partial<RepoData> = {}): RepoData {
@@ -24,13 +31,192 @@ function buildRepo(overrides: Partial<RepoData> = {}): RepoData {
2431
}
2532
}
2633

34+
// ── computeDeathIndex ──────────────────────────────────────────────
35+
2736
test('inactive repo with many issues gets high death index', () => {
2837
const repo = buildRepo({
2938
lastCommitDate: '2018-01-01T00:00:00.000Z',
3039
openIssuesCount: 120,
3140
isArchived: false,
3241
})
33-
3442
const score = computeDeathIndex(repo)
3543
assert.ok(score >= 5)
3644
})
45+
46+
test('archived repo gets high score', () => {
47+
const repo = buildRepo({ isArchived: true })
48+
const score = computeDeathIndex(repo)
49+
assert.ok(score >= 3, `expected >= 3, got ${score}`)
50+
})
51+
52+
test('repo with last commit today returns 0', () => {
53+
const repo = buildRepo({
54+
lastCommitDate: new Date().toISOString(),
55+
openIssuesCount: 0,
56+
stargazersCount: 0,
57+
isArchived: false,
58+
})
59+
const score = computeDeathIndex(repo)
60+
assert.equal(score, 0)
61+
})
62+
63+
test('repo with 1000+ open issues and no recent commits scores very high', () => {
64+
const repo = buildRepo({
65+
lastCommitDate: '2015-01-01T00:00:00.000Z',
66+
openIssuesCount: 1500,
67+
stargazersCount: 500,
68+
isArchived: true,
69+
})
70+
const score = computeDeathIndex(repo)
71+
assert.ok(score >= 9, `expected >= 9, got ${score}`)
72+
})
73+
74+
test('commit 200 days ago with low issues scores modestly', () => {
75+
const d = new Date()
76+
d.setDate(d.getDate() - 200)
77+
const repo = buildRepo({
78+
lastCommitDate: d.toISOString(),
79+
openIssuesCount: 5,
80+
stargazersCount: 10,
81+
isArchived: false,
82+
})
83+
const score = computeDeathIndex(repo)
84+
assert.equal(score, 1)
85+
})
86+
87+
// ── getDeathLabel ──────────────────────────────────────────────────
88+
89+
test('getDeathLabel returns correct labels at boundaries', () => {
90+
assert.equal(getDeathLabel(0), 'too soon to tell')
91+
assert.equal(getDeathLabel(2), 'too soon to tell')
92+
assert.equal(getDeathLabel(3), 'struggling')
93+
assert.equal(getDeathLabel(5), 'struggling')
94+
assert.equal(getDeathLabel(6), 'dying')
95+
assert.equal(getDeathLabel(8), 'dying')
96+
assert.equal(getDeathLabel(9), 'dead dead')
97+
assert.equal(getDeathLabel(10), 'dead dead')
98+
})
99+
100+
// ── determineCauseOfDeath ──────────────────────────────────────────
101+
102+
test('known repo (atom/atom) returns exact known cause', () => {
103+
const repo = buildRepo({ fullName: 'atom/atom' })
104+
const cause = determineCauseOfDeath(repo)
105+
assert.equal(cause, 'GitHub shipped VS Code, then sunset Atom in public')
106+
})
107+
108+
test('fork repo returns "Forked but never understood"', () => {
109+
const d = new Date()
110+
d.setDate(d.getDate() - 100)
111+
const repo = buildRepo({
112+
isFork: true,
113+
isArchived: false,
114+
lastCommitDate: d.toISOString(),
115+
openIssuesCount: 0,
116+
stargazersCount: 0,
117+
description: 'some fork',
118+
})
119+
const cause = determineCauseOfDeath(repo)
120+
assert.equal(cause, 'Forked but never understood')
121+
})
122+
123+
test('no description returns "No README. No hope."', () => {
124+
const d = new Date()
125+
d.setDate(d.getDate() - 100)
126+
const repo = buildRepo({
127+
description: null,
128+
isFork: false,
129+
isArchived: false,
130+
lastCommitDate: d.toISOString(),
131+
openIssuesCount: 0,
132+
stargazersCount: 0,
133+
})
134+
const cause = determineCauseOfDeath(repo)
135+
assert.equal(cause, 'No README. No hope.')
136+
})
137+
138+
test('archived repo returns "Officially declared dead by author"', () => {
139+
const repo = buildRepo({ isArchived: true })
140+
const cause = determineCauseOfDeath(repo)
141+
assert.equal(cause, 'Officially declared dead by author')
142+
})
143+
144+
test('commitmentissues repo returns its own easter egg cause', () => {
145+
const repo = buildRepo({ fullName: 'dotsystemsdevs/commitmentissues' })
146+
const cause = determineCauseOfDeath(repo)
147+
assert.equal(cause, 'Monetized before loved.')
148+
})
149+
150+
// ── generateLastWords ──────────────────────────────────────────────
151+
152+
test('commit message with "fix typo" returns "pls work now"', () => {
153+
const repo = buildRepo({ lastCommitMessage: 'fix typo in header' })
154+
assert.equal(generateLastWords(repo), 'pls work now')
155+
})
156+
157+
test('commit message with "update readme" returns docs quip', () => {
158+
const repo = buildRepo({ lastCommitMessage: 'update readme with badges' })
159+
assert.equal(generateLastWords(repo), 'at least the docs are good')
160+
})
161+
162+
test('commit message with "wip" returns "i\'ll finish this later"', () => {
163+
const repo = buildRepo({
164+
lastCommitMessage: 'wip: refactor auth module',
165+
lastCommitDate: new Date().toISOString(),
166+
})
167+
assert.equal(generateLastWords(repo), "i'll finish this later")
168+
})
169+
170+
test('commit message with "merge" returns merge conflict quip', () => {
171+
const repo = buildRepo({
172+
lastCommitMessage: 'Merge pull request #42',
173+
lastCommitDate: new Date().toISOString(),
174+
})
175+
assert.equal(generateLastWords(repo), 'dying in a merge conflict')
176+
})
177+
178+
test('very long commit message is truncated to 80 chars', () => {
179+
const longMsg = 'a'.repeat(120)
180+
const repo = buildRepo({
181+
lastCommitMessage: longMsg,
182+
lastCommitDate: new Date().toISOString(),
183+
})
184+
const words = generateLastWords(repo)
185+
assert.ok(words.length <= 80, `expected <= 80, got ${words.length}`)
186+
assert.ok(words.endsWith('...'))
187+
})
188+
189+
test('commitmentissues repo returns its own easter egg last words', () => {
190+
const repo = buildRepo({ fullName: 'dotsystemsdevs/commitmentissues' })
191+
assert.equal(generateLastWords(repo), "should've farmed laughs before revenue.")
192+
})
193+
194+
// ── computeAge ─────────────────────────────────────────────────────
195+
196+
test('same month created and last commit returns "less than a month"', () => {
197+
assert.equal(computeAge('2024-03-15T00:00:00Z', '2024-03-28T00:00:00Z'), 'less than a month')
198+
})
199+
200+
test('exactly 1 year returns "1 year"', () => {
201+
assert.equal(computeAge('2023-01-01T00:00:00Z', '2024-01-01T00:00:00Z'), '1 year')
202+
})
203+
204+
test('2 years 3 months returns "2 years, 3 months"', () => {
205+
assert.equal(computeAge('2020-01-01T00:00:00Z', '2022-04-01T00:00:00Z'), '2 years, 3 months')
206+
})
207+
208+
test('11 months returns "11 months"', () => {
209+
assert.equal(computeAge('2023-01-01T00:00:00Z', '2023-12-01T00:00:00Z'), '11 months')
210+
})
211+
212+
test('1 month returns "1 month" (singular)', () => {
213+
assert.equal(computeAge('2024-01-01T00:00:00Z', '2024-02-01T00:00:00Z'), '1 month')
214+
})
215+
216+
// ── formatDate ─────────────────────────────────────────────────────
217+
218+
test('formatDate returns en-GB formatted date', () => {
219+
const result = formatDate('2024-06-15T12:00:00Z')
220+
assert.ok(result.includes('June'), `expected "June" in "${result}"`)
221+
assert.ok(result.includes('2024'), `expected "2024" in "${result}"`)
222+
})

0 commit comments

Comments
 (0)