Files
MetaCrate/tests/compat/tests/inventory_ais_semantics.rs

303 lines
11 KiB
Rust

// Exact Rust translations of LibreMetaverse.Tests/ConstructorNullArgumentTests.cs and
// LibreMetaverse.Tests/InventoryAISClientTests.cs inventory-owned cases.
// Source SHA-256: 28deea0bf4d9353a2424842c6184abab8fe82746ceb12e093912728a247f21bc
// Source SHA-256: 6de18630ff0da2612721a9d4e28b5fdee5845c8d9477d322a8d608508762e1ff
use libremetaverse::{Error, GridClient, InventoryAISClient};
use libremetaverse_compat_tests::block_on;
use libremetaverse_structured_data::OSD;
use libremetaverse_types::{AssetType, InventoryType, SaleType, UUID};
use std::collections::HashMap;
use std::future::Future;
use std::sync::Arc;
use std::task::{Context, Poll, Waker};
use std::time::{SystemTime, UNIX_EPOCH};
fn uuid() -> UUID {
UUID::random().expect("UUID Random")
}
fn now_seconds() -> i32 {
i32::try_from(
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("clock before Unix epoch")
.as_secs(),
)
.expect("current Unix time fits the C# Int32 fixture")
}
fn map(entries: impl IntoIterator<Item = (&'static str, OSD)>) -> OSD {
OSD::Map(
entries
.into_iter()
.map(|(key, value)| (key.to_owned(), value))
.collect(),
)
}
fn permissions(creator: UUID, last_owner: UUID, owner: Option<UUID>) -> OSD {
map([
("creator_id", OSD::UUID(creator)),
("last_owner_id", OSD::UUID(last_owner)),
("owner_id", OSD::UUID(owner.unwrap_or(last_owner))),
("base_mask", OSD::Integer(0)),
("everyone_mask", OSD::Integer(0)),
("group_mask", OSD::Integer(0)),
("next_owner_mask", OSD::Integer(0)),
("owner_mask", OSD::Integer(0)),
("is_owner_group", OSD::Boolean(false)),
("group_id", OSD::UUID(UUID::zero())),
])
}
fn sale_info() -> OSD {
map([
("sale_price", OSD::Integer(0)),
("sale_type", OSD::Integer(SaleType::Not as i32)),
])
}
fn concrete_item(item_id: UUID, parent_id: UUID, agent_id: UUID, name: &str) -> OSD {
map([
("item_id", OSD::UUID(item_id)),
("parent_id", OSD::UUID(parent_id)),
("name", OSD::String(name.into())),
("desc", OSD::String("desc".into())),
("agent_id", OSD::UUID(agent_id)),
("inv_type", OSD::Integer(i32::from(InventoryType::OBJECT.0))),
("type", OSD::Integer(AssetType::Object as i32)),
("created_at", OSD::Integer(now_seconds())),
("permissions", permissions(uuid(), uuid(), Some(agent_id))),
("sale_info", sale_info()),
])
}
fn link_item(
item_id: UUID,
parent_id: UUID,
agent_id: UUID,
linked_id: UUID,
name: &str,
asset_type: AssetType,
) -> OSD {
map([
("item_id", OSD::UUID(item_id)),
("parent_id", OSD::UUID(parent_id)),
("name", OSD::String(name.into())),
("desc", OSD::String("desc".into())),
("agent_id", OSD::UUID(agent_id)),
("linked_id", OSD::UUID(linked_id)),
(
"inv_type",
OSD::Integer(i32::from(InventoryType::TEXTURE.0)),
),
("type", OSD::Integer(asset_type as i32)),
("created_at", OSD::Integer(now_seconds())),
("permissions", permissions(uuid(), uuid(), None)),
("sale_info", sale_info()),
])
}
fn section(name: &'static str, value: OSD, embedded: bool) -> OSD {
let content = map([(name, value)]);
if embedded {
map([("_embedded", content)])
} else {
content
}
}
fn numbered(value: OSD) -> OSD {
OSD::Map(HashMap::from([("0".into(), value)]))
}
fn client() -> InventoryAISClient {
let grid = GridClient::new().expect("GridClient constructor");
InventoryAISClient::new(Some(Arc::new(grid))).expect("InventoryAISClient constructor")
}
// parity-case: LibreMetaverse.Tests/ConstructorNullArgumentTests.cs::ConstructorNullArgumentTests.InventoryAISClient_Null_Throws::test ac92e375efc45c50b37e6c82aea372d605fceb470ce053a025e05ff47a5c7121 translated
#[test]
fn inventory_ais_client_null_throws() {
match InventoryAISClient::new(None) {
Err(error) => assert_eq!(error, Error::ArgumentNull),
Ok(_) => panic!("expected ArgumentNull for client"),
}
}
// parity-case: LibreMetaverse.Tests/InventoryAISClientTests.cs::InventoryAISClientTests.ParseLinksFromEmbedded_ObjectAsset_ResultsInAttachmentInventoryTypeAndParsesFields::test 3ae365ed34f12d036dcd44c94f8568d163cfeec2a58b4975975b77b418770131 translated
#[test]
fn parse_links_object_asset_results_in_attachment_type_and_parses_fields() {
let item_id = uuid();
let parent_id = uuid();
let agent_id = uuid();
let linked_id = uuid();
let response = section(
"links",
numbered(link_item(
item_id,
parent_id,
agent_id,
linked_id,
"TestObject",
AssetType::Object,
)),
true,
);
let result = client()
.parse_links_from_embedded(Some(response))
.expect("ParseLinksFromEmbedded");
assert_eq!(result.len(), 1);
let parsed = &result[0];
assert_eq!(parsed.base.name(), "TestObject");
assert_eq!(parsed.base.parent_uuid(), parent_id);
assert_eq!(parsed.asset_uuid(), linked_id);
assert_eq!(parsed.base.owner_id(), agent_id);
assert_ne!(parsed.creation_date(), UNIX_EPOCH);
}
// parity-case: LibreMetaverse.Tests/InventoryAISClientTests.cs::InventoryAISClientTests.ParseItemsFromEmbedded_ItemsKey_ParsesConcreteItems::test d9e7c64106639071e1ec6ada7346bfa050a31183becaac79efefcd4755fe2855 translated
#[test]
fn parse_items_items_key_parses_concrete_items() {
let item_id = uuid();
let parent_id = uuid();
let agent_id = uuid();
let response = section(
"items",
numbered(concrete_item(item_id, parent_id, agent_id, "ConcreteItem")),
true,
);
let result = client()
.parse_items_from_embedded(Some(response))
.expect("ParseItemsFromEmbedded");
assert_eq!(result.len(), 1);
let parsed = &result[0];
assert_eq!(parsed.base.name(), "ConcreteItem");
assert_eq!(parsed.base.parent_uuid(), parent_id);
assert_eq!(parsed.base.owner_id(), agent_id);
assert_ne!(parsed.creation_date(), UNIX_EPOCH);
}
// parity-case: LibreMetaverse.Tests/InventoryAISClientTests.cs::InventoryAISClientTests.ParseLinksFromEmbedded_MeshAsset_TreatedAsAttachment::test f807110d577c654128dd8d42e618c610c260c4f3367cf2795776564409f876a2 translated
#[test]
fn parse_links_mesh_asset_treated_as_attachment() {
let item_id = uuid();
let parent_id = uuid();
let agent_id = uuid();
let linked_id = uuid();
let response = section(
"links",
numbered(link_item(
item_id,
parent_id,
agent_id,
linked_id,
"MeshLink",
AssetType::Mesh,
)),
false,
);
let result = client()
.parse_links_from_embedded(Some(response))
.expect("ParseLinksFromEmbedded");
assert_eq!(result.len(), 1);
let parsed = &result[0];
assert_eq!(parsed.base.name(), "MeshLink");
assert_eq!(parsed.base.parent_uuid(), parent_id);
assert_eq!(parsed.asset_uuid(), linked_id);
}
// parity-case: LibreMetaverse.Tests/InventoryAISClientTests.cs::InventoryAISClientTests.ParseItemsFromEmbedded_TopLevelItemsKey_WorksWithoutEmbedded::test 9c8f2090d59ff5e75e75381a7283c501cadd56e591991cdead23c504738a0a6d translated
#[test]
fn parse_items_top_level_items_key_works_without_embedded() {
let response = section(
"items",
numbered(concrete_item(uuid(), uuid(), uuid(), "TopLevelItem")),
false,
);
let result = client()
.parse_items_from_embedded(Some(response))
.expect("ParseItemsFromEmbedded");
assert_eq!(result.len(), 1);
assert_eq!(result[0].base.name(), "TopLevelItem");
}
// parity-case: LibreMetaverse.Tests/InventoryAISClientTests.cs::InventoryAISClientTests.ParseLinksFromEmbedded_TopLevelLinksKey_WorksWithoutEmbedded::test 29afd2bd6a554959d6cfa99b632672d56bbb5bcad2ccbaf8caf4773a514f5d79 translated
#[test]
fn parse_links_top_level_links_key_works_without_embedded() {
let response = section(
"links",
numbered(link_item(
uuid(),
uuid(),
uuid(),
uuid(),
"TopLevelLink",
AssetType::Object,
)),
false,
);
let result = client()
.parse_links_from_embedded(Some(response))
.expect("ParseLinksFromEmbedded");
assert_eq!(result.len(), 1);
assert_eq!(result[0].base.name(), "TopLevelLink");
}
// parity-case: LibreMetaverse.Tests/InventoryAISClientTests.cs::InventoryAISClientTests.ParseItemsFromEmbedded_NullOrEmpty_ReturnsEmptyList::test 198fb619bbf396a4b1a7b4b85b7fba8808ae127e2575b2b84d21f01a2bdbc445 translated
#[test]
fn parse_items_null_or_empty_returns_empty_list() {
let ais = client();
assert!(
ais.parse_items_from_embedded(None)
.expect("ParseItemsFromEmbedded null")
.is_empty()
);
assert!(
ais.parse_items_from_embedded(Some(OSD::Map(HashMap::new())))
.expect("ParseItemsFromEmbedded empty")
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/InventoryAISClientTests.cs::InventoryAISClientTests.ParseEmbedded_CombinesItemsAndLinks::test f2ebf4638c9aef3c846dc182d97d80c95118799428cf8c2bba86163e33196846 translated
#[test]
fn parse_embedded_combines_items_and_links() {
let item = concrete_item(uuid(), uuid(), uuid(), "I");
let link = link_item(uuid(), uuid(), uuid(), uuid(), "L", AssetType::Object);
let response = map([(
"_embedded",
map([("items", numbered(item)), ("links", numbered(link))]),
)]);
let mut folders = None;
let mut items = None;
let mut links = None;
client()
.parse_embedded(response, &mut folders, &mut items, &mut links)
.expect("ParseEmbedded");
assert_eq!(items.expect("items output").len(), 1);
assert_eq!(links.expect("links output").len(), 1);
assert!(folders.is_some(), "folders output must not be null");
}
// parity-case: LibreMetaverse.Tests/InventoryAISClientTests.cs::InventoryAISClientTests.MoveCategoryLinksAsync_AlwaysReturnsFalse::test bebad05897efc0da2f959b4f567faa3ffee950520d13265ecbab1dee978f4886 translated
#[test]
fn move_category_links_always_returns_false() {
let result = block_on(client().move_category_links("outfit".into(), uuid(), None))
.expect("MoveCategoryLinksAsync");
assert!(!result, "AIS v3 has no MoveCategoryLinks equivalent");
}
// parity-case: LibreMetaverse.Tests/InventoryAISClientTests.cs::InventoryAISClientTests.MoveCategoryLinksAsync_ReturnsCompletedTask::test f9830b11e6a75c90f8394a5ade56bbd542c140be4c050ba7db6c9ee4d2b7a699 translated
#[test]
fn move_category_links_returns_completed_future() {
let ais = client();
let mut future = std::pin::pin!(ais.move_category_links("outfit".into(), uuid(), None));
let mut context = Context::from_waker(Waker::noop());
assert!(
matches!(future.as_mut().poll(&mut context), Poll::Ready(Ok(false))),
"MoveCategoryLinksAsync should be immediately ready with false"
);
}