feat: add persistent unique tags to player nicknames
This commit is contained in:
@@ -156,6 +156,27 @@ test('bot and friend wins never change ranked standings, profile stats or cosmet
|
||||
} finally { await f.close(); }
|
||||
});
|
||||
|
||||
test('duplicate nicknames receive distinct persistent tags despite concurrent reads and client tag spoofing', integration, async () => {
|
||||
const f = await fixture();
|
||||
try {
|
||||
const reads = await Promise.all(Array.from({ length: 8 }, () => f.service.profile('player-a')));
|
||||
assert.ok(reads[0].nameTag > 0);
|
||||
assert.equal(new Set(reads.map(profile => profile.nameTag)).size, 1);
|
||||
const a = await f.service.updateProfile('player-a', { displayName: '손오공' });
|
||||
const b = await f.service.updateProfile('player-b', { displayName: '손오공', nameTag: a.nameTag } as any);
|
||||
assert.equal(a.displayName, b.displayName); assert.notEqual(a.nameTag, b.nameTag);
|
||||
assert.equal((await f.service.updateProfile('player-a', { displayName: '베지터', nameTag: b.nameTag } as any)).nameTag, a.nameTag);
|
||||
await assert.rejects(f.db.collection<any>('player_profiles').updateOne({ _id: 'player-b' }, { $set: { nameTag: a.nameTag } }), { code: 11000 });
|
||||
await f.service.close();
|
||||
const restarted = await createRankedService(f.db, f.clock, 'test');
|
||||
try {
|
||||
assert.equal((await restarted.profile('player-a')).nameTag, a.nameTag);
|
||||
assert.equal((await restarted.profile('player-b')).nameTag, b.nameTag);
|
||||
assert.ok((await restarted.profile('player-c')).nameTag > Math.max(a.nameTag, b.nameTag));
|
||||
} finally { await restarted.close(); }
|
||||
} finally { await f.close(); }
|
||||
});
|
||||
|
||||
test('profiles save filtered names and validate unlocked appearances, persistence and pairing snapshots', integration, async () => {
|
||||
const f = await fixture();
|
||||
try {
|
||||
@@ -200,6 +221,7 @@ test('startup preserves old names and hides invalid leaderboard names without re
|
||||
const profiles = f.db.collection<any>('player_profiles');
|
||||
await profiles.updateOne({ _id: 'player-a' }, { $set: { displayName: '광고.example' }, $unset: { nameVersion: '' } });
|
||||
await profiles.updateOne({ _id: 'player-b' }, { $set: { displayName: '무도가', nameVersion: 0 } });
|
||||
await profiles.updateMany({}, { $unset: { nameTag: '' } });
|
||||
const restarted = await createRankedService(f.db, f.clock, 'test');
|
||||
let names: string[];
|
||||
try {
|
||||
@@ -207,6 +229,8 @@ test('startup preserves old names and hides invalid leaderboard names without re
|
||||
const board = await restarted.leaderboard('new-viewer');
|
||||
names = board.entries.map(entry => entry.displayName);
|
||||
assert.equal(names.length, 2);
|
||||
assert.ok(board.entries.every(entry => entry.nameTag > 0));
|
||||
assert.equal(new Set(board.entries.map(entry => entry.nameTag)).size, 2);
|
||||
assert.deepEqual(names, ['플레이어', '무도가']);
|
||||
assert.equal(board.entries[0].wins, 1);
|
||||
const profile = await restarted.profile('player-a');
|
||||
|
||||
Reference in New Issue
Block a user