// What a merge commit says it is. It writes git's own subject, because // a merge is a record of taking a change rather than the change itself. import { describe, expect, it } from 'vitest'; import { createGitMerger, mergeSubject } from '../src/merger.js'; /** * A merger whose ports answer just enough to reach the guards. * @param {Record} records - repository records by rkey * @param {string[]} seen - the DIDs it resolved, so a test can say it did not */ function mergerSeeing(records, seen) { return createGitMerger({ readRecord: async ( /** @type {string} */ _did, /** @type {string} */ _collection, /** @type {string} */ rkey, ) => records[rkey] ?? null, writeRecord: async () => {}, readBlob: async () => null, writeBlob: async () => ({ ref: { $link: 'bafypart' }, mimeType: 'application/x-git-bundle', size: 0, }), linkBlob: async () => {}, chunkSize: 1024, locate: async (/** @type {string} */ did) => { seen.push(did); return { did, service: 'http://elsewhere.invalid' }; }, handle: async () => 'alice.localhost', }); } describe('mergeSubject', () => { it("is git's own subject, naming where the branch came from", () => { expect(mergeSubject('refs/heads/agent/farewell', 'bob.localhost')).toBe( "Merge branch 'agent/farewell' of bob.localhost", ); }); it('names the branch alone where the account is not known', () => { expect(mergeSubject('refs/heads/fix', '')).toBe("Merge branch 'fix'"); expect(mergeSubject('refs/heads/fix')).toBe("Merge branch 'fix'"); }); }); describe('createGitMerger', () => { const records = { demo: { $type: 'dev.pdsjs.git.repo', name: 'demo', refs: [], bundles: [], createdAt: '2026-08-24T00:00:00Z', }, }; it('reads the repository before it reaches across the network', async () => { /** @type {string[]} */ const seen = []; const merger = mergerSeeing(records, seen); await expect( merger.merge({ did: 'did:plc:alice', rkey: 'demo', name: 'demo', from: 'did:plc:bob', ref: 'refs/heads/fix', mode: 'merge', }), ).rejects.toThrow(/is not a branch here/); // A repository with no main is refused before the other account is // resolved, so a merge that cannot work costs no request. expect(seen).toEqual([]); }); it('refuses a repository this account does not hold', async () => { const merger = mergerSeeing({}, []); await expect( merger.merge({ did: 'did:plc:alice', rkey: 'gone', name: 'gone', from: 'did:plc:bob', ref: 'refs/heads/fix', mode: 'merge', }), ).rejects.toThrow(/no such repository/); }); });