/** * Matching commit authors against the identities an account claims. */ import { describe, expect, it } from 'vitest'; import { coAuthorsOf, creditAuthors, identMatches, matchIdent, parseIdentityRecord, splitIdent, } from '../src/authors.js'; describe('splitIdent', () => { it('separates the name from the address', () => { expect(splitIdent('Chad Miller ')).toEqual({ name: 'Chad Miller', email: 'chad@example.com', }); }); it('reads an ident that carries no address', () => { expect(splitIdent('Chad Miller')).toEqual({ name: 'Chad Miller', email: '', }); }); it('reads an address with no name, as git writes for an empty user.name', () => { expect(splitIdent('')).toEqual({ name: '', email: 'chad@example.com', }); }); it('handles an angle bracket inside the name', () => { expect(splitIdent('a c ')).toEqual({ name: 'a c', email: 'real@example.com', }); }); }); describe('parseIdentityRecord', () => { it('lowercases addresses and drops malformed entries', () => { expect( parseIdentityRecord({ idents: [ { email: ' Chad@Example.COM ' }, { name: 'Chad Miller' }, { email: 42 }, {}, null, 'nope', ], }), ).toEqual([ { name: '', email: 'chad@example.com', did: '', label: '', avatarCid: '', }, { name: 'Chad Miller', email: '', did: '', label: '', avatarCid: '' }, ]); }); it('keeps a did that names somebody other than the account', () => { expect( parseIdentityRecord({ idents: [ { email: 'them@example.com', did: 'did:plc:someone' }, { email: 'bogus@example.com', did: 'not-a-did' }, ], }), ).toEqual([ { name: '', email: 'them@example.com', did: 'did:plc:someone', label: '', avatarCid: '', }, { name: '', email: 'bogus@example.com', did: '', label: '', avatarCid: '', }, ]); }); it('carries the label and face of an identity with no account', () => { expect( parseIdentityRecord({ idents: [ { email: 'noreply@anthropic.com', label: 'Claude', avatar: { $type: 'blob', ref: { $link: 'bafyface' } }, }, ], }), ).toEqual([ { name: '', email: 'noreply@anthropic.com', did: '', label: 'Claude', avatarCid: 'bafyface', }, ]); }); it('reads a record with no idents as no claims', () => { expect(parseIdentityRecord({})).toEqual([]); expect(parseIdentityRecord(null)).toEqual([]); expect(parseIdentityRecord({ idents: 'nope' })).toEqual([]); }); }); describe('identMatches', () => { const claims = parseIdentityRecord({ idents: [{ email: 'chad@example.com' }, { name: 'Solo Name' }], }); it('matches an address whatever name it travels under', () => { expect(identMatches(claims, 'Chad Miller ')).toBe(true); expect(identMatches(claims, 'Someone Else ')).toBe(true); }); it('does not match an address that was never claimed', () => { expect(identMatches(claims, 'Chad Miller ')).toBe(false); }); it('matches a name-only claim against a commit with no address', () => { expect(identMatches(claims, 'Solo Name')).toBe(true); }); it('never lets a name-only claim capture a commit that names an address', () => { // Otherwise claiming a common name would take over every commit that // author name appears on, whoever actually wrote it. expect(identMatches(claims, 'Solo Name ')).toBe(false); }); it('matches nothing when the account claims nothing', () => { expect(identMatches([], 'Chad Miller ')).toBe(false); }); it('returns the matched claim, so a reader can see whose identity it is', () => { const vouched = parseIdentityRecord({ idents: [{ email: 'them@example.com', did: 'did:plc:someone' }], }); expect(matchIdent(vouched, 'Them ')?.did).toBe( 'did:plc:someone', ); expect(matchIdent(vouched, 'Other ')).toBeNull(); }); it('prefers an address claim over a name claim for the same commit', () => { // Otherwise a bare-name claim listed first would answer for a commit the // address claim identifies exactly. const both = parseIdentityRecord({ idents: [ { name: 'Chad Miller' }, { email: 'chad@example.com', did: 'did:plc:byaddress' }, ], }); expect(matchIdent(both, 'Chad Miller ')?.did).toBe( 'did:plc:byaddress', ); }); }); describe('coAuthorsOf', () => { it('reads the trailers a message ends with', () => { expect( coAuthorsOf( 'feat: a thing\n\nWhy it is here.\n\n' + 'Co-Authored-By: Ada \n' + 'Co-authored-by: Bo \n', ), ).toEqual(['Ada ', 'Bo ']); }); it('credits each person once, however often they are named', () => { expect( coAuthorsOf( 'x\n\nCo-authored-by: Ada \n' + 'Co-authored-by: ada \n', ), ).toEqual(['Ada ']); }); it('reads only the last paragraph, so a quoted trailer credits nobody', () => { expect( coAuthorsOf( 'revert\n\nThis reverts a commit that said:\n' + 'Co-authored-by: Ada \n\n' + 'Co-authored-by: Bo \n', ), ).toEqual(['Bo ']); }); it('answers empty for a message with no trailers', () => { expect(coAuthorsOf('just a subject')).toEqual([]); expect(coAuthorsOf('')).toEqual([]); }); }); describe('creditAuthors', () => { /** @param {string} author @param {string} [message] */ const commit = (author, message = 'x') => ({ author, message }); it('holds one row for the names one address writes', () => { expect( creditAuthors([ commit('Ada Lovelace '), commit('ada '), commit('A. Lovelace '), ]), ).toEqual([{ ident: 'Ada Lovelace ', commits: 3 }]); }); it('credits the people a message names beside the author', () => { expect( creditAuthors([ commit( 'Ada ', 'a\n\nCo-authored-by: Bo \n', ), commit('Ada '), ]), ).toEqual([ { ident: 'Ada ', commits: 2 }, { ident: 'Bo ', commits: 1 }, ]); }); it('credits an author their own message names once', () => { expect( creditAuthors([ commit( 'Ada ', 'a\n\nCo-authored-by: Ada Lovelace \n', ), ]), ).toEqual([{ ident: 'Ada ', commits: 1 }]); }); it('keys an ident with no address on its name', () => { expect(creditAuthors([commit('Ada'), commit('ada')])).toEqual([ { ident: 'Ada', commits: 2 }, ]); }); it('answers empty for no commits', () => { expect(creditAuthors([])).toEqual([]); }); });