diff --git a/tests/proxy-view.test.ts b/tests/proxy-view.test.ts deleted file mode 100644 index e41b85248..000000000 --- a/tests/proxy-view.test.ts +++ /dev/null @@ -1,388 +0,0 @@ -import assert from 'node:assert/strict' - -import { test } from 'vitest' - -import { - findCurrentGroupMember, - getRecord, - isInteractableMember, - memberDetails, - providerNameOf, - rebindMemberOccurrence, - rebindNode, - resolveMember, - selectGlobalChainNodes, - selectRuleChainMembers, - toMemberOccurrenceBinding, -} from '@/types/proxy-view' - -const node = { - recordId: 'p:0:0', - name: 'provider-node', - type: 'Shadowsocks', - alive: true, - history: [], - udp: true, - xudp: false, - tfo: false, - mptcp: false, - smux: false, - source: { - kind: 'provider', - providerName: 'provider-key', - proxyName: 'provider-node', - }, -} - -const group = { - name: 'Group', - type: 'Selector', - alive: true, - history: [], - udp: true, - xudp: false, - tfo: false, - mptcp: false, - smux: false, - members: [{ kind: 'node', name: node.name, recordId: node.recordId }], -} - -const view = { - schemaVersion: 1, - orderSource: 'runtime', - providerState: 'ready', - global: null, - direct: null, - groups: [group], - records: { [node.recordId]: node }, - standalone: [], - providers: [], -} - -test('resolves nodes only through recordId and preserves provider identity', () => { - const resolved = resolveMember(view, group.members[0]) - assert.equal(resolved.kind, 'node') - assert.equal(getRecord(view, 'p:0:0'), node) - assert.equal(memberDetails(resolved), node) - assert.equal(providerNameOf(node), 'provider-key') - assert.equal(isInteractableMember(resolved), true) -}) - -test('keeps unresolved members visible but non-interactable', () => { - const resolved = resolveMember(view, { - kind: 'unresolved', - name: 'unknown', - reason: 'provider-unavailable', - }) - assert.deepEqual(resolved, { - kind: 'unresolved', - ref: { - kind: 'unresolved', - name: 'unknown', - reason: 'provider-unavailable', - }, - }) - assert.equal(isInteractableMember(resolved), false) - assert.equal(memberDetails(resolved), undefined) -}) - -test('rebinds a node semantically when its response-scoped id moves', () => { - const previous = resolveMember(view, group.members[0]) - assert.equal(previous.kind, 'node') - - const movedNode = { ...node, recordId: 'p:1:0' } - const movedGroup = { - ...group, - members: [ - { kind: 'node', name: movedNode.name, recordId: movedNode.recordId }, - ], - } - const movedView = { - ...view, - groups: [movedGroup], - records: { [movedNode.recordId]: movedNode }, - } - const movedCandidates = movedGroup.members.map((member) => { - const resolved = resolveMember(movedView, member) - assert.equal(resolved.kind, 'node') - return resolved.node - }) - - assert.equal( - rebindNode(movedCandidates, { - name: previous.node.name, - source: previous.node.source, - })?.recordId, - 'p:1:0', - ) - assert.equal( - rebindNode(movedCandidates, { name: 'provider-node' })?.recordId, - 'p:1:0', - ) - - const duplicate = { ...movedNode, recordId: 'p:1:1' } - assert.equal( - rebindNode([movedNode, duplicate], { - name: previous.node.name, - source: previous.node.source, - }), - undefined, - ) - - const sameNameOtherSource = { - ...movedNode, - recordId: 'p:2:0', - source: { ...movedNode.source, providerName: 'other-provider' }, - } - assert.equal( - rebindNode([movedNode, sameNameOtherSource], { - name: 'provider-node', - }), - undefined, - ) -}) - -test('does not expose global-chain candidates without GLOBAL', () => { - const runtimeOnly = { - ...node, - recordId: 'c:0', - name: 'runtime-only', - source: { kind: 'core', proxyName: 'runtime-only' }, - } - const globalMissingView = { - ...view, - global: null, - records: { 'c:0': runtimeOnly }, - standalone: ['c:0'], - } - - assert.deepEqual( - selectGlobalChainNodes(globalMissingView, [{ name: 'runtime-only' }]), - [], - ) -}) - -test('does not fall back to global nodes when a selected rule group disappears', () => { - assert.deepEqual(selectRuleChainMembers(view, 'removed-group'), []) -}) - -test('uses the current backend group selection after ids and now change', () => { - const previousNode = { - ...node, - recordId: 'p:0:0', - name: 'previous-node', - source: { ...node.source, proxyName: 'previous-node' }, - } - const nextNode = { - ...node, - recordId: 'p:0:1', - name: 'next-node', - source: { ...node.source, proxyName: 'next-node' }, - } - const firstGroup = { - ...group, - now: previousNode.name, - members: [ - { - kind: 'node', - name: previousNode.name, - recordId: previousNode.recordId, - }, - { kind: 'node', name: nextNode.name, recordId: nextNode.recordId }, - ], - } - const firstView = { - ...view, - groups: [firstGroup], - records: { - [previousNode.recordId]: previousNode, - [nextNode.recordId]: nextNode, - }, - } - - assert.equal( - findCurrentGroupMember(firstView, firstGroup).member.node.recordId, - previousNode.recordId, - ) - - const movedPrevious = { ...previousNode, recordId: 'p:1:1' } - const movedNext = { ...nextNode, recordId: 'p:1:0' } - const refreshedGroup = { - ...firstGroup, - now: movedNext.name, - members: [ - { kind: 'node', name: movedNext.name, recordId: movedNext.recordId }, - { - kind: 'node', - name: movedPrevious.name, - recordId: movedPrevious.recordId, - }, - ], - } - const refreshedView = { - ...firstView, - groups: [refreshedGroup], - records: { - [movedNext.recordId]: movedNext, - [movedPrevious.recordId]: movedPrevious, - }, - } - - const current = findCurrentGroupMember(refreshedView, refreshedGroup) - assert.equal(current.member.ref.name, movedNext.name) - assert.equal(current.member.node.recordId, movedNext.recordId) - - const unresolvedGroup = { - ...refreshedGroup, - now: 'unresolved-node', - members: [ - { - kind: 'unresolved', - name: 'unresolved-node', - reason: 'provider-unavailable', - }, - ...refreshedGroup.members, - ], - } - assert.equal( - findCurrentGroupMember( - { ...refreshedView, groups: [unresolvedGroup] }, - unresolvedGroup, - ), - undefined, - ) - assert.equal( - findCurrentGroupMember(refreshedView, { - ...refreshedGroup, - now: undefined, - }), - undefined, - ) - assert.equal( - findCurrentGroupMember(refreshedView, { - ...refreshedGroup, - now: 'missing-node', - }), - undefined, - ) -}) - -test('rebinds a semantic member occurrence across id and index rotation', () => { - const firstDuplicate = node - const secondDuplicate = { ...node, recordId: 'p:0:1' } - const firstMembers = [ - resolveMember(view, group.members[0]), - { - kind: 'group', - ref: { kind: 'group', name: group.name }, - group, - }, - { - kind: 'node', - ref: { - kind: 'node', - name: secondDuplicate.name, - recordId: secondDuplicate.recordId, - }, - node: secondDuplicate, - }, - ] - - const binding = toMemberOccurrenceBinding(firstMembers, 2) - assert.deepEqual(binding, { - kind: 'node', - name: node.name, - source: node.source, - occurrence: 1, - }) - const groupBinding = toMemberOccurrenceBinding(firstMembers, 1) - assert.deepEqual(groupBinding, { - kind: 'group', - name: group.name, - occurrence: 0, - }) - - const movedFirst = { ...firstDuplicate, recordId: 'p:1:0' } - const movedSecond = { ...secondDuplicate, recordId: 'p:1:1' } - const refreshedMembers = [ - { - kind: 'group', - ref: { kind: 'group', name: group.name }, - group, - }, - { - kind: 'node', - ref: { - kind: 'node', - name: movedFirst.name, - recordId: movedFirst.recordId, - }, - node: movedFirst, - }, - { - kind: 'unresolved', - ref: { kind: 'unresolved', name: node.name, reason: 'ambiguous' }, - }, - { - kind: 'node', - ref: { - kind: 'node', - name: movedSecond.name, - recordId: movedSecond.recordId, - }, - node: movedSecond, - }, - ] - - const rebound = rebindMemberOccurrence(refreshedMembers, binding) - assert.equal(rebound.memberIndex, 3) - assert.equal(rebound.member.node.recordId, movedSecond.recordId) - assert.equal( - rebindMemberOccurrence(refreshedMembers, groupBinding).memberIndex, - 0, - ) -}) - -test('rejects missing, unresolved, or missing duplicate occurrences', () => { - const firstDuplicate = resolveMember(view, group.members[0]) - const secondNode = { ...node, recordId: 'p:0:1' } - const secondDuplicate = { - kind: 'node', - ref: { - kind: 'node', - name: secondNode.name, - recordId: secondNode.recordId, - }, - node: secondNode, - } - const binding = toMemberOccurrenceBinding( - [firstDuplicate, secondDuplicate], - 1, - ) - - assert.equal( - rebindMemberOccurrence( - [ - { - kind: 'unresolved', - ref: { kind: 'unresolved', name: node.name, reason: 'ambiguous' }, - }, - ], - binding, - ), - undefined, - ) - assert.equal(rebindMemberOccurrence([firstDuplicate], binding), undefined) - assert.equal( - toMemberOccurrenceBinding( - [ - { - kind: 'unresolved', - ref: { kind: 'unresolved', name: node.name, reason: 'missing' }, - }, - ], - 0, - ), - undefined, - ) -})