agent-ecosystem/test/main/services/team/TeamMemberStoragePaths.test.ts
2026-04-30 23:11:18 +03:00

76 lines
2.7 KiB
TypeScript

import { mkdtemp, readFile, rm } from 'fs/promises';
import { tmpdir } from 'os';
import { join } from 'path';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import {
encodeTeamMemberStorageKey,
TeamMemberStoragePaths,
} from '@main/services/team/TeamMemberStoragePaths';
describe('TeamMemberStoragePaths', () => {
let root: string;
let paths: TeamMemberStoragePaths;
beforeEach(async () => {
root = await mkdtemp(join(tmpdir(), 'team-member-storage-paths-'));
paths = new TeamMemberStoragePaths(root);
});
afterEach(async () => {
await rm(root, { recursive: true, force: true });
});
it('builds stable path-safe keys from canonical member names', () => {
expect(encodeTeamMemberStorageKey(' Bob ')).toBe('bob');
expect(encodeTeamMemberStorageKey('Jack Smith')).toBe('jack%20smith');
expect(encodeTeamMemberStorageKey('../Alice')).toBe('..%2Falice');
expect(encodeTeamMemberStorageKey('.')).toBe('%2E');
expect(encodeTeamMemberStorageKey('..')).toBe('%2E%2E');
expect(encodeTeamMemberStorageKey('Том')).toBe('%D1%82%D0%BE%D0%BC');
});
it('keeps member storage inside the team members directory', () => {
expect(paths.getMemberDir('team-a', '../Alice')).toBe(
join(root, 'team-a', 'members', '..%2Falice')
);
expect(paths.getMemberDir('team-a', '..')).toBe(
join(root, 'team-a', 'members', '%2E%2E')
);
expect(paths.getMemberDir('team-a', '.')).toBe(
join(root, 'team-a', 'members', '%2E')
);
expect(paths.getMemberFeatureDir('team-a', 'Bob', '.member-work-sync')).toBe(
join(root, 'team-a', 'members', 'bob', '.member-work-sync')
);
});
it('rejects empty member names and nested feature directory names', () => {
expect(() => encodeTeamMemberStorageKey(' ')).toThrow('memberName is required');
expect(() => paths.getMemberFeatureDir('team-a', 'Bob', '../unsafe')).toThrow(
'featureDirName must be a single path segment'
);
expect(() => paths.getMemberFeatureDir('team-a', 'Bob', 'nested/unsafe')).toThrow(
'featureDirName must be a single path segment'
);
expect(() => paths.getMemberFeatureDir('team-a', 'Bob', '..')).toThrow(
'featureDirName must be a single path segment'
);
expect(() => paths.getMemberFeatureDir('team-a', 'Bob', '.')).toThrow(
'featureDirName must be a single path segment'
);
});
it('materializes canonical member meta without changing the path key', async () => {
await paths.ensureMemberMeta('team-a', 'Bob');
const meta = JSON.parse(
await readFile(join(root, 'team-a', 'members', 'bob', 'member.meta.json'), 'utf8')
);
expect(meta).toMatchObject({
schemaVersion: 1,
memberName: 'Bob',
memberKey: 'bob',
});
});
});