test: add 31 meaningful unit tests for business logic
Activity receive() tests (src/tests/activities.rs):
- Accept: updates following_status to Accepted with correct user/actor
- Reject: removes following with correct user/actor
- Undo(Follow): removes follower + calls on_actor_removed
- Undo(Like): calls on_unlike for local objects; ignores remote objects
- Undo(Announce): removes announce record + calls on_announce_removed for local;
removes record but skips notification for remote objects
- Create: uses object["id"] not activity id; mention fires on_mention + on_create
- Update: uses object["id"]
- Delete(object): calls on_delete; does NOT call on_actor_removed
- Delete(actor): calls on_actor_removed; does NOT call on_delete
- Announce(local): records announce + calls on_announce_received
- Announce(remote): calls on_announce_of_remote; does NOT record announce
- Like(local): calls on_like
- Like(remote): silently ignored
- Add: uses object["id"] not activity id
- Block: removes both following and follower
- Domain block: activity skipped before any processing
- Actor block: Follow skipped before HTTP dereference (SSRF fix)
- Idempotency: duplicate delivery skipped
Actor serialization tests (src/tests/actors.rs):
- actor_type=Service serializes as "Service"
- discoverable=false serializes
- also_known_as serializes as JSON array (all aliases, not just first)
- optional fields omitted when None
- featured URL serialized when set
Visibility addressing tests (src/tests/broadcast.rs):
- Public: to=[AS_PUBLIC], cc=[followers]
- FollowersOnly: to=[followers], cc=[] — AS_PUBLIC absent
- Private: both empty
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use super::*;
|
||||
|
||||
// ── Person AP JSON serialization ──────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn person_serializes_with_enriched_fields() {
|
||||
let person = Person {
|
||||
@@ -13,7 +15,7 @@ fn person_serializes_with_enriched_fields() {
|
||||
outbox: Some("https://example.com/users/1/outbox".parse().unwrap()),
|
||||
followers: Some("https://example.com/users/1/followers".parse().unwrap()),
|
||||
following: Some("https://example.com/users/1/following".parse().unwrap()),
|
||||
public_key: PublicKey {
|
||||
public_key: activitypub_federation::protocol::public_key::PublicKey {
|
||||
id: "https://example.com/users/1#main-key".to_string(),
|
||||
owner: "https://example.com/users/1".parse().unwrap(),
|
||||
public_key_pem: "pem".to_string(),
|
||||
@@ -27,7 +29,7 @@ fn person_serializes_with_enriched_fields() {
|
||||
url: Some("https://example.com/u/alice".parse().unwrap()),
|
||||
discoverable: Some(true),
|
||||
manually_approves_followers: true,
|
||||
updated: Some(Utc::now()),
|
||||
updated: Some(chrono::Utc::now()),
|
||||
endpoints: Some(Endpoints {
|
||||
shared_inbox: "https://example.com/inbox".parse().unwrap(),
|
||||
}),
|
||||
@@ -47,4 +49,94 @@ fn person_serializes_with_enriched_fields() {
|
||||
json["endpoints"]["sharedInbox"],
|
||||
"https://example.com/inbox"
|
||||
);
|
||||
assert_eq!(json["featured"], "https://example.com/users/1/featured");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn person_actor_type_service_serializes_correctly() {
|
||||
let mut person = minimal_person();
|
||||
person.kind = crate::user::ApActorType::Service;
|
||||
let json = serde_json::to_value(&person).unwrap();
|
||||
assert_eq!(json["type"], "Service");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn person_discoverable_false_serializes() {
|
||||
let mut person = minimal_person();
|
||||
person.discoverable = Some(false);
|
||||
let json = serde_json::to_value(&person).unwrap();
|
||||
assert_eq!(json["discoverable"], false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn person_also_known_as_serializes_as_array() {
|
||||
let mut person = minimal_person();
|
||||
person.also_known_as = vec![
|
||||
"https://old.example/users/alice".to_string(),
|
||||
"https://other.example/users/alice".to_string(),
|
||||
];
|
||||
let json = serde_json::to_value(&person).unwrap();
|
||||
assert!(
|
||||
json["alsoKnownAs"].is_array(),
|
||||
"alsoKnownAs must serialize as a JSON array"
|
||||
);
|
||||
assert_eq!(json["alsoKnownAs"].as_array().unwrap().len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn person_omits_optional_fields_when_none() {
|
||||
let person = minimal_person();
|
||||
let json = serde_json::to_value(&person).unwrap();
|
||||
assert!(
|
||||
json.get("summary").is_none(),
|
||||
"null summary should be omitted"
|
||||
);
|
||||
assert!(json.get("icon").is_none(), "null icon should be omitted");
|
||||
assert!(
|
||||
json.get("featured").is_none(),
|
||||
"null featured should be omitted"
|
||||
);
|
||||
assert!(json.get("url").is_none(), "null url should be omitted");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn person_featured_omitted_when_none() {
|
||||
let mut person = minimal_person();
|
||||
person.featured = None;
|
||||
let json = serde_json::to_value(&person).unwrap();
|
||||
assert!(json.get("featured").is_none());
|
||||
}
|
||||
|
||||
// ── helper ────────────────────────────────────────────────────────────────────
|
||||
|
||||
fn minimal_person() -> Person {
|
||||
Person {
|
||||
kind: Default::default(),
|
||||
id: "https://example.com/users/1"
|
||||
.parse::<url::Url>()
|
||||
.unwrap()
|
||||
.into(),
|
||||
preferred_username: "alice".to_string(),
|
||||
inbox: "https://example.com/users/1/inbox".parse().unwrap(),
|
||||
outbox: None,
|
||||
followers: None,
|
||||
following: None,
|
||||
public_key: activitypub_federation::protocol::public_key::PublicKey {
|
||||
id: "https://example.com/users/1#main-key".to_string(),
|
||||
owner: "https://example.com/users/1".parse().unwrap(),
|
||||
public_key_pem: "pem".to_string(),
|
||||
},
|
||||
name: None,
|
||||
summary: None,
|
||||
icon: None,
|
||||
url: None,
|
||||
discoverable: None,
|
||||
manually_approves_followers: false,
|
||||
updated: None,
|
||||
endpoints: None,
|
||||
image: None,
|
||||
also_known_as: vec![],
|
||||
attachment: vec![],
|
||||
featured: None,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user