Skip to content

test: cover the least-tested modules (timemachine, purgeable, docker, homebrew, dns, config) - #81

Open
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1787003005-least-covered-module-tests
Open

test: cover the least-tested modules (timemachine, purgeable, docker, homebrew, dns, config)#81
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1787003005-least-covered-module-tests

Conversation

@devin-ai-integration

Copy link
Copy Markdown

What does this PR do?

Adds unit tests for the modules with the lowest coverage. Overall coverage goes from 83.09% statements / 71.56% branches to 93.52% / 84.6%, and the thresholds in vitest.config.ts are raised to 90/90/80/90 to lock that in.

Per-module before → after (statements):

module before after
maintenance/timemachine.ts 2.27% 100%
scanners/homebrew.ts 32.83% 100%
scanners/docker.ts 50% 100%
maintenance/purgeable.ts 66.66% 96.29%
utils/clipboard.ts 71.42% 100%
maintenance/dns-cache.ts 77.41% 96.77%
utils/hash.ts 81.81% 90.9%
utils/config.ts 82.85% 100%

The recurring problem in the existing tests was that the child_process and fs/promises mocks were fixed for the whole file (access always rejected, spawn always closed with code 0), so the interesting paths — brew/docker actually installed, sudo available, a command failing — were unreachable and several assertions were tautological (expect(typeof result.success).toBe('boolean')).

The new tests use a per-test scriptable spawn mock plus a recorded call log, so a test can decide what each invocation does and assert the exact argv:

respond = (command, args) => {
  if (args.includes('cleanup')) return { code: 1, stderr: 'cleanup exploded' };
  return { stdout: `${BREW_CACHE}\n` };
};
// ...
expect(spawnCalls).toEqual([{ command: DOCKER_BIN, args: ['system', 'prune', '-af'] }]);

That makes the security-relevant behavior testable and now covered: snapshot dates are only accepted when they match the strict date regex, sudo -n is used and reported via requiresSudo when passwordless sudo is unavailable, brew --cache output outside the expected prefixes is rejected, unknown docker system df resource types are skipped, docker system prune never gets --volumes, and config extraPaths outside home//Users//Volumes are dropped and the list is capped at 50.

config.test.ts now mocks os.homedir() to a temp directory. config.ts builds CONFIG_PATHS from homedir() at import time, so covering initConfig()/configExists() otherwise means writing ~/.maccleanerrc — i.e. clobbering the real config of whoever runs the suite.

Type of change

  • Bug fix
  • New feature (new scanner, command, or option)
  • Improvement to existing feature
  • Chore / dependency update
  • Documentation

Checklist

  • bun run lint passes
  • bun run test passes (no regressions) — 392 tests, 42 files
  • bun run build succeeds
  • New tests added for new behavior
  • I've tested this on macOS locally (developed on Linux; all new tests mock child_process/fs, so they are platform independent)

Notes for reviewer

No production code changed — tests and coverage thresholds only.

Link to Devin session: https://app.devin.ai/sessions/4a8526474f4a4c3fba300a24439718de
Requested by: @guhcostan

…ebrew, dns, config)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@guhcostan guhcostan self-assigned this Aug 17, 2026
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Comment thread src/utils/hash.test.ts Fixed
Comment thread src/utils/hash.test.ts Fixed
Comment thread src/utils/hash.test.ts Fixed
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants