release prep: rc.1 baseline and gating updates

This commit is contained in:
2026-03-02 15:54:55 -05:00
parent 97a42c8802
commit f43b2b24b6
168 changed files with 14708 additions and 982 deletions

View File

@@ -0,0 +1,136 @@
use bitdo_proto::{
device_profile_for, BitdoError, DeviceSession, MockTransport, SessionConfig, SupportLevel,
SupportTier, VidPid,
};
const CANDIDATE_READONLY_PIDS: &[u16] = &[
0x6002, 0x6003, 0x3010, 0x3011, 0x3012, 0x3013, 0x5200, 0x5201, 0x203a, 0x2049, 0x2028, 0x202e,
0x3004, 0x3019, 0x3100, 0x3105, 0x2100, 0x2101, 0x901a, 0x6006, 0x5203, 0x5204, 0x301a, 0x9028,
0x3026, 0x3027,
];
#[test]
fn candidate_targets_are_candidate_readonly() {
for pid in CANDIDATE_READONLY_PIDS {
let profile = device_profile_for(VidPid::new(0x2dc8, *pid));
assert_eq!(
profile.support_tier,
SupportTier::CandidateReadOnly,
"expected candidate-readonly for pid={pid:#06x}"
);
assert_eq!(
profile.support_level,
SupportLevel::DetectOnly,
"support_level remains detect-only until full promotion"
);
}
}
#[test]
fn candidate_standard_pid_allows_diag_read_but_blocks_write_and_unsafe() {
let pid = 0x6002;
let mut transport = MockTransport::default();
// get_mode issues up to 3 reads; allow timeout outcome to prove it was permitted by policy.
transport.push_read_timeout();
transport.push_read_timeout();
transport.push_read_timeout();
let mut session = DeviceSession::new(
transport,
VidPid::new(0x2dc8, pid),
SessionConfig {
experimental: true,
..Default::default()
},
)
.expect("open session");
let mode_err = session
.get_mode()
.expect_err("candidate get_mode should execute and fail only at transport/response stage");
assert!(matches!(
mode_err,
BitdoError::Timeout | BitdoError::MalformedResponse { .. }
));
let write_err = session
.set_mode(1)
.expect_err("candidate safe-write must be blocked");
assert!(matches!(write_err, BitdoError::UnsupportedForPid { .. }));
let unsafe_err = session
.enter_bootloader()
.expect_err("candidate unsafe command must be blocked");
assert!(matches!(unsafe_err, BitdoError::UnsupportedForPid { .. }));
let _ = session.close();
}
#[test]
fn candidate_jp_pid_remains_diag_only() {
let pid = 0x5200;
let mut transport = MockTransport::default();
transport.push_read_data({
let mut response = vec![0u8; 64];
response[0] = 0x02;
response[1] = 0x05;
response[4] = 0xC1;
response
});
let mut session = DeviceSession::new(
transport,
VidPid::new(0x2dc8, pid),
SessionConfig {
experimental: true,
..Default::default()
},
)
.expect("open session");
let identify = session.identify().expect("identify allowed");
assert_eq!(identify.target.pid, pid);
let profile = device_profile_for(VidPid::new(0x2dc8, pid));
assert_eq!(profile.support_tier, SupportTier::CandidateReadOnly);
let mode_err = session
.get_mode()
.expect_err("jp candidate should not expose mode read path");
assert!(matches!(mode_err, BitdoError::UnsupportedForPid { .. }));
let _ = session.close();
}
#[test]
fn wave2_candidate_standard_pid_allows_safe_reads_only() {
let pid = 0x3100;
let mut transport = MockTransport::default();
transport.push_read_timeout();
transport.push_read_timeout();
transport.push_read_timeout();
let mut session = DeviceSession::new(
transport,
VidPid::new(0x2dc8, pid),
SessionConfig {
experimental: true,
..Default::default()
},
)
.expect("open session");
let mode_err = session.get_mode().expect_err(
"wave2 candidate get_mode should be permitted and fail at transport/response stage",
);
assert!(matches!(
mode_err,
BitdoError::Timeout | BitdoError::MalformedResponse { .. }
));
let write_err = session
.set_mode(1)
.expect_err("wave2 candidate safe-write must be blocked");
assert!(matches!(write_err, BitdoError::UnsupportedForPid { .. }));
let _ = session.close();
}