v0.3.8-pre.008
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-store-desk/tests/dependency_boundary.rs
|
||||
// version: 5
|
||||
// version: 6
|
||||
|
||||
//! Dependency-boundary tests for the Store Desk application.
|
||||
|
||||
@@ -104,3 +104,30 @@ fn pre_007_transaction_inspection_uses_store_facade_and_new_visible_items_use_cr
|
||||
assert!(!sources.contains(forbidden), "Store Desk transaction inspection crossed physical/backend-neutral boundary: {forbidden}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_008_account_inspection_uses_store_facade_and_new_visible_items_use_crate_root_exports() {
|
||||
let lib = include_str!("../src/lib.rs");
|
||||
let runtime = include_str!("../src/store_runtime.rs");
|
||||
let app_state = include_str!("../src/app_state.rs");
|
||||
let tauri = include_str!("../src/tauri.rs");
|
||||
for expected in [
|
||||
"pub(crate) use self::dto_account::StoreAccountDetailRequestDto;",
|
||||
"pub(crate) use self::dto_account::StoreAccountDetailDto;",
|
||||
"pub(crate) use self::dto_account::StoreAccountQueryRequestDto;",
|
||||
"pub(crate) use self::dto_account::StoreAccountQueryResponseDto;",
|
||||
"pub(crate) use self::dto_account::StoreAccountRowDto;",
|
||||
] {
|
||||
assert!(lib.contains(expected), "missing pre.008 crate-root DTO re-export: {expected}");
|
||||
}
|
||||
assert!(runtime.contains("ksp_store_lib::RawAccountStateInspectionRead::inspect_raw_account_states"));
|
||||
assert!(runtime.contains("ksp_store_lib::RawAccountStateRead::get_raw_account_state"));
|
||||
assert!(app_state.contains("request: crate::StoreAccountQueryRequestDto"));
|
||||
assert!(app_state.contains("request: crate::StoreAccountDetailRequestDto"));
|
||||
assert!(tauri.contains("request: crate::StoreAccountQueryRequestDto"));
|
||||
assert!(tauri.contains("request: crate::StoreAccountDetailRequestDto"));
|
||||
let sources = [runtime, app_state, tauri].join("\n");
|
||||
for forbidden in ["ksp_store_api", "ksp_store_postgres", "tokio_postgres", "deadpool_postgres", "SELECT ", "OFFSET "] {
|
||||
assert!(!sources.contains(forbidden), "Store Desk account inspection crossed physical/backend-neutral boundary: {forbidden}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-store-desk/tests/desktop_contract.rs
|
||||
// version: 6
|
||||
// version: 7
|
||||
|
||||
//! Desktop template and frontend contract tests for the Store Desk scaffold.
|
||||
|
||||
@@ -80,7 +80,7 @@ fn pre_002_binary_assets_reuse_the_ksp_desktop_template_byte_exact() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_007_shell_exposes_transaction_filters_detail_and_keeps_account_skeleton_unconnected() {
|
||||
fn pre_007_shell_exposes_transaction_filters_detail_and_planned_account_view() {
|
||||
let html = include_str!("../frontend/main.html");
|
||||
for view in ["overview", "transactions", "accounts", "diagnostics"] {
|
||||
assert!(html.contains(&format!("data-view=\"{view}\"")));
|
||||
@@ -95,11 +95,10 @@ fn pre_007_shell_exposes_transaction_filters_detail_and_keeps_account_skeleton_u
|
||||
for transaction_id in ["refreshTransactions", "transactionSlotMin", "transactionSlotMax", "transactionDirection", "transactionDetailModal"] {
|
||||
assert!(html.contains(&format!("id=\"{transaction_id}\"")), "missing pre.007 transaction control: {transaction_id}");
|
||||
}
|
||||
assert!(html.contains("jusqu'à pre.008"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_007_transaction_datatable_is_server_side_while_account_remains_unconnected_and_no_second_pager_exists() {
|
||||
fn pre_007_transaction_datatable_is_server_side_and_no_second_pager_exists() {
|
||||
let source = include_str!("../frontend/ts/main.ts");
|
||||
assert!(source.contains("datatables.net-bs5"));
|
||||
assert!(source.contains("paging: true"));
|
||||
@@ -108,8 +107,6 @@ fn pre_007_transaction_datatable_is_server_side_while_account_remains_unconnecte
|
||||
assert!(source.contains("store_query_transactions"));
|
||||
assert!(source.contains("serverSide: true"));
|
||||
assert!(source.contains("Store Desk transaction DataTable initialized"));
|
||||
assert!(source.contains("Store Desk account DataTable skeleton initialized"));
|
||||
assert!(source.contains("serverSide: false"));
|
||||
assert!(source.contains("searching: false"));
|
||||
assert!(source.contains("ordering: false"));
|
||||
let html = include_str!("../frontend/main.html");
|
||||
@@ -231,3 +228,47 @@ fn pre_007_fix_002_payload_preview_remains_bounded_and_is_explicitly_copyable()
|
||||
assert!(frontend.contains("const previousTitle = button.title"));
|
||||
assert!(frontend.contains("button.title = previousTitle"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_008_account_ipc_maps_datatables_filters_counts_and_bounded_detail_without_cursor_contract() {
|
||||
let dto = include_str!("../src/dto_account.rs");
|
||||
let runtime = include_str!("../src/store_runtime.rs");
|
||||
let tauri = include_str!("../src/tauri.rs");
|
||||
let frontend = include_str!("../frontend/ts/main.ts");
|
||||
assert!(dto.contains("records_total_decimal"));
|
||||
assert!(dto.contains("records_filtered_decimal"));
|
||||
assert!(runtime.contains("RawAccountStateInspectionQuery::new"));
|
||||
assert!(runtime.contains("RawInspectionPageRequest::new(offset, limit)"));
|
||||
assert!(runtime.contains("RawAccountStateRead::get_raw_account_state"));
|
||||
assert!(runtime.contains("const ACCOUNT_DETAIL_PREVIEW_BYTES: usize = 512;"));
|
||||
assert!(tauri.contains("store_query_accounts"));
|
||||
assert!(tauri.contains("store_get_account_detail"));
|
||||
assert!(frontend.contains("store_query_accounts"));
|
||||
assert!(frontend.contains("store_get_account_detail"));
|
||||
assert!(frontend.contains("pubkey: pubkey === "" ? null : pubkey"));
|
||||
assert!(frontend.contains("recordsTotalDecimal"));
|
||||
assert!(frontend.contains("recordsFilteredDecimal"));
|
||||
assert!(frontend.contains("data-account-detail"));
|
||||
assert!(!dto.contains("RawPageCursor"));
|
||||
assert!(!frontend.contains("storePager"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_008_account_datatable_is_server_side_copyable_and_uses_datatables_as_only_pager() {
|
||||
let frontend = include_str!("../frontend/ts/main.ts");
|
||||
let html = include_str!("../frontend/main.html");
|
||||
assert!(frontend.contains("Store Desk account DataTable initialized"));
|
||||
assert!(frontend.contains("Store Desk account DataTables server-side query started"));
|
||||
assert!(frontend.contains(r#"renderCopyableLongText(String(data), "account-pubkey")"#));
|
||||
assert!(frontend.contains(r#"renderCopyableLongText(String(data), "account-state-hash")"#));
|
||||
assert!(frontend.contains(r#"renderCopyableLongText(String(data), "account-owner")"#));
|
||||
assert!(frontend.contains(r#"dataPreviewCopy.dataset.copyField = "account-data-preview""#));
|
||||
for control in ["refreshAccounts", "accountPubkey", "accountSlotMin", "accountSlotMax", "accountDirection", "accountDetailModal"] {
|
||||
assert!(html.contains(&format!("id=\"{control}\"")), "missing pre.008 account control: {control}");
|
||||
}
|
||||
assert!(html.contains("Account data preview hex"));
|
||||
assert!(html.contains("Preview tronquée à 512 bytes"));
|
||||
for forbidden in ["Premier", "Précédent", "Suivant", "storePager", "store-pagination"] {
|
||||
assert!(!html.contains(forbidden), "second Store pager marker present: {forbidden}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-store-desk/tests/desktop_security.rs
|
||||
// version: 8
|
||||
// version: 9
|
||||
|
||||
//! Security boundary tests for the Store Desk scaffold.
|
||||
|
||||
@@ -162,3 +162,71 @@ fn pre_007_fix_002_payload_preview_copy_never_logs_preview_material() {
|
||||
assert!(!frontend.contains(r#"frontendDebug("main", "Store Desk long text copy completed", { fieldId, value })"#));
|
||||
assert!(!frontend.contains(r#"frontendError("main", "Store Desk long text copy failed", { fieldId, value })"#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_008_account_rows_are_data_free_detail_is_bounded_and_filter_values_are_not_logged() {
|
||||
let dto = include_str!("../src/dto_account.rs");
|
||||
let runtime = include_str!("../src/store_runtime.rs");
|
||||
let frontend = include_str!("../frontend/ts/main.ts");
|
||||
let row_start = dto.find("pub(crate) struct StoreAccountRowDto");
|
||||
let response_start = dto.find("pub(crate) struct StoreAccountQueryResponseDto");
|
||||
assert!(row_start.is_some());
|
||||
assert!(response_start.is_some());
|
||||
if let (std::option::Option::Some(row_start), std::option::Option::Some(response_start)) = (row_start, response_start) {
|
||||
let row_source = &dto[row_start..response_start];
|
||||
assert!(!row_source.contains("data_preview_hex"));
|
||||
assert!(!row_source.contains("pub(crate) data:"));
|
||||
}
|
||||
assert!(dto.contains("data_preview_hex"));
|
||||
assert!(dto.contains("data_preview_truncated"));
|
||||
assert!(runtime.contains("ACCOUNT_DETAIL_PREVIEW_BYTES: usize = 512"));
|
||||
assert!(runtime.contains("std::cmp::min(data.len(), ACCOUNT_DETAIL_PREVIEW_BYTES)"));
|
||||
for required in [
|
||||
"account DataTables page changed",
|
||||
"account DataTables page length changed",
|
||||
"account DataTables redraw completed",
|
||||
"account detail opened",
|
||||
"account detail closed",
|
||||
] {
|
||||
assert!(frontend.contains(required), "missing account tracing event: {required}");
|
||||
}
|
||||
for forbidden in [
|
||||
r#"frontendDebug("main", "Store Desk account Store filter changed", { pubkey"#,
|
||||
r#"frontendDebug("main", "Store Desk account Store filter changed", { slotMin"#,
|
||||
r#"frontendDebug("main", "Store Desk account Store filter changed", { slotMax"#,
|
||||
r#"frontendDebug("main", "Store Desk account detail opened", { pubkey"#,
|
||||
"dataPreviewHex:",
|
||||
] {
|
||||
assert!(!frontend.contains(forbidden), "account business/filter value leaked into frontend tracing: {forbidden}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_008_account_request_rejects_datatables_search_order_draw_network_and_physical_material() {
|
||||
let dto = include_str!("../src/dto_account.rs");
|
||||
let runtime = include_str!("../src/store_runtime.rs");
|
||||
for forbidden in ["draw:", "columns:", "search:", "order:", "cursor:", "network:", "connection_uri", "postgresql://", "endpoint"] {
|
||||
assert!(!dto.contains(forbidden), "forbidden DataTables/physical account request material present: {forbidden}");
|
||||
}
|
||||
assert!(runtime.contains("25 | 50 | 100"));
|
||||
assert!(runtime.contains("request.offset.parse::<u64>()"));
|
||||
assert!(runtime.contains("parse_optional_pubkey(request.pubkey.as_deref())"));
|
||||
assert!(runtime.contains("RawSlotRange::new"));
|
||||
assert!(runtime.contains("request.pubkey.parse::<ksp_store_lib::Pubkey>()"));
|
||||
assert!(runtime.contains("decode_hex_32(request.state_hash.as_str())"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_008_account_copy_tracing_never_logs_identity_or_data_material() {
|
||||
let frontend = include_str!("../frontend/ts/main.ts");
|
||||
for required in ["account-pubkey", "account-state-hash", "account-owner", "account-data-preview"] {
|
||||
assert!(frontend.contains(required), "missing account copy field id: {required}");
|
||||
}
|
||||
for forbidden in [
|
||||
r#"frontendDebug("main", "Store Desk long text copy requested", { fieldId, value })"#,
|
||||
r#"frontendDebug("main", "Store Desk long text copy completed", { fieldId, value })"#,
|
||||
r#"frontendError("main", "Store Desk long text copy failed", { fieldId, value })"#,
|
||||
] {
|
||||
assert!(!frontend.contains(forbidden), "account copy tracing leaked copied value material: {forbidden}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user