use std::path::PathBuf;
use ek_core::Configurable;
use ek_core::SectionMap;
use ek_ui::appconfig::{AcctSpec, write_account};
fn tmp_root(tag: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("target")
.join("tmp")
.join(format!("ekui-appc-{tag}-{}", std::process::id()))
}
fn spec() -> AcctSpec {
AcctSpec {
broker_id: "9".to_string(),
user: "11".to_string(),
td_addr: "tcp://1.2.3.4:40001".to_string(),
md_addr: "tcp://1.2.3.4:40011".to_string(),
app_id: "simnow_client_test".to_string(),
auth_code: "0123456789abcdef".to_string(),
classes: "1".to_string(),
md_user: String::new(),
md_password: None,
}
}
#[test]
fn u_cli_section_is_the_realm_of_apply_config() {
ek_cfg::set_default_root_for_tests(std::path::PathBuf::from("C:/dev/fuke/ek-ui/target/cfg-test-root"));
ek_cfg::secret::force_fake_for_tests(); let root = tmp_root("a");
let _ = std::fs::remove_dir_all(&root);
let store = ek_cfg::Store::with_root(root.clone());
let gw = write_account(&store, &spec(), "判据密码").expect("CLI 写档");
assert_eq!(gw, "ctp_9_11");
let ns = format!("ctp.{gw}");
let map = match store.load(&ns).expect("载入") {
ek_cfg::LoadOutcome::Loaded { map, .. } => map,
ek_cfg::LoadOutcome::Fresh => panic!("档应存在"),
};
assert_eq!(map.get_plain("td_user"), Some("11"));
assert_eq!(map.get_plain("product_classes"), Some("1"));
assert_eq!(
map.get_secret_key("td_password"),
Some("gw_td_password"),
"密码行 = 密库引用"
);
let plugin = ek_ctp::plugin::CtpPlugin::default();
let rep = plugin.apply_config(&map).expect("CLI 段必被受理");
for k in [
"broker_id",
"td_addr",
"td_user",
"td_app_id",
"td_auth_code",
"md_addr",
"product_classes",
"td_password",
] {
assert!(
rep.adopted.iter().any(|a| a == k),
"键 {k} 必被采纳(实际 adopted={:?})",
rep.adopted
);
}
assert!(
rep.deferred.is_empty(),
"CLI 段不应有被搁置的键(实际 deferred={:?})",
rep.deferred
);
let creds = plugin.credentials_state();
let td = creds
.iter()
.find(|c| c.field == "td_password")
.expect("档位应含 td_password");
assert_eq!(
td.state, "REFERENCED",
"受理面只登记引用(整合值在 on_start)"
);
assert_eq!(td.ref_key, "gw_td_password");
let dumped = plugin.dump_config();
let keys_of = |m: &SectionMap| m.iter().map(|(k, _)| k.to_string()).collect::<Vec<_>>();
let mut a = keys_of(&map);
let mut b = keys_of(&dumped);
a.sort();
b.sort();
assert_eq!(a, b, "CLI 段键集必须与受理后 dump 相等(CLI 即受理面)");
let _ = std::fs::remove_dir_all(&root);
}
#[test]
fn u_cli_rejects_incomplete_specs() {
ek_cfg::set_default_root_for_tests(std::path::PathBuf::from("C:/dev/fuke/ek-ui/target/cfg-test-root"));
ek_cfg::secret::force_fake_for_tests(); let root = tmp_root("b");
let _ = std::fs::remove_dir_all(&root);
let store = ek_cfg::Store::with_root(root.clone());
let s = spec();
let s = AcctSpec {
td_addr: String::new(),
..s
};
assert!(write_account(&store, &s, "pw").is_err(), "缺 td 前置必拒");
let _s = spec();
assert!(
write_account(&store, &_s, " ").is_err(),
"空/全空白密码必拒"
);
let s = spec();
let s = AcctSpec {
classes: "1,113".to_string(),
..s
};
assert!(
write_account(&store, &s, "pw").is_err(),
"非单字符收录面必拒(D-PC-FILTER)"
);
let _ = std::fs::remove_dir_all(&root);
}
#[test]
fn u_multi_front_same_account_gets_suffix() {
ek_cfg::set_default_root_for_tests(std::path::PathBuf::from("C:/dev/fuke/ek-ui/target/cfg-test-root"));
ek_cfg::secret::force_fake_for_tests(); use ek_ui::appconfig::unique_gw_name;
let taken: Vec<(String, String, String, String)> = vec![(
"ctp_9_11".to_string(),
"9".to_string(),
"11".to_string(),
"tcp://1.2.3.4:40001".to_string(),
)];
assert!(
unique_gw_name(&taken, "9", "11", "tcp://1.2.3.4:40001").is_err(),
"同 broker+账号+前置须被拒"
);
assert_eq!(
unique_gw_name(&taken, "9", "11", "tcp://8.8.8.8:40001").as_deref().unwrap(),
"ctp_9_11_2",
"同账号换 IP = 后缀 _2"
);
assert_eq!(
unique_gw_name(&taken, "9", "11", "tcp://1.2.3.4:41001").as_deref().unwrap(),
"ctp_9_11_2",
"同账号换端口 = 后缀 _2"
);
let taken2: Vec<(String, String, String, String)> = vec![
taken[0].clone(),
(
"ctp_9_11_2".to_string(),
"9".to_string(),
"11".to_string(),
"tcp://8.8.8.8:40001".to_string(),
),
];
assert_eq!(
unique_gw_name(&taken2, "9", "11", "tcp://9.9.9.9:40001").as_deref().unwrap(),
"ctp_9_11_3",
"第三套前置 = _3"
);
assert_eq!(
unique_gw_name(&taken2, "9", "22", "tcp://1.2.3.4:40001").as_deref().unwrap(),
"ctp_9_22",
"换账号 = 各用各的基名"
);
let root = tmp_root("mf");
let _ = std::fs::remove_dir_all(&root);
let store = ek_cfg::Store::with_root(root.clone());
let gw1 = write_account(&store, &spec(), "判据密码").expect("基名档");
assert_eq!(gw1, "ctp_9_11");
let s2 = AcctSpec {
td_addr: "tcp://1.2.3.4:41001".to_string(),
md_addr: "tcp://1.2.3.4:41011".to_string(),
..spec()
};
let gw2 = write_account(&store, &s2, "判据密码2").expect("同账号第二套前置写档");
assert_eq!(gw2, "ctp_9_11_2", "CLI 写档走同一后缀算法");
assert!(
write_account(&store, &s2, "判据密码2").is_err(),
"同前置重复登记必拒(档案侧同样吃 (broker,账号,td) 三全同闸)"
);
let _ = std::fs::remove_dir_all(&root);
}