Translate world-state parity tests
This commit is contained in:
@@ -1036,16 +1036,18 @@ pub enum FolderType {
|
||||
|
||||
/// C# type: `T:LibreMetaverse.HoleType`.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum HoleType {
|
||||
#[repr(transparent)]
|
||||
pub struct HoleType(pub u8);
|
||||
#[allow(non_upper_case_globals)]
|
||||
impl HoleType {
|
||||
/// C# member: `F:LibreMetaverse.HoleType.Circle`.
|
||||
Circle = 16,
|
||||
pub const Circle: Self = Self(16);
|
||||
/// C# member: `F:LibreMetaverse.HoleType.Same`.
|
||||
Same = 0,
|
||||
pub const Same: Self = Self(0);
|
||||
/// C# member: `F:LibreMetaverse.HoleType.Square`.
|
||||
Square = 32,
|
||||
pub const Square: Self = Self(32);
|
||||
/// C# member: `F:LibreMetaverse.HoleType.Triangle`.
|
||||
Triangle = 48,
|
||||
pub const Triangle: Self = Self(48);
|
||||
}
|
||||
|
||||
/// C# type: `T:LibreMetaverse.ICacheDictionaryRemovalStrategy`1`.
|
||||
|
||||
@@ -901,7 +901,9 @@ impl AgentManager {
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.AgentManager.#ctor(LibreMetaverse.GridClient)`.
|
||||
pub fn new(client: libremetaverse::GridClient) -> Result<Self, crate::Error> {
|
||||
pub fn new(
|
||||
client: Option<std::sync::Arc<libremetaverse::GridClient>>,
|
||||
) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.AgentManager.#ctor(LibreMetaverse.GridClient)",
|
||||
)
|
||||
@@ -11611,7 +11613,9 @@ impl GridManager {
|
||||
libremetaverse_types::unimplemented_api!("E:LibreMetaverse.GridManager.RegionHandleReply")
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.GridManager.#ctor(LibreMetaverse.GridClient)`.
|
||||
pub fn new(client: libremetaverse::GridClient) -> Result<Self, crate::Error> {
|
||||
pub fn new(
|
||||
client: Option<std::sync::Arc<libremetaverse::GridClient>>,
|
||||
) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.GridManager.#ctor(LibreMetaverse.GridClient)",
|
||||
)
|
||||
@@ -20642,7 +20646,9 @@ impl ObjectManager {
|
||||
/// C# member: `F:LibreMetaverse.ObjectManager.HAVOK_TIMESTEP`.
|
||||
pub const HAVOK_TIMESTEP: f32 = 0.022222223;
|
||||
/// C# member: `M:LibreMetaverse.ObjectManager.#ctor(LibreMetaverse.GridClient)`.
|
||||
pub fn new(client: libremetaverse::GridClient) -> Result<Self, crate::Error> {
|
||||
pub fn new(
|
||||
client: Option<std::sync::Arc<libremetaverse::GridClient>>,
|
||||
) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.ObjectManager.#ctor(LibreMetaverse.GridClient)",
|
||||
)
|
||||
@@ -23536,7 +23542,7 @@ pub struct Primitive {
|
||||
/// C# member: `F:LibreMetaverse.Primitive.Flags`.
|
||||
pub flags: libremetaverse_types::PrimFlags,
|
||||
/// C# member: `F:LibreMetaverse.Primitive.Flexible`.
|
||||
pub flexible: libremetaverse::PrimitiveFlexibleData,
|
||||
pub flexible: Option<libremetaverse::PrimitiveFlexibleData>,
|
||||
/// C# member: `F:LibreMetaverse.Primitive.GroupID`.
|
||||
pub group_id: libremetaverse_types::UUID,
|
||||
/// C# member: `F:LibreMetaverse.Primitive.ID`.
|
||||
@@ -23550,9 +23556,9 @@ pub struct Primitive {
|
||||
/// C# member: `F:LibreMetaverse.Primitive.JointPivot`.
|
||||
pub joint_pivot: libremetaverse_types::Vector3,
|
||||
/// C# member: `F:LibreMetaverse.Primitive.Light`.
|
||||
pub light: libremetaverse::PrimitiveLightData,
|
||||
pub light: Option<libremetaverse::PrimitiveLightData>,
|
||||
/// C# member: `F:LibreMetaverse.Primitive.LightMap`.
|
||||
pub light_map: libremetaverse::PrimitiveLightImage,
|
||||
pub light_map: Option<libremetaverse::PrimitiveLightImage>,
|
||||
/// C# member: `F:LibreMetaverse.Primitive.LocalID`.
|
||||
pub local_id: u32,
|
||||
/// C# member: `F:LibreMetaverse.Primitive.MediaURL`.
|
||||
@@ -24550,7 +24556,7 @@ pub struct PrimitiveTextureEntry {
|
||||
/// C# member: `F:LibreMetaverse.Primitive.TextureEntry.DefaultTexture`.
|
||||
pub default_texture: Option<libremetaverse::PrimitiveTextureEntryFace>,
|
||||
/// C# member: `F:LibreMetaverse.Primitive.TextureEntry.FaceTextures`.
|
||||
pub face_textures: Vec<libremetaverse::PrimitiveTextureEntryFace>,
|
||||
pub face_textures: Vec<Option<libremetaverse::PrimitiveTextureEntryFace>>,
|
||||
}
|
||||
impl PrimitiveTextureEntry {
|
||||
/// C# member: `F:LibreMetaverse.Primitive.TextureEntry.MAX_FACES`.
|
||||
@@ -24597,9 +24603,9 @@ impl PrimitiveTextureEntry {
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.CreateFace(System.UInt32)`.
|
||||
pub fn create_face(
|
||||
&self,
|
||||
&mut self,
|
||||
index: u32,
|
||||
) -> Result<libremetaverse::PrimitiveTextureEntryFace, crate::Error> {
|
||||
) -> Result<&mut libremetaverse::PrimitiveTextureEntryFace, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Primitive.TextureEntry.CreateFace(System.UInt32)",
|
||||
)
|
||||
@@ -24620,7 +24626,7 @@ impl PrimitiveTextureEntry {
|
||||
pub fn get_face(
|
||||
&self,
|
||||
index: u32,
|
||||
) -> Result<libremetaverse::PrimitiveTextureEntryFace, crate::Error> {
|
||||
) -> Result<Option<&libremetaverse::PrimitiveTextureEntryFace>, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Primitive.TextureEntry.GetFace(System.UInt32)",
|
||||
)
|
||||
@@ -26821,7 +26827,7 @@ pub enum SlappCommand {
|
||||
pub struct SlurlParser;
|
||||
impl SlurlParser {
|
||||
/// C# member: `M:LibreMetaverse.SlurlParser.#ctor(System.String)`.
|
||||
pub fn new(location: String) -> Result<Self, crate::Error> {
|
||||
pub fn new(location: Option<String>) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented("M:LibreMetaverse.SlurlParser.#ctor(System.String)")
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.SlurlParser.GetAgentUrl(LibreMetaverse.UUID,System.String)`.
|
||||
|
||||
@@ -12,6 +12,8 @@ mod asset_archive_semantics;
|
||||
mod avatar_animesh_semantics;
|
||||
#[cfg(test)]
|
||||
mod batch_link_internal_semantics;
|
||||
#[cfg(test)]
|
||||
mod world_internal_semantics;
|
||||
|
||||
type Terrain = Vec<Vec<f32>>;
|
||||
type TerrainLoaded = Box<dyn Fn(Terrain, i64, i64) + Send + Sync>;
|
||||
@@ -124,6 +126,44 @@ impl InventoryAISClient {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl AgentManager {
|
||||
fn extract_experience_permission(
|
||||
_map: libremetaverse_structured_data::OSDMap,
|
||||
_experience_id: libremetaverse_types::UUID,
|
||||
) -> Result<String, Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.AgentManager.ExtractExperiencePermission(LibreMetaverse.StructuredData.OSDMap,LibreMetaverse.UUID)",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code, clippy::unused_self)]
|
||||
impl EstateTools {
|
||||
fn estate_owner_message_handler(
|
||||
&self,
|
||||
_packet: packets::EstateOwnerMessagePacket,
|
||||
_simulator: Simulator,
|
||||
) -> Result<(), Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.EstateTools.EstateOwnerMessageHandler(System.Object,LibreMetaverse.PacketReceivedEventArgs)",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code, clippy::unused_self)]
|
||||
impl NetworkManager {
|
||||
fn raise_sim_console_response(
|
||||
&self,
|
||||
_message: messages::linden::SimConsoleResponseMessage,
|
||||
_simulator: Simulator,
|
||||
) -> Result<(), Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"F:LibreMetaverse.NetworkManager.CapsEvents.SimConsoleResponse",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl imaging::Baker {
|
||||
fn resize_to_bake_dimensions(
|
||||
|
||||
217
crates/libremetaverse/src/world_internal_semantics.rs
Normal file
217
crates/libremetaverse/src/world_internal_semantics.rs
Normal file
@@ -0,0 +1,217 @@
|
||||
// Exact Rust translations of the C# tests that deliberately invoke internal handlers.
|
||||
// Source SHA-256: 74fa1275cd1f6c2a372af2fefc011a3e764f028a8957291d61f599bcb023a8ff
|
||||
// Source SHA-256: 7b67b72c2ad652626126d0e4eda7e8c26fc94c28f0f915238b2925f80a3d4af2
|
||||
|
||||
use super::*;
|
||||
use libremetaverse_structured_data::{OSD, OSDMap};
|
||||
use libremetaverse_types::UUID;
|
||||
use packets::{
|
||||
EstateOwnerMessagePacket, EstateOwnerMessagePacketAgentDataBlock,
|
||||
EstateOwnerMessagePacketMethodDataBlock, EstateOwnerMessagePacketParamListBlock,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::task::{Context, Poll, Wake, Waker};
|
||||
use std::time::Duration;
|
||||
|
||||
fn uuid() -> UUID {
|
||||
UUID::random().expect("UUID Random")
|
||||
}
|
||||
|
||||
fn ids(values: impl IntoIterator<Item = UUID>) -> OSD {
|
||||
OSD::Array(values.into_iter().map(OSD::UUID).collect())
|
||||
}
|
||||
|
||||
fn map(entries: impl IntoIterator<Item = (&'static str, OSD)>) -> OSDMap {
|
||||
OSDMap::new_with_dictionary(
|
||||
entries
|
||||
.into_iter()
|
||||
.map(|(key, value)| (key.into(), value))
|
||||
.collect(),
|
||||
)
|
||||
.expect("OSDMap dictionary constructor")
|
||||
}
|
||||
|
||||
fn simulator() -> Simulator {
|
||||
Simulator::new(
|
||||
GridClient::new().expect("simulator GridClient constructor"),
|
||||
"127.0.0.1:13".parse().unwrap(),
|
||||
0,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("Simulator constructor")
|
||||
}
|
||||
|
||||
fn estate_packet(blocked: &[UUID], trusted: &[UUID], allowed: &[UUID]) -> EstateOwnerMessagePacket {
|
||||
let counts = [
|
||||
"1".to_owned(),
|
||||
"0".to_owned(),
|
||||
blocked.len().to_string(),
|
||||
trusted.len().to_string(),
|
||||
allowed.len().to_string(),
|
||||
];
|
||||
let mut parameters = counts
|
||||
.into_iter()
|
||||
.map(|value| EstateOwnerMessagePacketParamListBlock {
|
||||
parameter: value.as_bytes().to_vec(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
parameters.extend(blocked.iter().chain(trusted).chain(allowed).map(|id| {
|
||||
EstateOwnerMessagePacketParamListBlock {
|
||||
parameter: id.get_bytes().expect("UUID bytes"),
|
||||
}
|
||||
}));
|
||||
EstateOwnerMessagePacket {
|
||||
agent_data: EstateOwnerMessagePacketAgentDataBlock {
|
||||
agent_id: uuid(),
|
||||
session_id: uuid(),
|
||||
transaction_id: uuid(),
|
||||
},
|
||||
method_data: EstateOwnerMessagePacketMethodDataBlock {
|
||||
method: b"setexperience".to_vec(),
|
||||
invoice: UUID::zero(),
|
||||
},
|
||||
param_list: parameters,
|
||||
}
|
||||
}
|
||||
|
||||
fn block_on_with<F: Future>(future: F, mut after_pending: impl FnMut()) -> F::Output {
|
||||
struct ThreadWake(std::thread::Thread);
|
||||
impl Wake for ThreadWake {
|
||||
fn wake(self: Arc<Self>) {
|
||||
self.0.unpark();
|
||||
}
|
||||
}
|
||||
let waker = Waker::from(Arc::new(ThreadWake(std::thread::current())));
|
||||
let mut context = Context::from_waker(&waker);
|
||||
let mut future = std::pin::pin!(future);
|
||||
let mut invoked = false;
|
||||
loop {
|
||||
match future.as_mut().poll(&mut context) {
|
||||
Poll::Ready(value) => return value,
|
||||
Poll::Pending if !invoked => {
|
||||
invoked = true;
|
||||
after_pending();
|
||||
}
|
||||
Poll::Pending => std::thread::park_timeout(Duration::from_millis(10)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/EstateExperienceReplyTests.cs::EstateExperienceReplyTests.SetExperience_ParsesBlockedTrustedAndAllowedLists::test 49a77aa9d7c5bf1232082a08594e7ebcfafad11ab110c9e15d2ad4ea1831c649 translated
|
||||
#[test]
|
||||
fn set_experience_parses_blocked_trusted_and_allowed_lists() {
|
||||
let blocked = uuid();
|
||||
let trusted = uuid();
|
||||
let allowed = [uuid(), uuid()];
|
||||
let client = GridClient::new().expect("GridClient constructor");
|
||||
let estate = client.estate();
|
||||
let received = Arc::new(Mutex::new(None));
|
||||
let captured = Arc::clone(&received);
|
||||
let _subscription = estate.subscribe_estate_experience_reply(Arc::new(move |reply| {
|
||||
*captured.lock().unwrap() = Some((reply.blocked(), reply.trusted(), reply.allowed()));
|
||||
}));
|
||||
estate
|
||||
.estate_owner_message_handler(estate_packet(&[blocked], &[trusted], &allowed), simulator())
|
||||
.unwrap();
|
||||
let reply = received.lock().unwrap();
|
||||
let (actual_blocked, actual_trusted, actual_allowed) =
|
||||
reply.as_ref().expect("EstateExperienceReply event");
|
||||
assert_eq!(actual_blocked, &[blocked]);
|
||||
assert_eq!(actual_trusted, &[trusted]);
|
||||
assert_eq!(actual_allowed, &allowed);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/EstateExperienceReplyTests.cs::EstateExperienceReplyTests.SetExperience_AllEmptyLists_ProducesEmptyResult::test 711eaebb11f5d7ece92946d3de240a341a4b1fd8f30617fd97cb059d0dc6a0b9 translated
|
||||
#[test]
|
||||
fn set_experience_all_empty_lists_produces_empty_result() {
|
||||
let client = GridClient::new().expect("GridClient constructor");
|
||||
let estate = client.estate();
|
||||
let received = Arc::new(Mutex::new(None));
|
||||
let captured = Arc::clone(&received);
|
||||
let _subscription = estate.subscribe_estate_experience_reply(Arc::new(move |reply| {
|
||||
*captured.lock().unwrap() = Some((reply.blocked(), reply.trusted(), reply.allowed()));
|
||||
}));
|
||||
estate
|
||||
.estate_owner_message_handler(estate_packet(&[], &[], &[]), simulator())
|
||||
.unwrap();
|
||||
let reply = received.lock().unwrap();
|
||||
let (blocked, trusted, allowed) = reply.as_ref().expect("EstateExperienceReply event");
|
||||
assert!(blocked.is_empty());
|
||||
assert!(trusted.is_empty());
|
||||
assert!(allowed.is_empty());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/ExperiencePreferencesMessageTests.cs::ExperiencePreferencesMessageTests.ExtractExperiencePermission_Allowed_ReturnsAllow::test cf095ab428713004ebac6e1915a47ae0c03bd2958addbba2a39fd2f0edf51a74 translated
|
||||
#[test]
|
||||
fn extract_experience_permission_allowed_returns_allow() {
|
||||
let id = uuid();
|
||||
assert_eq!(
|
||||
AgentManager::extract_experience_permission(map([("experiences", ids([id]))]), id).unwrap(),
|
||||
"Allow"
|
||||
);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/ExperiencePreferencesMessageTests.cs::ExperiencePreferencesMessageTests.ExtractExperiencePermission_Blocked_ReturnsBlock::test af084d1ab7a11079e6251865e8fd5aecfde38d2df359ebc1e208bc74925935c0 translated
|
||||
#[test]
|
||||
fn extract_experience_permission_blocked_returns_block() {
|
||||
let id = uuid();
|
||||
assert_eq!(
|
||||
AgentManager::extract_experience_permission(map([("blocked", ids([id]))]), id).unwrap(),
|
||||
"Block"
|
||||
);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/ExperiencePreferencesMessageTests.cs::ExperiencePreferencesMessageTests.ExtractExperiencePermission_NeitherList_ReturnsForget::test 93204469ecfec2f3f4eb6838c99f6e2baf09bf76a075958d1ed369ba03767158 translated
|
||||
#[test]
|
||||
fn extract_experience_permission_neither_list_returns_forget() {
|
||||
let id = uuid();
|
||||
let input = OSDMap::new_with_dictionary(HashMap::from([
|
||||
("experiences".into(), ids([uuid()])),
|
||||
("blocked".into(), ids([uuid()])),
|
||||
]))
|
||||
.expect("OSDMap dictionary constructor");
|
||||
assert_eq!(
|
||||
AgentManager::extract_experience_permission(input, id).unwrap(),
|
||||
"Forget"
|
||||
);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/SimConsoleTests.cs::SimConsoleTests.SendSimConsoleCommandAsync_IgnoresPostBody_UsesSimConsoleResponseEvent::test df6eb48241f71c34074be66869c9ae1d5980186583259568728261b5eedd7c48 translated
|
||||
#[test]
|
||||
fn send_sim_console_command_ignores_post_body_and_uses_response_event() {
|
||||
let client = GridClient::new().expect("GridClient constructor");
|
||||
let estate = client.estate();
|
||||
let network = client.network();
|
||||
let result = block_on_with(
|
||||
estate.send_sim_console_command("show name".into(), Some(Duration::from_secs(5)), None),
|
||||
|| {
|
||||
let mut message = messages::linden::SimConsoleResponseMessage::new()
|
||||
.expect("SimConsoleResponseMessage constructor");
|
||||
message.body = "Agent Name".into();
|
||||
network
|
||||
.raise_sim_console_response(message, simulator())
|
||||
.unwrap();
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(result.as_deref(), Some("Agent Name"));
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/SimConsoleTests.cs::SimConsoleTests.SendSimConsoleCommandAsync_NoResponseEvent_ReturnsNullAfterTimeout::test 2ac5a6c96f3acec341056387d727288fd3661565bd2a7c385078602efe8661da translated
|
||||
#[test]
|
||||
fn send_sim_console_command_no_response_event_returns_none_after_timeout() {
|
||||
let client = GridClient::new().expect("GridClient constructor");
|
||||
let result = block_on_with(
|
||||
client.estate().send_sim_console_command(
|
||||
"show name".into(),
|
||||
Some(Duration::from_millis(200)),
|
||||
None,
|
||||
),
|
||||
|| {},
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.is_none());
|
||||
}
|
||||
Reference in New Issue
Block a user