DRY pass #2, batch 8: the Rust and ffi docs (#5372)

sync/mod.rs listed 5 of its 9 modules; migrate's doc sat above the v9 SQL;
client.rs had items after its test module; the ffi's sync_now doc had fused
into client_update's; complete_reminder (ffi and EditorAction) still said
recurrence advancement was to come, though the core does it; NoteQuery.view
listed views the core never matched and claimed it validated. Test scratch
dirs drop the old ts-/iw- prefixes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 15:05:43 -04:00
co-authored by Claude Opus 5.5
parent 2ce68f578a
commit 63abff8681
9 changed files with 93 additions and 90 deletions
+2 -2
View File
@@ -223,7 +223,7 @@ pub(crate) fn scratch(tag: &str) -> BlobStore {
use std::sync::atomic::{AtomicU32, Ordering};
static SEQ: AtomicU32 = AtomicU32::new(0);
let n = SEQ.fetch_add(1, Ordering::Relaxed);
let dir = std::env::temp_dir().join(format!("ts-blobs-{}-{n}-{tag}", std::process::id()));
let dir = std::env::temp_dir().join(format!("inkwell-blobs-{}-{n}-{tag}", std::process::id()));
let _ = fs::remove_dir_all(&dir);
BlobStore::new(dir).expect("scratch blob store")
}
@@ -326,7 +326,7 @@ mod tests {
#[test]
fn serving_refuses_a_path_that_isnt_a_hash() {
// Delegated to `path`, so the traversal guard is the same one `store` uses.
publish_root(std::env::temp_dir().join("ts-blobs-serve-guard"));
publish_root(std::env::temp_dir().join("inkwell-blobs-serve-guard"));
let (status, _, body) = serve("/../../etc/passwd", None);
assert_eq!(status, 404);
assert!(body.is_empty());
+69 -69
View File
@@ -594,75 +594,6 @@ fn describe_transport_error(base_url: &str, err: &reqwest::Error) -> String {
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_share_names_a_person_or_a_group() {
assert_eq!(
ShareTarget::Member("u1".into()).body("view"),
serde_json::json!({ "user_id": "u1", "permission": "view" })
);
assert_eq!(
ShareTarget::Group("g1".into()).body("edit"),
serde_json::json!({ "group_id": "g1", "permission": "edit" })
);
let raw = r#"{"id":"s2","member":null,
"group":{"id":"g1","name":"Family","member_count":3},
"permission":"edit"}"#;
let share: NoteShare = serde_json::from_str(raw).expect("a group share reads");
assert!(share.member.is_none());
assert_eq!(share.group.expect("group").member_count, 3);
// A server from before groups sends no `groups` at all.
let older: Directory = serde_json::from_str(r#"{"members":[]}"#).expect("directory");
assert!(older.groups.is_empty());
}
#[test]
fn urls_join_without_doubling_slashes() {
// normalize_base_url has already stripped any trailing slash, so plain
// concatenation is correct — this pins that assumption.
assert_eq!(
config_url("https://notes.example.com"),
"https://notes.example.com/api/config"
);
assert_eq!(
device_login_url("https://notes.example.com"),
"https://notes.example.com/api/auth/device-login"
);
assert_eq!(
me_url("https://notes.example.com"),
"https://notes.example.com/api/auth/me"
);
assert_eq!(
revoke_self_url("https://notes.example.com"),
"https://notes.example.com/api/auth/devices/self"
);
}
#[test]
fn revoke_outcome_serializes_tagged_for_the_frontend() {
// The UI decides between "signed out on the server" and "still valid, go
// revoke it" by reading this tag, so its shape is part of the contract.
let json = serde_json::to_string(&RevokeOutcome::Failed {
reason: "offline".into(),
})
.expect("outcome serializes");
assert!(json.contains("\"status\":\"failed\""), "got {json}");
let json = serde_json::to_string(&RevokeOutcome::Revoked).expect("outcome serializes");
assert!(json.contains("\"status\":\"revoked\""), "got {json}");
}
#[test]
fn urls_preserve_a_port_and_subpath() {
assert_eq!(
config_url("http://192.168.1.10:8000/inkwell"),
"http://192.168.1.10:8000/inkwell/api/config"
);
}
}
/// The Android client a linked server can hand out.
///
/// Mirrors `/api/client/android` (see the server's `client_dist.py`). Absent there
@@ -782,3 +713,72 @@ pub async fn download_client(
std::fs::rename(&partial, dest)
.map_err(|e| format!("Couldn't put the downloaded update in place: {e}"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_share_names_a_person_or_a_group() {
assert_eq!(
ShareTarget::Member("u1".into()).body("view"),
serde_json::json!({ "user_id": "u1", "permission": "view" })
);
assert_eq!(
ShareTarget::Group("g1".into()).body("edit"),
serde_json::json!({ "group_id": "g1", "permission": "edit" })
);
let raw = r#"{"id":"s2","member":null,
"group":{"id":"g1","name":"Family","member_count":3},
"permission":"edit"}"#;
let share: NoteShare = serde_json::from_str(raw).expect("a group share reads");
assert!(share.member.is_none());
assert_eq!(share.group.expect("group").member_count, 3);
// A server from before groups sends no `groups` at all.
let older: Directory = serde_json::from_str(r#"{"members":[]}"#).expect("directory");
assert!(older.groups.is_empty());
}
#[test]
fn urls_join_without_doubling_slashes() {
// normalize_base_url has already stripped any trailing slash, so plain
// concatenation is correct — this pins that assumption.
assert_eq!(
config_url("https://notes.example.com"),
"https://notes.example.com/api/config"
);
assert_eq!(
device_login_url("https://notes.example.com"),
"https://notes.example.com/api/auth/device-login"
);
assert_eq!(
me_url("https://notes.example.com"),
"https://notes.example.com/api/auth/me"
);
assert_eq!(
revoke_self_url("https://notes.example.com"),
"https://notes.example.com/api/auth/devices/self"
);
}
#[test]
fn revoke_outcome_serializes_tagged_for_the_frontend() {
// The UI decides between "signed out on the server" and "still valid, go
// revoke it" by reading this tag, so its shape is part of the contract.
let json = serde_json::to_string(&RevokeOutcome::Failed {
reason: "offline".into(),
})
.expect("outcome serializes");
assert!(json.contains("\"status\":\"failed\""), "got {json}");
let json = serde_json::to_string(&RevokeOutcome::Revoked).expect("outcome serializes");
assert!(json.contains("\"status\":\"revoked\""), "got {json}");
}
#[test]
fn urls_preserve_a_port_and_subpath() {
assert_eq!(
config_url("http://192.168.1.10:8000/inkwell"),
"http://192.168.1.10:8000/inkwell/api/config"
);
}
}
+4
View File
@@ -8,6 +8,10 @@
//! - `client` — HTTP transport: the handshake call and device-token auth.
//! - `state` — the persisted link record (server, token, change-feed cursor).
//! - `engine` — one full cycle: push local changes, then pull the server's.
//! - `link` — linking a device to a server and unlinking it, one flow for every client.
//! - `pull` / `push` — the two halves of that cycle.
//! - `wire` — the delta-feed JSON shapes, as the server sends them.
//! - `blobs` — attachment bytes on disk, filed under their own sha256.
//! - `sharing` — the Share dialog's calls, straight to the server (#5175).
//!
//! The UI surface that drives this lives in whichever client is wrapping the crate,