OverviewFilesCommitsIssuesDocsReleasesPeers

pear-git / test / unit / ref-diff.test.js

170 lines · javascript ref:
import test from 'brittle'
import { diffRefs } from '../../lib/git/ref-diff.js'

// Sample SHA hashes for testing
const SHA_A = 'aabbccdd00112233445566778899aabbccddeeff'
const SHA_B = '1122334455667788990011223344556677889900'
const SHA_C = 'ff00112233445566778899aabbccddeeff001122'
const SHA_D = 'deadbeef00112233445566778899aabbccddeeff'

test('diffRefs: detects updated branch (same ref name, different hashes)', (t) => {
  const local = { 'refs/heads/main': SHA_A }
  const remote = { 'refs/heads/main': SHA_B }

  const result = diffRefs(local, remote)

  t.is(result.changed.length, 1)
  t.is(result.changed[0].ref, 'refs/heads/main')
  t.is(result.changed[0].local, SHA_A)
  t.is(result.changed[0].remote, SHA_B)
  t.is(result.added.length, 0)
  t.is(result.removed.length, 0)
  t.is(result.synced, false)
})

test('diffRefs: detects new remote branch (exists in remote, not in local)', (t) => {
  const local = { 'refs/heads/main': SHA_A }
  const remote = { 'refs/heads/main': SHA_A, 'refs/heads/develop': SHA_B }

  const result = diffRefs(local, remote)

  t.is(result.changed.length, 0)
  t.is(result.added.length, 1)
  t.is(result.added[0].ref, 'refs/heads/develop')
  t.is(result.added[0].remote, SHA_B)
  t.is(result.removed.length, 0)
  t.is(result.synced, false)
})

test('diffRefs: detects deleted remote branch (exists in local, not in remote)', (t) => {
  const local = { 'refs/heads/main': SHA_A, 'refs/heads/old-branch': SHA_C }
  const remote = { 'refs/heads/main': SHA_A }

  const result = diffRefs(local, remote)

  t.is(result.changed.length, 0)
  t.is(result.added.length, 0)
  t.is(result.removed.length, 1)
  t.is(result.removed[0].ref, 'refs/heads/old-branch')
  t.is(result.removed[0].local, SHA_C)
  t.is(result.synced, false)
})

test('diffRefs: returns synced=true when refs are identical', (t) => {
  const local = {
    'refs/heads/main': SHA_A,
    'refs/heads/develop': SHA_B,
    'refs/tags/v1.0.0': SHA_C
  }
  const remote = {
    'refs/heads/main': SHA_A,
    'refs/heads/develop': SHA_B,
    'refs/tags/v1.0.0': SHA_C
  }

  const result = diffRefs(local, remote)

  t.is(result.changed.length, 0)
  t.is(result.added.length, 0)
  t.is(result.removed.length, 0)
  t.is(result.synced, true)
})

test('diffRefs: handles empty ref objects', (t) => {
  const result = diffRefs({}, {})

  t.is(result.changed.length, 0)
  t.is(result.added.length, 0)
  t.is(result.removed.length, 0)
  t.is(result.synced, true)
})

test('diffRefs: handles empty local with populated remote', (t) => {
  const local = {}
  const remote = { 'refs/heads/main': SHA_A, 'refs/tags/v1.0.0': SHA_C }

  const result = diffRefs(local, remote)

  t.is(result.changed.length, 0)
  t.is(result.added.length, 2)
  t.is(result.removed.length, 0)
  t.is(result.synced, false)
})

test('diffRefs: handles populated local with empty remote', (t) => {
  const local = { 'refs/heads/main': SHA_A, 'refs/tags/v1.0.0': SHA_C }
  const remote = {}

  const result = diffRefs(local, remote)

  t.is(result.changed.length, 0)
  t.is(result.added.length, 0)
  t.is(result.removed.length, 2)
  t.is(result.synced, false)
})

test('diffRefs: handles multiple changes at once', (t) => {
  const local = {
    'refs/heads/main': SHA_A,
    'refs/heads/old-feature': SHA_C,
    'refs/tags/v1.0.0': SHA_D
  }
  const remote = {
    'refs/heads/main': SHA_B,
    'refs/heads/new-feature': SHA_D,
    'refs/tags/v1.0.0': SHA_D
  }

  const result = diffRefs(local, remote)

  // main changed: SHA_A -> SHA_B
  t.is(result.changed.length, 1)
  t.is(result.changed[0].ref, 'refs/heads/main')
  t.is(result.changed[0].local, SHA_A)
  t.is(result.changed[0].remote, SHA_B)

  // new-feature added from remote
  t.is(result.added.length, 1)
  t.is(result.added[0].ref, 'refs/heads/new-feature')
  t.is(result.added[0].remote, SHA_D)

  // old-feature removed (not in remote)
  t.is(result.removed.length, 1)
  t.is(result.removed[0].ref, 'refs/heads/old-feature')
  t.is(result.removed[0].local, SHA_C)

  // v1.0.0 is the same in both — not in any diff list
  t.is(result.synced, false)
})

test('diffRefs: skips HEAD in comparison', (t) => {
  const local = {
    HEAD: 'ref: refs/heads/main',
    'refs/heads/main': SHA_A
  }
  const remote = {
    HEAD: 'ref: refs/heads/develop',
    'refs/heads/main': SHA_A
  }

  const result = diffRefs(local, remote)

  // HEAD differs but should be skipped — refs/heads/main is the same
  t.is(result.changed.length, 0)
  t.is(result.added.length, 0)
  t.is(result.removed.length, 0)
  t.is(result.synced, true)
})

test('diffRefs: skips HEAD even when only HEAD exists', (t) => {
  const local = { HEAD: SHA_A }
  const remote = { HEAD: SHA_B }

  const result = diffRefs(local, remote)

  t.is(result.changed.length, 0)
  t.is(result.added.length, 0)
  t.is(result.removed.length, 0)
  t.is(result.synced, true)
})