OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-overlay / test / ignore.test.js

102 lines · javascript ref:
import test from 'brittle'
import { tmpDir, fs, path } from './helpers.js'
import { parseIgnoreFile, createMatcher, loadIgnoreFile, getDefaultDenyList } from '../lib/ignore.js'

// ── parseIgnoreFile ───────────────────────────────────────────

test('parseIgnoreFile — basic patterns', (t) => {
  const patterns = parseIgnoreFile('*.log\nbuild/\n\n# comment\ntemp')
  t.alike(patterns, ['*.log', 'build/', 'temp'])
})

test('parseIgnoreFile — handles empty', (t) => {
  t.alike(parseIgnoreFile(''), [])
  t.alike(parseIgnoreFile('\n\n\n'), [])
})

test('parseIgnoreFile — trims whitespace', (t) => {
  const patterns = parseIgnoreFile('  *.tmp  \n  build  ')
  t.alike(patterns, ['*.tmp', 'build'])
})

// ── createMatcher ─────────────────────────────────────────────

test('matcher — blocks default deny list', (t) => {
  const isIgnored = createMatcher()

  t.ok(isIgnored('.env', '.env'), '.env blocked')
  t.ok(isIgnored('.env.local', '.env.local'), '.env.local blocked')
  t.ok(isIgnored('.ssh', '.ssh'), '.ssh blocked')
  t.ok(isIgnored('.gnupg', '.gnupg'), '.gnupg blocked')
  t.ok(isIgnored('server.key', 'server.key'), '*.key blocked')
  t.ok(isIgnored('cert.pem', 'cert.pem'), '*.pem blocked')
  t.ok(isIgnored('.git', '.git'), '.git blocked')
  t.ok(isIgnored('node_modules', 'node_modules'), 'node_modules blocked')
  t.ok(isIgnored('.DS_Store', '.DS_Store'), '.DS_Store blocked')
})

test('matcher — allows normal files', (t) => {
  const isIgnored = createMatcher()

  t.absent(isIgnored('app.js', 'app.js'), 'app.js allowed')
  t.absent(isIgnored('docs/readme.md', 'readme.md'), 'readme.md allowed')
  t.absent(isIgnored('photo.jpg', 'photo.jpg'), 'photo.jpg allowed')
})

test('matcher — custom patterns', (t) => {
  const isIgnored = createMatcher(['*.log', 'build/', 'temp*'])

  t.ok(isIgnored('debug.log', 'debug.log'), '*.log matched')
  t.ok(isIgnored('build', 'build'), 'build/ matched')
  t.ok(isIgnored('tempfile', 'tempfile'), 'temp* matched')
  t.absent(isIgnored('app.js', 'app.js'), 'app.js not matched')
})

test('matcher — negation patterns', (t) => {
  const isIgnored = createMatcher(['*.log', '!important.log'])

  t.ok(isIgnored('debug.log', 'debug.log'), 'debug.log blocked')
  t.absent(isIgnored('important.log', 'important.log'), 'important.log allowed by negation')
})

test('matcher — ** glob matches deep paths', (t) => {
  const isIgnored = createMatcher(['build/**'])

  t.ok(isIgnored('build/output.js', 'output.js'), 'build/output.js matched')
  t.ok(isIgnored('build/sub/deep/file.js', 'file.js'), 'deep path matched')
  t.absent(isIgnored('src/build.js', 'build.js'), 'src/build.js not matched')
})

// ── loadIgnoreFile ────────────────────────────────────────────

test('loadIgnoreFile — reads .overlayignore', (t) => {
  const dir = tmpDir('ignore')
  fs.writeFileSync(path.join(dir, '.overlayignore'), '*.tmp\nbuild/\n# comment\n')

  const patterns = loadIgnoreFile(dir)
  t.alike(patterns, ['*.tmp', 'build/'])
})

test('loadIgnoreFile — returns empty for missing file', (t) => {
  const dir = tmpDir('ignore-empty')
  const patterns = loadIgnoreFile(dir)
  t.alike(patterns, [])
})

// ── getDefaultDenyList ────────────────────────────────────────

test('getDefaultDenyList — returns a copy', (t) => {
  const list = getDefaultDenyList()
  t.ok(list.length > 0)
  t.ok(list.includes('.env'))
  t.ok(list.includes('.ssh'))

  // Modifying the returned list shouldn't affect future calls
  list.push('custom')
  const list2 = getDefaultDenyList()
  t.absent(list2.includes('custom'))
})

// (v1 watch-manager integration test removed with the watch-manager subsystem —
// hyper-overlay 0.3.0 is a pure content-addressed distribution library.)