test: remove tests that do not pin user-visible behavior (#16539)

* 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>
This commit is contained in:
RustDeskandClaude Opus 5.5 authored and GitHub committed 2026-10-14 14:45:22 +08:00
1 parent 76ab280ae9
commit 9997b7a3b8
94 files changed
+66 -9405

No files matched your search

-62
View File
@@ -1677,15 +1677,6 @@ mod tests {
assert_err_contains(err, "empty file name");
}
#[test]
fn set_files_rejects_null_byte_name() {
let mut job = new_validation_job(103);
let err = job
.set_files(vec![new_file_entry("bad\0name.txt")])
.expect_err("null byte in file name must be rejected");
assert_err_contains(err, "null bytes");
}
#[test]
fn set_files_rejects_mixed_entries_when_one_is_traversal() {
let mut job = new_validation_job(104);
@@ -1708,39 +1699,6 @@ mod tests {
assert_err_contains(err, "absolute path");
}
#[cfg(not(windows))]
#[test]
fn set_files_allows_backslash_prefixed_name_on_unix() {
let mut job = new_validation_job(105);
assert!(job
.set_files(vec![new_file_entry("\\\\server\\share\\payload.txt")])
.is_ok());
}
#[test]
fn remove_file_rejects_empty_path() {
let err = remove_file("").expect_err("empty file path must be rejected");
assert_err_contains(err, "cannot be empty");
}
#[test]
fn remove_file_rejects_null_byte_path() {
let err = remove_file("bad\0path").expect_err("null byte path must be rejected");
assert_err_contains(err, "null bytes");
}
#[test]
fn create_dir_rejects_empty_path() {
let err = create_dir("").expect_err("empty directory path must be rejected");
assert_err_contains(err, "cannot be empty");
}
#[test]
fn create_dir_rejects_null_byte_path() {
let err = create_dir("bad\0path").expect_err("null byte path must be rejected");
assert_err_contains(err, "null bytes");
}
#[test]
fn rename_file_rejects_invalid_new_name() {
let tmp_root = TestTempDir::new("rustdesk_rename_invalid");
@@ -1790,24 +1748,4 @@ mod tests {
assert!(!src.exists());
assert!(dst.exists());
}
#[cfg(windows)]
#[test]
fn set_files_rejects_windows_drive_absolute_path() {
let mut job = new_validation_job(106);
let err = job
.set_files(vec![new_file_entry("C:\\Windows\\Temp\\payload.txt")])
.expect_err("drive-letter absolute path must be rejected");
assert_err_contains(err, "absolute path");
}
#[cfg(windows)]
#[test]
fn set_files_rejects_windows_verbatim_drive_absolute_path() {
let mut job = new_validation_job(1061);
let err = job
.set_files(vec![new_file_entry(r"\\?\C:\Windows\Temp\x.txt")])
.expect_err("verbatim drive absolute path must be rejected");
assert_err_contains(err, "absolute path");
}
}
-56
View File
@@ -515,48 +515,6 @@ pub fn get_home_dir_trusted() -> Option<PathBuf> {
mod tests {
use super::*;
#[test]
fn test_transform_degrees_maps_all_eight_variants() {
use sctk::reexports::client::protocol::wl_output::Transform;
// Flipped variants report their rotation: the frame still needs that turn to read
// upright, and the mirror half has no producer among desktop compositors to test.
for (t, deg) in [
(Transform::Normal, 0),
(Transform::_90, 90),
(Transform::_180, 180),
(Transform::_270, 270),
(Transform::Flipped, 0),
(Transform::Flipped90, 90),
(Transform::Flipped180, 180),
(Transform::Flipped270, 270),
] {
assert_eq!(transform_degrees(t), deg, "{t:?}");
}
}
#[test]
fn test_display_info_without_transform_defaults_to_zero() {
// A snapshot serialized by an older probe child carries no transform field; it must
// deserialize with 0 rather than fail, or a greeter-side child update becomes a
// lockstep upgrade.
let old = r#"{"name":"HDMI-1","x":0,"y":0,"width":1920,"height":1080,"logical_size":null,"refresh_rate":60}"#;
let info: WaylandDisplayInfo = serde_json::from_str(old).unwrap();
assert_eq!(info.transform, 0);
let roundtrip: WaylandDisplayInfo =
serde_json::from_str(&serde_json::to_string(&info).unwrap()).unwrap();
assert_eq!(roundtrip.transform, 0);
}
#[test]
fn test_run_cmds_trim_newline() {
assert_eq!(run_cmds_trim_newline("echo -n 123").unwrap(), "123");
assert_eq!(run_cmds_trim_newline("echo 123").unwrap(), "123");
assert_eq!(
run_cmds_trim_newline("whoami").unwrap() + "\n",
run_cmds("whoami").unwrap()
);
}
/// Test get_home_dir_trusted: returns valid path and ignores HOME env var
#[test]
fn test_get_home_dir_trusted() {
@@ -584,20 +542,6 @@ mod tests {
}
}
/// Test shell_quote with normal strings
#[test]
fn test_shell_quote_normal() {
assert_eq!(shell_quote("hello"), "'hello'");
assert_eq!(shell_quote("/home/user"), "'/home/user'");
}
/// Test shell_quote with spaces
#[test]
fn test_shell_quote_spaces() {
assert_eq!(shell_quote("/home/my user/file"), "'/home/my user/file'");
assert_eq!(shell_quote("path with spaces"), "'path with spaces'");
}
/// Test shell_quote with single quotes (the tricky case)
#[test]
fn test_shell_quote_single_quotes() {