mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-10-19 16:17:03 +00:00
* test: remove tests that do not pin user-visible behavior Apply the AGENTS.md test rules to the existing Rust and Flutter suites. A test is kept when it is the only coverage of user- or API-visible behavior, the regression test of a reported or fixed bug, a security boundary (one test per rejection class), or a check against an external reference. Tests that assert private state or the order of internal steps, pin review-round corner cases, or repeat what a kept test already covers are removed. Rust: 679 -> 298 tests. Dart: 118 -> 45 tests. Test-only helpers left without callers go with them (applyLastOnlineStateForTesting, terminalKeyboardRowWidth, debugBufferedInputCount, tokio's test-util dev feature), and cfg gates and visibility that existed only for the deleted tests are narrowed. Runtime behavior is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WS1HTjp6UQuG43KEcQPq1R * test: keep tests that pin security and user-visible behavior Restore six tests that review showed are the only coverage of their behavior: - update metadata rejects an artifact file name with path components; - ICE candidates from another session are dropped; - KCP delivers every multi-segment frame queued before a close; - set_files rejects an empty name in a multi-file transfer; - a lopsided elongated cursor keeps its centre hotspot (#16242); - toggling Show hidden during a pending same-path read issues a new read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WS1HTjp6UQuG43KEcQPq1R * test: keep offline update and key-exchange downgrade rejections Restore three tests that are the only coverage of their rejection class: - offline update metadata rejects a signed artifact with an http or credential-bearing URL; - offline verification rejects a renamed local file and a version that does not match the release; - a key-exchange pick lowered in transit leaves both sides unable to decrypt, so a v0 fallback after a failed v1 decrypt cannot pass unnoticed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WS1HTjp6UQuG43KEcQPq1R * test: keep the decomposed-grapheme and reconnect-cancel tests Each catches a plausible wrong change that passes every kept test: mapping the first scalar under a locked Ctrl turns é into \x05, and a reconnect that does not fail pending reads leaves them hanging until the 30 s timeout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WS1HTjp6UQuG43KEcQPq1R --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
237 lines
6.2 KiB
Dart
237 lines
6.2 KiB
Dart
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter_hbb/models/input_modifier_utils.dart';
|
|
|
|
void main() {
|
|
group('shouldReleaseStaleMobileShift', () {
|
|
test('releases one-shot mobile shift after a text key', () {
|
|
expect(
|
|
shouldReleaseStaleMobileShift(
|
|
isMobile: true,
|
|
cachedShiftPressed: true,
|
|
actualShiftPressed: false,
|
|
logicalKey: LogicalKeyboardKey.keyD,
|
|
hasTrackedShiftKeyDown: true,
|
|
),
|
|
isTrue,
|
|
);
|
|
});
|
|
|
|
test('does not release when shift is still physically pressed', () {
|
|
expect(
|
|
shouldReleaseStaleMobileShift(
|
|
isMobile: true,
|
|
cachedShiftPressed: true,
|
|
actualShiftPressed: true,
|
|
logicalKey: LogicalKeyboardKey.keyD,
|
|
hasTrackedShiftKeyDown: true,
|
|
),
|
|
isFalse,
|
|
);
|
|
});
|
|
});
|
|
|
|
group('shouldApplyTerminalInputModifiers', () {
|
|
test('rejects terminal control bytes and multi-character sequences', () {
|
|
for (final input in ['\x00', '\x03', '\t', '\n', '\r', '\x1B', '\x7F']) {
|
|
expect(
|
|
shouldApplyTerminalInputModifiers(input),
|
|
isFalse,
|
|
reason: '${input.codeUnits} must not consume a one-shot modifier',
|
|
);
|
|
}
|
|
expect(shouldApplyTerminalInputModifiers('\x1B[A'), isFalse);
|
|
});
|
|
});
|
|
|
|
group('applyTerminalInputModifiers', () {
|
|
test('maps the complete Ctrl symbol range', () {
|
|
const mappings = {
|
|
'[': '\x1B',
|
|
r'\': '\x1C',
|
|
']': '\x1D',
|
|
'^': '\x1E',
|
|
'_': '\x1F',
|
|
'/': '\x1F',
|
|
};
|
|
|
|
for (final entry in mappings.entries) {
|
|
expect(
|
|
applyTerminalInputModifiers(
|
|
entry.key,
|
|
ctrlLocked: true,
|
|
altLocked: false,
|
|
),
|
|
entry.value,
|
|
reason: 'Ctrl+${entry.key} should map to ${entry.value.codeUnits}',
|
|
);
|
|
}
|
|
});
|
|
|
|
test('applies Ctrl before Alt for combined modifiers', () {
|
|
expect(
|
|
applyTerminalInputModifiers(
|
|
'b',
|
|
ctrlLocked: true,
|
|
altLocked: true,
|
|
),
|
|
'\x1B\x02',
|
|
);
|
|
});
|
|
});
|
|
|
|
group('prepareTerminalInputPayload', () {
|
|
test('normalizes a mobile keyboard Enter to carriage return', () {
|
|
expect(
|
|
prepareTerminalInputPayload(
|
|
'\n',
|
|
source: TerminalInputSource.keyboard,
|
|
isMobileOrWebMobile: true,
|
|
bracketedPasteMode: false,
|
|
ctrlLocked: false,
|
|
altLocked: false,
|
|
),
|
|
'\r',
|
|
);
|
|
});
|
|
|
|
test('keeps Ctrl+J as line feed on mobile', () {
|
|
expect(
|
|
prepareTerminalInputPayload(
|
|
'j',
|
|
source: TerminalInputSource.keyboard,
|
|
isMobileOrWebMobile: true,
|
|
bracketedPasteMode: false,
|
|
ctrlLocked: true,
|
|
altLocked: false,
|
|
),
|
|
'\n',
|
|
);
|
|
});
|
|
|
|
test('does not apply Alt to a terminal control byte', () {
|
|
expect(
|
|
prepareTerminalInputPayload(
|
|
'\x1B',
|
|
source: TerminalInputSource.keyboard,
|
|
isMobileOrWebMobile: true,
|
|
bracketedPasteMode: false,
|
|
ctrlLocked: false,
|
|
altLocked: true,
|
|
),
|
|
'\x1B',
|
|
);
|
|
});
|
|
|
|
test('keeps decomposed graphemes intact with locked keyboard modifiers',
|
|
() {
|
|
const decomposedEAcute = 'é';
|
|
|
|
expect(
|
|
prepareTerminalInputPayload(
|
|
decomposedEAcute,
|
|
source: TerminalInputSource.keyboard,
|
|
isMobileOrWebMobile: true,
|
|
bracketedPasteMode: false,
|
|
ctrlLocked: true,
|
|
altLocked: false,
|
|
),
|
|
decomposedEAcute,
|
|
);
|
|
});
|
|
|
|
test('wraps paste without applying locked modifiers', () {
|
|
expect(
|
|
prepareTerminalInputPayload(
|
|
'd',
|
|
source: TerminalInputSource.paste,
|
|
isMobileOrWebMobile: true,
|
|
bracketedPasteMode: true,
|
|
ctrlLocked: true,
|
|
altLocked: true,
|
|
),
|
|
'\x1B[200~d\x1B[201~',
|
|
);
|
|
});
|
|
});
|
|
|
|
group('shouldHandleTerminalPasteShortcut', () {
|
|
test('handles only Ctrl+Shift+V on Linux with a virtual lock', () {
|
|
expect(
|
|
shouldHandleTerminalPasteShortcut(
|
|
platform: TargetPlatform.linux,
|
|
logicalKey: LogicalKeyboardKey.keyV,
|
|
isKeyDown: true,
|
|
isKeyRepeat: false,
|
|
controlPressed: true,
|
|
metaPressed: false,
|
|
altPressed: false,
|
|
shiftPressed: true,
|
|
modifierLockActive: true,
|
|
),
|
|
isTrue,
|
|
);
|
|
expect(
|
|
shouldHandleTerminalPasteShortcut(
|
|
platform: TargetPlatform.linux,
|
|
logicalKey: LogicalKeyboardKey.keyV,
|
|
isKeyDown: true,
|
|
isKeyRepeat: false,
|
|
controlPressed: true,
|
|
metaPressed: false,
|
|
altPressed: false,
|
|
shiftPressed: false,
|
|
modifierLockActive: true,
|
|
),
|
|
isFalse,
|
|
);
|
|
});
|
|
|
|
test('handles Ctrl+V and Meta+V when a virtual modifier lock is active',
|
|
() {
|
|
expect(
|
|
shouldHandleTerminalPasteShortcut(
|
|
platform: TargetPlatform.windows,
|
|
logicalKey: LogicalKeyboardKey.keyV,
|
|
isKeyDown: true,
|
|
isKeyRepeat: false,
|
|
controlPressed: true,
|
|
metaPressed: false,
|
|
altPressed: false,
|
|
shiftPressed: false,
|
|
modifierLockActive: true,
|
|
),
|
|
isTrue,
|
|
);
|
|
expect(
|
|
shouldHandleTerminalPasteShortcut(
|
|
platform: TargetPlatform.macOS,
|
|
logicalKey: LogicalKeyboardKey.keyV,
|
|
isKeyDown: true,
|
|
isKeyRepeat: false,
|
|
controlPressed: false,
|
|
metaPressed: true,
|
|
altPressed: false,
|
|
shiftPressed: false,
|
|
modifierLockActive: true,
|
|
),
|
|
isTrue,
|
|
);
|
|
});
|
|
});
|
|
|
|
group('shouldClearTerminalModifiersWhenRow3Collapses', () {
|
|
test('clears visible modifier state when expanded row is collapsed', () {
|
|
expect(
|
|
shouldClearTerminalModifiersWhenRow3Collapses(
|
|
wasExpanded: true,
|
|
willExpand: false,
|
|
ctrlLocked: true,
|
|
altLocked: false,
|
|
),
|
|
isTrue,
|
|
);
|
|
});
|
|
});
|
|
}
|