Translate complete RLV test suite

This commit is contained in:
2026-08-08 23:21:40 +02:00
parent 1604822689
commit 3140e65dc7
31 changed files with 14434 additions and 4938 deletions

View File

@@ -60,8 +60,8 @@ The current workspace is a structural baseline, not a working client:
members with real fields/constants/enum values and standardized failing members with real fields/constants/enum values and standardized failing
bodies; bodies;
- all 1,289 real NUnit `[Test]`/`[TestCase]` invocations have stable catalog - all 1,289 real NUnit `[Test]`/`[TestCase]` invocations have stable catalog
entries; 650 are translated, 19 live-grid cases and four benchmarks are entries; all 1,266 non-live, non-benchmark cases are translated, all 19
reviewed, and 616 remain pending without executable placeholder tests; live-grid cases and four benchmarks are reviewed, and none remain pending;
- all nine sample/tool projects have compiling Rust binary targets; - all nine sample/tool projects have compiling Rust binary targets;
- the 128 TestClient command source files are retained as a command inventory. - the 128 TestClient command source files are retained as a command inventory.
@@ -334,8 +334,9 @@ markers in hand-written Rust files, so regeneration records unresolved cases
without creating fake executable tests and fails on body drift. The checked-in without creating fake executable tests and fails on body drift. The checked-in
audit reports pending, translated, ignored-live, benchmark, drifted, missing, audit reports pending, translated, ignored-live, benchmark, drifted, missing,
duplicate, stale, and unreviewed cases. The initial handover contained 1,289 duplicate, stale, and unreviewed cases. The initial handover contained 1,289
unreviewed cases; the current ledger contains 488 translated, 18 reviewed unreviewed cases; the current ledger contains all 1,266 ordinary cases as
live-grid cases, four benchmark-reviewed, and 779 pending cases. translated, 19 reviewed live-grid cases, four benchmark-reviewed cases, and no
pending or unreviewed cases.
The Rust tests must call the public APIs rather than internal replacements. The Rust tests must call the public APIs rather than internal replacements.
Where the C# tests call internal members through friend-assembly access, record Where the C# tests call internal members through friend-assembly access, record

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,7 @@
//! Shared deterministic fixtures used by translated compatibility tests. //! Shared deterministic fixtures used by translated compatibility tests.
pub mod rlv_support;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::future::Future; use std::future::Future;
use std::io; use std::io;

View File

@@ -0,0 +1,491 @@
//! Recording callbacks shared by the RLV translations.
use libremetaverse_rlv::{
AttachmentRequest, CameraSettings, IRlvActionCallbacks, IRlvQueryCallbacks, InventoryMap,
RlvAttachmentPoint, RlvInventoryItem, RlvService, RlvSharedFolder,
};
use libremetaverse_types::Error;
use libremetaverse_types::compat::{CancellationToken, Guid};
use std::collections::{BTreeMap, HashMap};
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
pub const SENDER_NAME: &str = "Sender 1";
pub const SENDER_ID: &str = "ffffffff-ffff-4fff-8fff-ffffffffffff";
/// Parses a UUID literal used by the pinned RLV fixtures.
///
/// # Panics
///
/// Panics when `value` is not a 32-digit hexadecimal UUID, ignoring hyphens.
#[must_use]
pub fn guid(value: &str) -> Guid {
let digits: Vec<_> = value.bytes().filter(|byte| *byte != b'-').collect();
assert_eq!(digits.len(), 32, "valid RLV test UUID");
let mut bytes = [0; 16];
for (index, pair) in digits.chunks_exact(2).enumerate() {
let digit = |byte| match byte {
b'0'..=b'9' => byte - b'0',
b'a'..=b'f' => byte - b'a' + 10,
b'A'..=b'F' => byte - b'A' + 10,
_ => panic!("valid RLV test UUID"),
};
bytes[index] = digit(pair[0]) << 4 | digit(pair[1]);
}
Guid(bytes)
}
#[derive(Clone, Debug, PartialEq)]
pub struct AttachmentCall {
pub item_id: Guid,
pub point: RlvAttachmentPoint,
pub replace: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct TeleportCall {
pub x: f32,
pub y: f32,
pub z: f32,
pub region: Option<String>,
pub look_at: Option<Option<f32>>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ActionLog {
pub adjusted_heights: Vec<(f32, f32, f32)>,
pub attachments: Vec<Vec<AttachmentCall>>,
pub detachments: Vec<Vec<Guid>>,
pub removed_outfits: Vec<Vec<Guid>>,
pub instant_messages: Vec<(Guid, String)>,
pub replies: Vec<(i32, String)>,
pub camera_fovs: Vec<f32>,
pub debug_settings: Vec<(String, String)>,
pub environment_settings: Vec<(String, String)>,
pub group_ids: Vec<(Guid, Option<String>)>,
pub group_names: Vec<(String, Option<String>)>,
pub rotations: Vec<f32>,
pub sits: Vec<Guid>,
pub sit_ground_count: usize,
pub teleports: Vec<TeleportCall>,
pub unsit_count: usize,
}
#[derive(Clone, Default)]
pub struct RecordingActions(pub Arc<Mutex<ActionLog>>);
type ActionFuture<'a> = Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>>;
impl IRlvActionCallbacks for RecordingActions {
fn adjust_height(
&self,
distance: f32,
factor: f32,
delta: f32,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0
.lock()
.unwrap()
.adjusted_heights
.push((distance, factor, delta));
Box::pin(async { Ok(()) })
}
fn attach(&self, requests: Vec<AttachmentRequest>, _: CancellationToken) -> ActionFuture<'_> {
let calls = requests
.iter()
.map(|request| AttachmentCall {
item_id: request.item_id(),
point: request.attachment_point(),
replace: request.replace_existing_attachments(),
})
.collect();
self.0.lock().unwrap().attachments.push(calls);
Box::pin(async { Ok(()) })
}
fn detach(&self, item_ids: Vec<Guid>, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().detachments.push(item_ids);
Box::pin(async { Ok(()) })
}
fn rem_outfit(&self, item_ids: Vec<Guid>, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().removed_outfits.push(item_ids);
Box::pin(async { Ok(()) })
}
fn send_instant_message(
&self,
target: Guid,
message: String,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0
.lock()
.unwrap()
.instant_messages
.push((target, message));
Box::pin(async { Ok(()) })
}
fn send_reply(&self, channel: i32, message: String, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().replies.push((channel, message));
Box::pin(async { Ok(()) })
}
fn set_cam_fov(&self, value: f32, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().camera_fovs.push(value);
Box::pin(async { Ok(()) })
}
fn set_debug(&self, name: String, value: String, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().debug_settings.push((name, value));
Box::pin(async { Ok(()) })
}
fn set_env(&self, name: String, value: String, _: CancellationToken) -> ActionFuture<'_> {
self.0
.lock()
.unwrap()
.environment_settings
.push((name, value));
Box::pin(async { Ok(()) })
}
fn set_group_with_guid_string_cancellation_token(
&self,
id: Guid,
role: Option<String>,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0.lock().unwrap().group_ids.push((id, role));
Box::pin(async { Ok(()) })
}
fn set_group_with_string_string_cancellation_token(
&self,
name: String,
role: Option<String>,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0.lock().unwrap().group_names.push((name, role));
Box::pin(async { Ok(()) })
}
fn set_rot(&self, angle: f32, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().rotations.push(angle);
Box::pin(async { Ok(()) })
}
fn sit(&self, target: Guid, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().sits.push(target);
Box::pin(async { Ok(()) })
}
fn sit_ground(&self, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().sit_ground_count += 1;
Box::pin(async { Ok(()) })
}
fn tp_to(
&self,
x: f32,
y: f32,
z: f32,
region: Option<String>,
look_at: Option<Option<f32>>,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0.lock().unwrap().teleports.push(TeleportCall {
x,
y,
z,
region,
look_at,
});
Box::pin(async { Ok(()) })
}
fn unsit(&self, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().unsit_count += 1;
Box::pin(async { Ok(()) })
}
}
#[derive(Default)]
pub struct QueryState {
pub is_sitting: bool,
pub object_exists: HashMap<Guid, bool>,
pub active_group: Option<String>,
pub camera_settings: Option<[f32; 6]>,
pub debug_settings: BTreeMap<String, String>,
pub environment_settings: BTreeMap<String, String>,
pub inventory_map: Option<InventoryMap>,
pub sit_id: Option<Guid>,
}
#[derive(Clone, Default)]
pub struct RecordingQueries(pub Arc<Mutex<QueryState>>);
type QueryFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, Error>> + Send + 'a>>;
impl IRlvQueryCallbacks for RecordingQueries {
fn is_sitting(&self, _: CancellationToken) -> QueryFuture<'_, bool> {
let value = self.0.lock().unwrap().is_sitting;
Box::pin(async move { Ok(value) })
}
fn object_exists(&self, id: Guid, _: CancellationToken) -> QueryFuture<'_, bool> {
let value = self
.0
.lock()
.unwrap()
.object_exists
.get(&id)
.copied()
.unwrap_or(false);
Box::pin(async move { Ok(value) })
}
fn try_get_active_group_name(&self, _: CancellationToken) -> QueryFuture<'_, (bool, String)> {
let value = self.0.lock().unwrap().active_group.clone();
Box::pin(async move { Ok(value.map_or((false, String::new()), |name| (true, name))) })
}
fn try_get_camera_settings(
&self,
_: CancellationToken,
) -> QueryFuture<'_, (bool, Option<CameraSettings>)> {
let values = self.0.lock().unwrap().camera_settings;
Box::pin(async move {
let Some([av_min, av_max, fov_min, fov_max, zoom_min, current_fov]) = values else {
return Ok((false, None));
};
Ok((
true,
Some(CameraSettings::new(
av_min,
av_max,
fov_min,
fov_max,
zoom_min,
current_fov,
)?),
))
})
}
fn try_get_debug_setting_value(
&self,
name: String,
_: CancellationToken,
) -> QueryFuture<'_, (bool, String)> {
let value = self.0.lock().unwrap().debug_settings.get(&name).cloned();
Box::pin(async move { Ok(value.map_or((false, String::new()), |value| (true, value))) })
}
fn try_get_environment_setting_value(
&self,
name: String,
_: CancellationToken,
) -> QueryFuture<'_, (bool, String)> {
let value = self
.0
.lock()
.unwrap()
.environment_settings
.get(&name)
.cloned();
Box::pin(async move { Ok(value.map_or((false, String::new()), |value| (true, value))) })
}
fn try_get_inventory_map(
&self,
_: CancellationToken,
) -> QueryFuture<'_, (bool, Option<InventoryMap>)> {
let value = self.0.lock().unwrap().inventory_map.take();
Box::pin(async move { Ok((value.is_some(), value)) })
}
fn try_get_sit_id(&self, _: CancellationToken) -> QueryFuture<'_, (bool, Guid)> {
let value = self.0.lock().unwrap().sit_id;
Box::pin(async move { Ok(value.map_or((false, Guid([0; 16])), |id| (true, id))) })
}
}
pub struct RlvHarness {
pub service: RlvService,
pub actions: Arc<Mutex<ActionLog>>,
pub queries: Arc<Mutex<QueryState>>,
}
impl RlvHarness {
/// Builds the same enabled service and two narrow callback fakes as the C# base fixture.
///
/// # Errors
///
/// Returns the standardized constructor error while the public RLV service is a shim.
pub fn new() -> Result<Self, Error> {
let action_callbacks = RecordingActions::default();
let query_callbacks = RecordingQueries::default();
let actions = Arc::clone(&action_callbacks.0);
let queries = Arc::clone(&query_callbacks.0);
let service = RlvService::new(Box::new(query_callbacks), Box::new(action_callbacks), true)?;
Ok(Self {
service,
actions,
queries,
})
}
/// Processes a command using the base fixture sender identity.
///
/// # Errors
///
/// Returns the public RLV service error for the command.
pub async fn process(&self, command: &str) -> Result<bool, Error> {
self.service
.process_message(command.into(), guid(SENDER_ID), SENDER_NAME.into(), None)
.await
}
/// Processes a command using an explicit sender identity.
///
/// # Errors
///
/// Returns the public RLV service error for the command.
pub async fn process_from(
&self,
command: &str,
sender_id: &str,
sender_name: &str,
) -> Result<bool, Error> {
self.service
.process_message(command.into(), guid(sender_id), sender_name.into(), None)
.await
}
}
pub struct SampleInventoryTree {
pub root: RlvSharedFolder,
pub clothing: RlvSharedFolder,
pub hats: RlvSharedFolder,
pub sub_hats: RlvSharedFolder,
pub accessories: RlvSharedFolder,
pub fancy_hat: RlvInventoryItem,
pub party_hat: RlvInventoryItem,
pub business_pants: RlvInventoryItem,
pub retro_pants: RlvInventoryItem,
pub happy_shirt: RlvInventoryItem,
pub glasses: RlvInventoryItem,
pub watch: RlvInventoryItem,
}
impl SampleInventoryTree {
/// Builds the exact `#RLV` hierarchy shared by the upstream fixtures.
///
/// # Errors
///
/// Returns a mapped constructor or collection error.
pub fn build() -> Result<Self, Error> {
let root =
RlvSharedFolder::new(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"), "#RLV".into())?;
let clothing = root.add_child(
guid("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
"Clothing".into(),
)?;
let hats =
clothing.add_child(guid("dddddddd-dddd-4ddd-8ddd-dddddddddddd"), "Hats".into())?;
let sub_hats = hats.add_child(
guid("ffffffff-0000-4000-8000-000000000000"),
"Sub Hats".into(),
)?;
root.add_child(
guid("eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee"),
".private".into(),
)?;
let accessories = root.add_child(
guid("cccccccc-cccc-4ccc-8ccc-cccccccccccc"),
"Accessories".into(),
)?;
let watch = accessories.add_item(
guid("c0000000-cccc-4ccc-8ccc-cccccccccccc"),
"Watch".into(),
false,
None,
None,
None,
None,
)?;
let glasses = accessories.add_item(
guid("c1111111-cccc-4ccc-8ccc-cccccccccccc"),
"Glasses".into(),
false,
None,
None,
None,
None,
)?;
let business_pants = clothing.add_item(
guid("b0000000-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
"Business Pants (Pelvis)".into(),
false,
None,
None,
None,
None,
)?;
let happy_shirt = clothing.add_item(
guid("b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
"Happy Shirt".into(),
false,
None,
None,
None,
None,
)?;
let retro_pants = clothing.add_item(
guid("b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
"Retro Pants".into(),
false,
None,
None,
None,
None,
)?;
let party_hat = hats.add_item(
guid("d0000000-dddd-4ddd-8ddd-dddddddddddd"),
"Party Hat (Spine)".into(),
false,
None,
None,
None,
None,
)?;
let fancy_hat = hats.add_item(
guid("d1111111-dddd-4ddd-8ddd-dddddddddddd"),
"Fancy Hat (chin)".into(),
false,
None,
None,
None,
None,
)?;
Ok(Self {
root,
clothing,
hats,
sub_hats,
accessories,
fancy_hat,
party_hat,
business_pants,
retro_pants,
happy_shirt,
glasses,
watch,
})
}
}

View File

@@ -1,620 +1,3 @@
// @generated by tools/generate_surface.py; do not edit by hand. // @generated by tools/generate_surface.py; do not edit by hand.
// Source: LibreMetaverse 2aa70bb68513b39795da5d13c88f31b86e85a3ba // Source: LibreMetaverse 2aa70bb68513b39795da5d13c88f31b86e85a3ba
// Pending cases are catalog entries, not fake executable Rust tests. // Pending cases are catalog entries, not fake executable Rust tests.
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight::test fb3adb86988b10b2d3fe9223324f8a3c1ba7b8c2ea909ee6b57b38c590fed372
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight_WithDelta::test 1f37a125fd9df8585740d37c711888dfcd92460d86c19077f771d7f3fab54264
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive::case:eee2b1b757fc196e 17a84542635b76f4f806126ab170d43441ad00b9b91650aa1164909de9692671
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive::case:e6bc1820d9335b07 17a84542635b76f4f806126ab170d43441ad00b9b91650aa1164909de9692671
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive::case:fb63a8c8c9b75b99 17a84542635b76f4f806126ab170d43441ad00b9b91650aa1164909de9692671
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_WithHiddenSubfolder::case:eee2b1b757fc196e f2e3209b5a1a655a846e7f19801ed118a6dd303edeab705480aaf03959a383e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_WithHiddenSubfolder::case:e6bc1820d9335b07 f2e3209b5a1a655a846e7f19801ed118a6dd303edeab705480aaf03959a383e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_WithHiddenSubfolder::case:fb63a8c8c9b75b99 f2e3209b5a1a655a846e7f19801ed118a6dd303edeab705480aaf03959a383e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:eee2b1b757fc196e 6164ae5589e5a684637e9c85dd04e5e4c439c541be45b5ae2228e5c5edb2b79d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:e6bc1820d9335b07 6164ae5589e5a684637e9c85dd04e5e4c439c541be45b5ae2228e5c5edb2b79d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:fb63a8c8c9b75b99 6164ae5589e5a684637e9c85dd04e5e4c439c541be45b5ae2228e5c5edb2b79d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_SourceFolderPrivate::case:eee2b1b757fc196e cdab3dc2313a5fec377f6fa0d49ac51b7ef58ede741d8c886f298b47efb508ae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_SourceFolderPrivate::case:e6bc1820d9335b07 cdab3dc2313a5fec377f6fa0d49ac51b7ef58ede741d8c886f298b47efb508ae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_SourceFolderPrivate::case:fb63a8c8c9b75b99 cdab3dc2313a5fec377f6fa0d49ac51b7ef58ede741d8c886f298b47efb508ae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive::case:bc5a9cb6a299a551 be84d92abe19975bbf7a680f077d36956f33873a2b65bfebff8eddf6458b77c9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive::case:0f04a34ae77465d3 be84d92abe19975bbf7a680f077d36956f33873a2b65bfebff8eddf6458b77c9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive::case:1560d5268a46ddf1 be84d92abe19975bbf7a680f077d36956f33873a2b65bfebff8eddf6458b77c9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_ById::case:bc5a9cb6a299a551 dfc11c1f68841153e34d37f98884c041366bd89d754b0f3421a166f09436daa7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_ById::case:0f04a34ae77465d3 dfc11c1f68841153e34d37f98884c041366bd89d754b0f3421a166f09436daa7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_ById::case:1560d5268a46ddf1 dfc11c1f68841153e34d37f98884c041366bd89d754b0f3421a166f09436daa7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_WithHiddenSubfolder::case:bc5a9cb6a299a551 cfdb334a613f22babdc58f2fb96a884ed7e7a2fd339ec396a71f4decc02a3747
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_WithHiddenSubfolder::case:0f04a34ae77465d3 cfdb334a613f22babdc58f2fb96a884ed7e7a2fd339ec396a71f4decc02a3747
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_WithHiddenSubfolder::case:1560d5268a46ddf1 cfdb334a613f22babdc58f2fb96a884ed7e7a2fd339ec396a71f4decc02a3747
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:bc5a9cb6a299a551 780e7212749cb332abbf1a1cef33ed8938584b817476d39424b4628d34c3f4ea
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:0f04a34ae77465d3 780e7212749cb332abbf1a1cef33ed8938584b817476d39424b4628d34c3f4ea
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:1560d5268a46ddf1 780e7212749cb332abbf1a1cef33ed8938584b817476d39424b4628d34c3f4ea
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_AttachPoint::case:bc5a9cb6a299a551 4115d8f4e18acc9992e84f30962536c4cd15db2e4c8c54aa840f5ee397ba8613
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_AttachPoint::case:0f04a34ae77465d3 4115d8f4e18acc9992e84f30962536c4cd15db2e4c8c54aa840f5ee397ba8613
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_AttachPoint::case:1560d5268a46ddf1 4115d8f4e18acc9992e84f30962536c4cd15db2e4c8c54aa840f5ee397ba8613
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_RlvWearableType::case:bc5a9cb6a299a551 91d47986c684dfb289df7f867f847d270324cbc6754a24aaa009b3a96226661d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_RlvWearableType::case:0f04a34ae77465d3 91d47986c684dfb289df7f867f847d270324cbc6754a24aaa009b3a96226661d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_RlvWearableType::case:1560d5268a46ddf1 91d47986c684dfb289df7f867f847d270324cbc6754a24aaa009b3a96226661d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce::case:5e4fd9176ccab2f0 2ecd1c4e8f6238ac0e1274053bcc512d08767c61a0532bbd321d1c8b15c94d6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce::case:1112c98c6420210d 2ecd1c4e8f6238ac0e1274053bcc512d08767c61a0532bbd321d1c8b15c94d6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce::case:0dd9d8fadf48e313 2ecd1c4e8f6238ac0e1274053bcc512d08767c61a0532bbd321d1c8b15c94d6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_WithClothing::case:5e4fd9176ccab2f0 1bbd8cf1f00311fc656ca6c05d60ed033c6a69d59d4ff69d876f50f9d48645a3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_WithClothing::case:1112c98c6420210d 1bbd8cf1f00311fc656ca6c05d60ed033c6a69d59d4ff69d876f50f9d48645a3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_WithClothing::case:0dd9d8fadf48e313 1bbd8cf1f00311fc656ca6c05d60ed033c6a69d59d4ff69d876f50f9d48645a3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AlreadyAttached::case:2a7ad8f0a57b741d 751483b13ff87bf258c3aec671ff6a8c9b34e8126f7e877982065d28ef426385
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AlreadyAttached::case:da775b6e5cf13e70 751483b13ff87bf258c3aec671ff6a8c9b34e8126f7e877982065d28ef426385
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AlreadyAttached::case:e59967ec103647cc 751483b13ff87bf258c3aec671ff6a8c9b34e8126f7e877982065d28ef426385
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_PositionFromFolderName::case:5e4fd9176ccab2f0 6a34c794669e596b982f5050071502e43061053677b44536f60847d4c3798634
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_PositionFromFolderName::case:1112c98c6420210d 6a34c794669e596b982f5050071502e43061053677b44536f60847d4c3798634
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_PositionFromFolderName::case:0dd9d8fadf48e313 6a34c794669e596b982f5050071502e43061053677b44536f60847d4c3798634
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_FolderNameSpecifiesToAddInsteadOfReplace::case:2a7ad8f0a57b741d 5c09150744493c62b8b5c0ec139b6580bb74fe618b1a111b7a1ce583e8fa82e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_FolderNameSpecifiesToAddInsteadOfReplace::case:da775b6e5cf13e70 5c09150744493c62b8b5c0ec139b6580bb74fe618b1a111b7a1ce583e8fa82e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_FolderNameSpecifiesToAddInsteadOfReplace::case:e59967ec103647cc 5c09150744493c62b8b5c0ec139b6580bb74fe618b1a111b7a1ce583e8fa82e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AttachPrivateParentFolder::case:5e4fd9176ccab2f0 268a375256333f2986ac68c5a357042b424f867585ef5a954328f9333b62007c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AttachPrivateParentFolder::case:1112c98c6420210d 268a375256333f2986ac68c5a357042b424f867585ef5a954328f9333b62007c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AttachPrivateParentFolder::case:0dd9d8fadf48e313 268a375256333f2986ac68c5a357042b424f867585ef5a954328f9333b62007c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_Default::case:6882162efd904e15 3bd216683e650e5727244882dd61b16c58192e48438d8a8a831d60782d409fb2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_Default::case:45b5361aae1131d0 3bd216683e650e5727244882dd61b16c58192e48438d8a8a831d60782d409fb2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_Default::case:f66e403049f440cf 3bd216683e650e5727244882dd61b16c58192e48438d8a8a831d60782d409fb2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_ById::case:6882162efd904e15 3f6cc1241679d7746e58925c3c17aabf88a5c8694bbfda0fceb4b054d8b90392
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_ById::case:45b5361aae1131d0 3f6cc1241679d7746e58925c3c17aabf88a5c8694bbfda0fceb4b054d8b90392
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_ById::case:f66e403049f440cf 3f6cc1241679d7746e58925c3c17aabf88a5c8694bbfda0fceb4b054d8b90392
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesToAddInsteadOfReplace::case:a2681d046a6f6fef 67d84750193300b9445aa33d47d78f8fc5161b9456b7755d305568c695737a4b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesToAddInsteadOfReplace::case:34172d9d6ebbcf53 67d84750193300b9445aa33d47d78f8fc5161b9456b7755d305568c695737a4b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesToAddInsteadOfReplace::case:30379630ffa50e68 67d84750193300b9445aa33d47d78f8fc5161b9456b7755d305568c695737a4b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesRlvAttachmentPoint::case:6882162efd904e15 c45b9e08563acaf523fc8bddf5953e970bc773749d6f52b59f0806f104c24d27
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesRlvAttachmentPoint::case:45b5361aae1131d0 c45b9e08563acaf523fc8bddf5953e970bc773749d6f52b59f0806f104c24d27
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesRlvAttachmentPoint::case:f66e403049f440cf c45b9e08563acaf523fc8bddf5953e970bc773749d6f52b59f0806f104c24d27
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FromHiddenSubfolder::case:6882162efd904e15 059d647777a2d65d5a14f77aa6914449d1a9c0cbc876d3acccfa3a0de30988e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FromHiddenSubfolder::case:45b5361aae1131d0 059d647777a2d65d5a14f77aa6914449d1a9c0cbc876d3acccfa3a0de30988e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FromHiddenSubfolder::case:f66e403049f440cf 059d647777a2d65d5a14f77aa6914449d1a9c0cbc876d3acccfa3a0de30988e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_AttachPoint::case:6882162efd904e15 9e004ad47add2d97565c14c2d70bff08d1bea46d997140ad17ca5ffe04ee41a9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_AttachPoint::case:45b5361aae1131d0 9e004ad47add2d97565c14c2d70bff08d1bea46d997140ad17ca5ffe04ee41a9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_AttachPoint::case:f66e403049f440cf 9e004ad47add2d97565c14c2d70bff08d1bea46d997140ad17ca5ffe04ee41a9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_RlvWearableType::case:6882162efd904e15 1c0adf85cffdece3b2576998e7c73921e8b842daf2e14ef1319e71c1f64797b3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_RlvWearableType::case:45b5361aae1131d0 1c0adf85cffdece3b2576998e7c73921e8b842daf2e14ef1319e71c1f64797b3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_RlvWearableType::case:f66e403049f440cf 1c0adf85cffdece3b2576998e7c73921e8b842daf2e14ef1319e71c1f64797b3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear::test 865d022233930e9582fec5b0e99063f15506a339c430755aba83706b594182ad
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_CaseInSensitive::test b70296f9d2b6c9eb8c6dd6e560056ab8320d746a991fafec858812fc2ebb3141
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_SenderBased::test 1ae70737411e18626227c0b15181572c1c623eefce0a8fa1a874b2229c44c38e
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_Filtered::test e0f0b5a42c3baf92fef6a8d4fc2c60dbd6963db6f844fed55b06968f0c9e543f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive::test 45405dbca6c2b8bb9f439736d53c2ff60056252f4cdf6296bedcc14d2be9248e
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_EnforceRestrictions::test 6186f5923009fb984daef726e8df44aff7cb65f74c2e381dd8cc9968f5534e43
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_PrivateTargetDir::test 300a323967b6258d1202190bbd3de7b91699231f7a5afa86204ba627cb61215f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_PrivateSubFolders::test e688b64d13f0a07f4bfeae0715fbfbf98c1d1fa64b0aefbd0e4e3d3d4dd98eee
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripSubFolders::test 22cf1a159861c98c8a0f14ac63bafcbef21466c2ac01e615fe9ca4630d16f956
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripSubFolders_LinkException::test cbe38368a6d4c59d72291195688d0c70898be5c3cceb02f09c5d386c3668fb07
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripItemName::test ea0fab47cb1829338948f605919fcf1dca4f88d7965cdca4c7f457e399e4fbfc
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Default::test 8fe4eacf8cc5841e638d69540e2ab080efc3e64534346ece854429d0476f8a84
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Nostrip::test 754bd01f2f0b77c05ee5d1548f76337da93d980a48ad0922d80f34707c4fe68b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Nostrip_LinkException::test 0cce15f7cfda160733c305b0867be31875e1814b38e2e980525d960e0214ad51
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById::test 2f657ffed317d4d7f97f6111942ea8214996872da6294f7c66d07890647f7f63
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById_Nostrip::test 48ab7aec02efd652478ca3110dd39011fd9b79a1e0a1336f53e9f77b2f56e635
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById_Nostrip_LinkException::test 5d882f00bfe73cecfc3e96c26ff18a20c00481619996b25ed2ce851eff9a86ce
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint::test 30e6806d5c484bf2a2f9a3b1fcdb5e88272874b0e755462c3b0bfa97326d180c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint_NoStrip::test 657125be7aec668f72e744cc87cae38f022c8ccf9e8980c8ef4bea7e0557fdd1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint_NoStrip_LinkException::test fe019191a9a3df9a43fd500db775ba5f874f4b767096365cba390480b2b2189f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType::test ccf302d870f323790af63873fcbb172f084c4e7400a728e480378706b5fb9947
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_NoStrip::test 1947e7c9cfe8bb931ee7ad50c6f505515feeb9d30b236702a2d68fb4734a30f0
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_NoStrip_LinkException::test 50ec101ab557e78d947ac7f9878acd4df4957482f358a7ce02371df8754add94
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_PrivateFolder::test 2ba745b093f0348d8754f74073c6a6a0f18383b5ce4a73721b39b01f0306a994
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce::test fde065233689ec75c12e9607acf06c5859a91efea58e143ecc508ebec784a567
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_WithNoStripItemName_SpecialException::test ee511230131312be9b788033aac8766ea3cb3c1f8d7c5b9b26a4bd6a83cd695c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_WithLockedFolderRestriction::test 05fefae0563306af0c491006f18915ff1b250b7972c82c160f20f06e07335887
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_MultipleLinksSameItem::test 1ae8a318762625819371fb109fd673e0d31a2c0354add1e65802eb54cb71e303
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_Default::test ae8c0fd737f869ef3e2dbd97ae28974b35c6bbc5327151c0074d531efdaaf54e
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStrip::test 3aa17222f7539814f8329e07de548cca4bb702f4b0409e793ea551327b0c57d0
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStripFolder::test 16b74c3bf8312ccb885e61f933ec9d292988d2e1fad05e0188006df5630681f8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStripFolder_LinkException::test b86b22a0ab30d0ded0cd6fbc7d34fae77e521861f5672b44a25a77325e594ab4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById::test 3c4a211e5fefb44b42f50f6e6e58f8f852c8cf2d732bb6c3f737c3d6a592fa22
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripItemName::test f32926ca6f4328afdd3ddeb9f7bec8ff2ee01e9563555921ac8c663d20005551
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripFolderName::test bec3216bf016c2543a3410b069abd786167e04a7527253887f158127644656a8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripFolderName_LinkException::test 1b5eb3a0bdef8ea65b800533ab3153dc6b3ea21d2f4f27e4820d0a0df48891a2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint::test 7e8f3a4d8b2cbdb5cc81eea598da6ef6395834b1cb7a629dc8d7ee2bfd80fab5
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint_NoStrip::test f6ff482bdb8d28414e01952201e37e49316b3e2345b0ff85dd4cb059193d1816
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint_NoStrip_LinkException::test 289f8cc48f0e6a412d58258876e4aca08d8116d549642a0011bbdaf9b2223e83
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType::test 51607294f12279974c2b44b47ba2eadca9846180a39bcde6a28c020dc4466254
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_NoStrip::test 30dec183993b2a644c2812ffc1c863e1714df134942f7827df818d9200e47c38
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_NoStrip_LinkException::test 62f59cf66f21dcac15cf3166dcec2183181c0b434e9eacba796eb7025c4f1ab3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_PrivateFolder::test dd40588598bd081189e7c4f284af3851a140155e2ede0ae2121dd59a156dc988
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach::case:bb1d34dc76ade75f 16420d56c60229e8d8b6a2a0d63b1f500112c23cef451d69bb0ed97fe9b63bae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach::case:c9faa5be8fef55e8 16420d56c60229e8d8b6a2a0d63b1f500112c23cef451d69bb0ed97fe9b63bae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip::case:bb1d34dc76ade75f 5b3f1cbe99833e16c6f10ef568618627445babbcdfc9be555b48257bfdffeea7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip::case:c9faa5be8fef55e8 5b3f1cbe99833e16c6f10ef568618627445babbcdfc9be555b48257bfdffeea7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip_LinkException::case:bb1d34dc76ade75f 96a4b53d9e55dcd656c25af6619a3d0d67f5bc2517a759d722559a4ffb225472
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip_LinkException::case:c9faa5be8fef55e8 96a4b53d9e55dcd656c25af6619a3d0d67f5bc2517a759d722559a4ffb225472
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ExternalItems::case:bb1d34dc76ade75f 7545f36532fcb7974a9e009e567b2342754a11da95eb3f17ee04089dcec42664
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ExternalItems::case:c9faa5be8fef55e8 7545f36532fcb7974a9e009e567b2342754a11da95eb3f17ee04089dcec42664
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder::case:97eb7af1f9c3c62c 583d3f596c80411d950038e3ec64032bee75150b8c819741fe89a4ca40eb2553
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder::case:1a04fd408fddaac0 583d3f596c80411d950038e3ec64032bee75150b8c819741fe89a4ca40eb2553
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip::case:2117c838922f5ba4 3a21b8ae807126d6f93ac95e16c47330b4146ace9781e9c9665ad493ee8c48b1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip::case:11d4ca4fd3e35db1 3a21b8ae807126d6f93ac95e16c47330b4146ace9781e9c9665ad493ee8c48b1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip_LinkException::case:2117c838922f5ba4 7c00e7dc70b3078d75009cf78a9fece889eee85f237c1a3c79c6249ae5e5327f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip_LinkException::case:11d4ca4fd3e35db1 7c00e7dc70b3078d75009cf78a9fece889eee85f237c1a3c79c6249ae5e5327f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint::case:644d3f75f3570ac3 e09627228c1cf8311e56ac6660389bc1b268db8fd4f883dc40aaf3d2ec00916b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint::case:53be219b37533fa6 e09627228c1cf8311e56ac6660389bc1b268db8fd4f883dc40aaf3d2ec00916b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip::case:644d3f75f3570ac3 ffaaad92700d5d606154abdddd05c24c7584c5c3e55290df61e2b2a71d8148d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip::case:53be219b37533fa6 ffaaad92700d5d606154abdddd05c24c7584c5c3e55290df61e2b2a71d8148d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip_LinkException::case:644d3f75f3570ac3 af1b1caf070a186bc2b02b598919b52d47c289d708fde3713e48ce1a40d7c025
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip_LinkException::case:53be219b37533fa6 af1b1caf070a186bc2b02b598919b52d47c289d708fde3713e48ce1a40d7c025
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_None::case:9a124e69f33b279f afed603254ad6048a46e157254f16253063e6c76c9ea16f46a69d8455bc0e6fb
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_None::case:800d7d8ba57071b1 afed603254ad6048a46e157254f16253063e6c76c9ea16f46a69d8455bc0e6fb
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID::case:e5bdbdba9613b46a 4b1a8acea7f1bb100bf11e9329672c64b53aba4974558f1c693460eef7f56c2d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID::case:7cb3f81460bd8e9f 4b1a8acea7f1bb100bf11e9329672c64b53aba4974558f1c693460eef7f56c2d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInItemName::case:e5bdbdba9613b46a 6857733912b45ef9153b0f58cd74ae6c9dc0034fa10933d153cae88a2c7d9423
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInItemName::case:7cb3f81460bd8e9f 6857733912b45ef9153b0f58cd74ae6c9dc0034fa10933d153cae88a2c7d9423
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName::case:e5bdbdba9613b46a 1a3189f931e086ab3d2d3e99c53dba2e9d39dce75a52fd02400c6892aef5d0c4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName::case:7cb3f81460bd8e9f 1a3189f931e086ab3d2d3e99c53dba2e9d39dce75a52fd02400c6892aef5d0c4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName_LinkException::case:e5bdbdba9613b46a bd7bc72a107b4a21b00977e13b086da192bef2c2e6f0fdb73b8e332016c6ef23
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName_LinkException::case:7cb3f81460bd8e9f bd7bc72a107b4a21b00977e13b086da192bef2c2e6f0fdb73b8e332016c6ef23
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_WithRestrictions::case:e5bdbdba9613b46a 2ecf40d1d338117ddac4cfd6c7a030e96b7adf72cd90e0d8327787317e1f38d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_WithRestrictions::case:7cb3f81460bd8e9f 2ecf40d1d338117ddac4cfd6c7a030e96b7adf72cd90e0d8327787317e1f38d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_External::case:e5bdbdba9613b46a e0bdc682df3416bdc01855e6e63974e64c21951aac629807352220baf572dded
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_External::case:7cb3f81460bd8e9f e0bdc682df3416bdc01855e6e63974e64c21951aac629807352220baf572dded
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit::test 60bd0e62bbd4613c4d2d1a65705644dc25fd7327408adfc0bb7e95c45d79cdcb
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_PrivateFolders::test d79ac3806f50915390edd0a24b756ef398c1334017f69d16f4cb887dcdd41fb1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems::test 0265a9fee1070cbcc458bfcb05fe267991cbdb5480500c1b32aace1eb4935217
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_NoStrip::test b93d39d919fb70b02ccdb724969f7b983c726c707bca96e1b1ddc6ee248a734f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_NoStrip_LinkException::test 5ecc44228573645e0a0c78d100dab54b793c6ce8dc50a02d79a919fe6d7c1678
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_ByType::test 8ba106f071f8768af1d6213c04f67dd0aec846ae47552686eba86c489bdb0292
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder::test 45f9e7a9d0ef99ec7d58b59f1c1db7b6065994939717842bb02486b470b357b5
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_PrivateFolder::test 68f3050a1b667304ff2b252690cc7d1994964dbd2c7633d54e5c6654714c0aed
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStrip::test d56b83a72d6d3529af0390674550ce40733c14de6210cf71e277f0e195d1e330
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStripFolderName::test a28f5517a9d05085627d5acaf33441d598912301962f6e99aaff49ef5114af53
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStripFolderName_LinkException::test 80efc201f976365e68d32ae1b30db0f10a17cbc65aedc82895ffa679700008da
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific::test 7235143679739442ec942d294a8a68f69b7fb5678ed4e3ca03be35c74e9c71a9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_PrivateFolder::test 3feea26f000dc7eb86b1413f1a5bdd5f109c5f9f969918cd1ce2e7f926f26c12
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_NoStrip::test 6e4b8bc53933a889df1cf553ca7e0601e5061bb87013a4075c2ff357cc9d987f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_NoStrip_LinkException::test 72b1409f70531d859f15a012cb1fb03d795d2065c5d03b7a263d352ca4b80e98
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_BodyPart_Specific::test 13804c96395db86821371dc8f2cacd2cb182338f8ea88034afcc5da19e3f0691
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:fa77559e30768d15 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:55694f25ed879d95 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Invalid::test 2e0595319ba8e2c9a8280c5b034363ad7998eb740cb6b7fff3d75bb0167c6464
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:f656b648d00a6d91 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:55694f25ed879d95 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByName::test fae27e58cd981f5471f4c2b8356bb07aa5e76a57aaf0882d0dbfb86360e077e3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByNameAndRole::test 408442b86bb8259eb9bbb4cf8a5d3b0830c7ba9357fa04cb6e851511a7a24df1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ById::test 27f13c52c8c5e2e4298fee3f4322f9906d5f82e900aa5f46c9a8ffac3a6dfae7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByIdAndRole::test e18fd0c318ebd4f9a189418449568b3a34b8f7d3a0097f100a7253c4d5a31bde
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetRotCommandTests.cs::SetRotCommandTests.SetRot::test c3302d63cdda9d72b85dad2749e2684cc26d51c72ddc6ace8275911f8ba67ef4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_Default::test 24e45ba898cb8ed0919369d07a39d0b21982fa4fc4c41eb4835ba765c05e2469
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileStanding::test 8d179277f6a7f98ead813de7bd02ab5146b46ce240d1d5e4a69037885e5f626a
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileSeated::test 1f2debd6e644c86698577e1c04db96d6aac43267ceae8de9f28435b62ff92817
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedSit::test 8ac0964fc07bb5e860123ce8de1102c2254ffde28f246896d81f7524c3c87021
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedStandTp::test bc0c259477ef5f1e5a76b1081f604ba421c82340f738e37fd52b91a421037cf6
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_InvalidObject::test 787bfe6fefe3895b4bcb5da027ffeac70bf67c3c7a295dbbf7e1526156290040
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround::test 2319cd49aaae5ac824bc5ffd4f33a5e4f3f684ebec1dc1f1732071eb44ee1cb8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround_RestrictedSit::test 5ac661e9f7fa93cf6ca76aa69f6d84ac61ebd22f26620203f084777010b6de4d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_Default::test 1613e723da60f84dfb54a7345b96566a055a9b7a017e66b0929d6f37c04b62a3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegion::test 50c5f63c5cb0da221846fd7c0c7f2d471bef2aa2ab203a9b5bdb4eceeb3d97bf
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegionAndLookAt::test c9030189de7acdad0db5c8f83e49ee0433ec0588a35436ab39cdcf40a4fd4d36
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedUnsit::test 4dc00a1048593f7468271a4262cf311a3516ea4a53e288eeca69d1297dafc9f2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedTpLoc::test 3e1ecc1d04973a496edf9d156e52ba76a93ff431181a3ece93c0e4f82884895a
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit::test 2f91e1112e1c4e97b79a4dc7bcd4d4a85f13125bd636f81147ce5b396366ebed
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit_RestrictedUnsit::test 2ecf210dc83b06018cdcf44cb44bdf43f1040133e7523542a2e1126d6d98004f
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptPermissionExceptionTests.cs::AcceptPermissionExceptionTests.AcceptPermission::test a5ffc51718e89fb872c6df8b8667f6d231618d47a2ffc71d596e8e10e15cb02e
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpExceptionTests.cs::AcceptTpExceptionTests.CanAutoAcceptTp_User::test e988496e81a717eae1a96c5501e748a441fa64f637aaa47a6ae7a8d571c30f6e
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpExceptionTests.cs::AcceptTpExceptionTests.CanAutoAcceptTp_All::test 428ec184c9d09f6ec57ac3429180f327ed1b79e9d9dea9815df3bb6f0f6244fd
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpRequestExceptionTests.cs::AcceptTpRequestExceptionTests.CanAutoAcceptTpRequest_User::test 3a5af1a55e74b5e75a04abc11826ded17c327ac2ed99ab2a423674fbb0e61f31
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpRequestExceptionTests.cs::AcceptTpRequestExceptionTests.CanAutoAcceptTpRequest_All::test 8e2cf7c4d17dcec4d7855fc430092699416108966fb5d97c170c13f0bcd04cfe
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll::test 1daa414beb2a767518f335f6ae59e711395375ed9d7912fbbc139fa0998dfdb1
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll_Recursive::test 6e0c78d6ed78bedca9a8c6a9a83fd9f90f7123da433eb4c560e6f5c0b6fe6d94
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll_Recursive_AddRem::test 9423ed205501604501d31909414ecf6ef99a0d56d4efae100f5576b31b71a858
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachThisExceptExceptionTests.cs::AttachThisExceptExceptionTests.AttachThisExcept_Default::test b8e6e55d8f2654429c9826e38ffc8522eec44ab2521891b68616db61ac662db0
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachThisExceptExceptionTests.cs::AttachThisExceptExceptionTests.AttachThisExcept_AddRem::test 05bc7eab5dd02a0a3e60f85eb51b374623aaa29c9ce2b522748a3478b8ee44ea
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DenyPermissionExceptionTests.cs::DenyPermissionExceptionTests.DenyPermission::test c2284b63e7b4a93f8613a3afe34466d14e1c6ed8528656d54ae64ca6d081cdd5
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll::test 75e7ab22f6d9d058580fd83741d65f7e5babb7ad54805eaeb16bec8cd65370ed
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll_Recursive::test 3fb8bb13d6a917d9be18265d90767488cde66746badc6584025bbbaf84f020ad
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll_Recursive_AddRem::test fb5fd8a4eda181d22d1756ec0cae700c4b90895a74dc79c24c67c1705cfd37c8
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachThisExceptExceptionTests.cs::DetachThisExceptExceptionTests.DetachAllThis_Recursive_Except::test 3222d97d73d8b54bd11212f8cd3de26279040321f0bc330e061ff93880053f3e
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachThisExceptExceptionTests.cs::DetachThisExceptExceptionTests.DetachAllThis_Recursive_Except_AddRem::test d25b2c533b9b51428c0c2414d687c466a3c80c4a573dd36763504de19e8dc6f8
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/EditExceptionTests.cs::EditExceptionTests.CanEdit_Exception::test e435b03faef04dfe06d0cbec76e94cbf30e61ad7bc08502728f9239cf47292f8
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/EditExceptionTests.cs::EditExceptionTests.CanEdit_Specific::test db097167497bc650c6729f0687924adedda7097b4089107fc5ea03716c1cb4e5
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/EmoteExceptionTests.cs::EmoteExceptionTests.CanEmote::test a643401539d7258ae04ddebaf9c82876f59c4433b11ee61bfe8b416058c9fe38
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvChatExceptionTests.cs::RecvChatExceptionTests.CanRecvChat_Except::test b34881785cf2df3d8f4e5ba971adcf2144d8de4db00acfbe136c79457742ec33
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvEmoteExceptionTests.cs::RecvEmoteExceptionTests.CanRecvChat_RecvEmote_Except::test d4647d71c02e05405ae2acf7b58522aae559b1c90a4f7a1521c9a9a383220f8a
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception::test 2e1afba517b29e8e7f2e0605340eb6e87443282857400eba259f0ebdf4874e23
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception_SingleGroup::test 9ec57daeed225caf960d00f0c83378d1836e86b1896063703ee1c3a38c7b582a
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception_AllGroups::test 633b8c680b583a6f8d80335c26f4ebcec77f9d8d5231e49bea562dcb66f00267
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat::test 1eb25c5579789db22ee242c4b52c65989bd26dce6d7577021c329c6c49be9414
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_Removed::test 62e03ff1db1e790d8bc1e38ac1495fc12723ba2eb5c9d6035d73c9fdb91a44ad
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_MultipleChannels::test c7d0c428d121ab80eee9b6b5855cbe50e7a4cd74e81c369da09df04d55c7554f
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChat::test c4a083e495a578c1ed0855c43680d5b05144bf627f06df48c82e089e6f0699bf
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChatMultiple::test 5ff8665440d8d02e0aa900121e591034d51e2b48ca62fdec2fbc9135f8c83428
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChatEmote::test 5d88009e3e8d365c52315a9b189f6cffdc9d04fdb70aa26bcc03d6bc16227189
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote::test 02170a2b3eb0cbb88921517c9742d2fc0baaea7a621e5a3c3264a7a17d5efb61
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_Removed::test 6ee89cedfd1e2d79d2447f2f48d1e2d1ac96295485b7509fe09f98e3bfcd9766
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_MultipleChannels::test 1a95f4cc5db96cf033fed0c1a4e573b1cb1ac17ef72b76e0ce115c051f10528a
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmote::test 525297be5b5ff466fc9a61f2bc87af38bd637cbef8e0c794e897e021d0cca464
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmoteMultiple::test fd6af49a90e111ed6424c85565242e1205e13604b529909f7be0260e93f0b1c6
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmoteChat::test e8b78a6a34e3d3acdfc6d454b46a939d341260362ae5327dc4b70164d41431aa
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendChannelExceptExceptionTests.cs::SendChannelExceptExceptionTests.CanSendChannelExcept::test 08c309d08681fe067f67315a72014d0a05c87d6e14632fa04f6f2fb617d61be3
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendChannelExceptionTests.cs::SendChannelExceptionTests.CanSendChannel_Exception::test 49bcacb6fb31d596ce9afc73099f8aaf645156ee222262174e1d7fed08393cf9
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception::test 8124011921e8d4caf6840e960bd9f98d21df9db476e1726e0d54550cb8527ceb
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception_SingleGroup::test b55a4bdba1d33652f3809c3478047afc65757fbe1dec6c5292e17b71a04b206c
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception_AllGroups::test 4190ff51848f63dce5682317db79da23fa19ad9e53004534382f3eb6e8544788
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShareExceptionTests.cs::ShareExceptionTests.CanShare_Except::test 37297059a814bfde94c466e263a429258cce11ae258afd7953d26f65f9178f1d
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShowNameTagsExceptionTests.cs::ShowNameTagsExceptionTests.CanShowNameTags_Except::test 5d1fe4ec1fa289623d473ffae1682ed725735cbdf48bdf5b7fed086237e32a1a
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShowNamesExceptionTests.cs::ShowNamesExceptionTests.CanShowNames_Except::test b11578e758631037440dd56a683a3ffc25b576eaa25e7388c950d8d647eb2a75
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/StartImExceptionTests.cs::StartImExceptionTests.CanStartIM_Exception::test e0001ffc665f0f39833cf2376ea1fcb7559bdb87a48ea60bb348e14b078880e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchMeExceptionTests.cs::TouchMeExceptionTests.TouchMe_default::test a0f3ffd3c70263738c074e258d9271e0a825f163c40d9c7ee8d20865873eb304
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchThisExceptionTests.cs::TouchThisExceptionTests.TouchThis_default::test e7e6c9e14badb0159f81adc96e17fcf3ebe2cf5351ec6465f03c430de06d85d2
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchWorldExceptionTests.cs::TouchWorldExceptionTests.TouchWorld_Exception::test ffef2f112b5718bab7b01fc1b624e588c181dadc5c50fd85de4404a501ee6f37
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/TpLureExceptionTests.cs::TpLureExceptionTests.CanTpLure_Except::test a32f4cdda5b48ffcaced683b2e77fc129c1c321951aa2e16623eea022f2aa0b9
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_Normal::test 97787ac6b51198e317ed391e91125724ce1b580924c40500f81186812b45f625
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_EmptyPath::test 0ffd4f32e285ba94e94f63ac312d3be20bf144b769e8d18af32e15f481042ed7
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameContainsForwardSlash::test 90ae520739ea1a2612f491bb110b0870ed4dcb8a983aad9526ed25d8c5cbe687
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameContainsForwardSlashes::test 8c0ed3c6cc16b916f9df8d25d55618e82299fd1bcd66983f682219c338853028
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashPrefix::test 8a86081d6b25ae50b3cf8cdcb1c58c8539264931ab74f395dfc7345ee7f4f861
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashSuffix::test 04afafa569b7a10d6add8c1e9d8f26ac502791f1da2dbdb3e37407e945c87872
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashAffix::test 7eaec38fa6b545f133748b502169fab575308c9c4e60548cfbfd704452bd9761
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_ContendingFoldersWithSlashes::test 96a8189266746a564072122342f36b3321998f3e0cbe0094f3e4c83d29bc53d5
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_InvalidPath::test 547def910ded67bc7950b211ad929f775d4eff26e351d11612f146b3e863510e
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_IgnoreFolderPrefix::test 5039b79496d215d3921427ab6f65867ba7a4ea5239864f1f5a1e38ea3e5bb426
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FailOnHiddenFolder::test bb0c7e531584128d251b06a4ac23b8cfad16ec4b117be79a53dea3c54aed4510
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_AllowHiddenFolder::test 9217cb5bd9c325fc792303e5ab53cefd71e95a5acf9e5a1601957ba8bf807346
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ById::test fc89036c3472dcc2ea4d3fcb55636238e3d2c75b490f46d328b5f91f28301ed0
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByAttachmentType::test 90b36c29312b87c824c158987e551ca31522cf53a68f5f6bd3eae8fe03e914ed
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByAttachmentType_SingleResult::test a973bf8087abb0c68cd80d76949fac2735474bf6ccbe743933051f60527d93ce
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByWearType::test d6712cbeacd6ddf25a1f76dc1eeb10f4c0d8967a7591c249127f9b6387f0df8a
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CamZoomMin_Default::test 662b332d66c72caecc1a179730bc2524b9da16aa85f7289bebd31842610ceccc
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextWorld_Default::test 380d1e30bd9ded04329bfd6d65ba447a8dd45a934cfa875628253719bb0e69ce
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextHud_Default::test a0af1f72f417cfa451284b7a3dbbb26d378e7eb9896dde3b6df0d0a2e4773f38
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverText_Default::test c4122dbf650f51bde55dfda412a884347a78d3cd09dd2bb0fcbe4a7e74a1fff6
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextAll_Default::test 0ed67c5566d038f770eb9f5df6aa0b5394d7d94cf7c397fa8089b419f872c681
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowNameTags_Default::test 0781be94eb099d9aed1be2ff313856770d1ec24047d04c81c69219c743b4c8cb
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShare_Default::test e827d549d1d9329b63db159446937735ead13eed5d3eaa59440d3c686182f517
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowNames_Default::test 56492cdd0802c5f8ed2a0f6d56abaf8186e37dd7b888904db52be97f9137279a
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanEdit_Default::test 417fb9f3eb3e70f3bd33710d11fb25eacd0db0a365b0ed2dec6778d09968f44b
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanRecvChat_Default::test b1ec48da83249b1141c3af926cd494373c47214d6a145916a8833d49edd155e2
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanAutoAcceptTpRequest_Default::test abbcccb4415afdb6558f40a6d4030704f64442f019d065fef8a7a56a407e8642
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanTpRequest_Default::test aefc51023a5274d402dae0e8111a0776622dc431754c3d1f0ce240a50dfd405d
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanAutoAcceptTp_Default::test 553245a5381689a7f1c6398cb0ca50510f9089b9bdc797672ae35fb5822fdf8e
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanChat_Default::test a9b0e4f8713991ce8b9b61d750c086d56da432dbddd533ec63dc0604238831a1
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanSendIM_Default::test 6cc5238ded59b80408c59c9e77ded1162e370c295b846903dbcc87f74175cd55
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanStartIM_Default::test c6d6db79b0939b33eb5fd29490474575e062f796160f4a69aab34ccefc1842cb
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanReceiveIM_Default::test 23c1c79ae9eba016a48f3e9097fc26283223c9e120308d93fe53ce591ee5691c
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_MultipleTerms::test a1f04e5ab064772c25feefc21ea57d65b1044f0fa3254aeb2a3bfedf68d8e0ca
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_SearchOrder::test 4cba32dd316f49713c18a71bf5a932e1c28c94944add38c25852e8611ef0f987
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_IgnorePrivate::test 54c5ec1f6a6ae5611221e3afdc47db0c2d0ecb0da460dd8f2c506ed34c221ff8
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_IgnoreTildePrefix::test 9f6635f5e14dbc14d1592a19b62d67748a60201128a75893e47ea1751c83b6d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFoldersQueryTests.cs::FindFoldersQueryTests.FindFolders::test 09dbc17be4b28cc4a63d0f837960586ba7cd03e184f0013b26ed27db15703d84
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFoldersQueryTests.cs::FindFoldersQueryTests.FindFolders_Separator::test 51caa783dded41b99c878066618a10a7fe32c681ef4385c9a72f154870312b1f
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingNothing::test 41fc967c6c174ac39ce3f6de7e273e6db1845bc2ad6acd393f27a6705a3555df
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_ExternalItems::test 3f8e640aad5deeaf00b07af2d12c33b0a93257260d057d7b5dd5488f846f467a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingSomeItems::test c209cd826958306f1350a685b29985cb8335a55ebcb9c0bec5c5a21279bb0a1a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingEverything::test 4adb25030cd3c125242a4b1f770bfd3afdcabd85c23d37c34df9c8f273489e5b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_Specific_Exists::test 7d8ccf26629911b6b20dc26c5c549975827d7378b4d85259a8b9724a3622892b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_Specific_NotExists::test 08d9852205987a266608ad17c12fa498894d7c3216e873cffb9db4584cfd100d
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:8e1b820c1f2bd3cd 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:64136cd82156035a 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:2068bf7f0a131fe8 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:b86b0c5e67f981c2 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:123b930bb970a1f1 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:f14641dea0f1de93 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:d25c660357f6ccff 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:fa77559e30768d15 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:55694f25ed879d95 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:f656b648d00a6d91 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:55694f25ed879d95 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_Default::test da65b184d0ef1380274e8e4dfa199c125a1a192b9e76f8fec1d406df18186169
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_NoGroup::test d1da37ae52bd94dac9cd6e031525b57f31ca7e9dc00a69a6e0c4e753741dc9e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv::test 7476602b4103b47ed7dff44146a7ba90a1d62dc0d502f7b9e37b7863d9441ceb
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits::test d60a78bb35cc8fcdbdc2465889333b25567ea5e1c9279a8fb7b4162f4a35eae2
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreLeadingSlash::test add33ed33e1940f26362332b89486253c6af1a56e601bafab49511b6607ed50a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreTrailingSlash::test 8f89302126be19f89d075d87d5194cc000fb7819f92ea7d54e6a63c1df9ca1ee
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreLeadingAndTrailingSlash::test c660447f93fb8508dbe4c874c92fd776a6e13596bbe3036bfb4664e35ee22306
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_Inventory::test 7db6f75e2f109d0e8d852d181ddd721f688e27144ad8a5604384b37de9f8c3eb
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Subfolder::test 6a5effe8012e9a446021b83f9b5314f6f9b66587222b447fa79028582830b3a1
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Empty::test 2dd9f242eb71826066482ff4faa80b952ef89f855723cdc0c01cc4714abf8751
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Invalid::test 92595df155e79568e70bceb1538c23f10de99a6a138a0a5d9b8a2626588fdae9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn::test 472d70fb14f393d43f8698bb81d1855426f570d85c9e592fa86607eb79ce366e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_PartialRoot::test ce4c640a901a6684a27b2b259c4fc3b25f2d6b870107babff3b930ced64a150b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_Naked::test fa8994189c5d9cda7d613dfb8f6ffbb1808c8bae54a3647530fb872d47c43dd5
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_EmptyFolder::test ab6fc753f4d4170e17f49b708d7e62816f197e83234feda1fdcf63dcdc0bc6c4
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_PartialWorn::test ceb446f2aa6eaa5232a99147d5d993386ee9e2e5fefd93ef582f27a6b8ece948
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingNothing::test 27befef9fdef993d82a641980f2b1ad7f458f07a50c7d008b6d311aeedfb4939
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_ExternalItems::test f88d149572ae35e880f16a5a92b4a9db73a3f26c5e8e61e4b1c01440151bd64b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingSomeItems::test 4e9ef77ab72f1fd16c4fad69f00eb80ab46421597d41b61df80b1f87370f42d3
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingEverything::test a840b239174cdb5dee4beb875bf9129209af3ba310564319528ad5b19764aae0
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_Specific_Exists::test a402fd67ed8ddfc12d09863f08f9b15b34262ffa12b4b5aa965826eac89abae5
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_Specific_NotExists::test d7e891a620b5e5407fe337f507874b63eb5a21589767a01362bd8bc43d19ba4a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_BySender::test e7e87c01e83967a7160509d76f49d2a4b18d34b9b3fbed370c174d64ddb2c2b5
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByUUID::test 3a7d242966286258ed075c8e5c69eaf54ba0e71b8607432615a1199f5aeb6dcf
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByUUID_Unknown::test c3c206661594026c36dfcfea110631548cd362d824db268c170e4d04b24b674a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByAttach::test f8858e6141b660cec8a09c016891f2275dd9364157b1aa614b63fca5abb7620c
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByWorn::test eed31d9aaf34578368cc4f590de1da7f47e3f6c5e663215866f7f8e6946f974b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID::test bfbf6d62c09c4878504aa529805a29fe9689d1e29e7ca3d44bf2346d6b3fbe6b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID_Default::test 456f8f22b1d2917c3729ed600bdf0b693c0189bd100b9863f4b42b07259110b0
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusAllQueryTests.cs::GetStatusAllQueryTests.GetStatusAll::test ee8fac8485db2b5c01abf8664364ca1e13214243f1e661a04d93df680422d596
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus::test c538e68277e93b40374dfd86bde9be00e0b82dfad7f4573cc4b0660f15fa5fe4
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_filtered::test 574b7f7c37b4e09e4257e5b02d50b222054216e34b6d1dd3fe6b26127c89b562
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_customSeparator::test 3bec2e53ea88857d4a1ae8cd6bc6f235f24e00d0773c24ca75a1892adb803527
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.Notify::test 082ff4cd00faf29a73aca158d4e24ed9fd3e7844ed6cefbf962d8727846a3c27
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyFiltered::test e00e51aeadd0d7a107105684129a6ae74fbf918be4c563d92d7cdaa223d2c03c
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiCommand::test 77f3950214a1bd1e3816fa6f7b0ca69727e9e18be5fb7b37f19490408ca023dc
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannels::test 12a0a6e0a0a6632960de98236670e063f2c1aa16cf6b6c8d718bde0e0abfd9b9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannelsFiltered::test bff8ca8465c2299d0d2ef60adfa4164270d08cee7223361bb27b86a7e4daeec9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:9e893d263294d04d 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:fc6b17eb4e9e7a00 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:b37376c5865a6fe8 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:5d497faea315b624 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:282fa0139ccbba29 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:f08c6eb7b4d12fac 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:37f0f73ed7492dd0 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:d75917941e63732c 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:2f72da33fdbcd8be 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear_Filtered::test f3e0550a53faca13679421318eee85f010c1b8668e3edfae6e2548d39dbcafd7
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear::test 61d7419956a83be04eeb13557c6a2120419b2f0f1c529149c4fb57871bb6506e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyInventoryOffer::test 2bbac63ab86ec77f6d0a4558a14ee913a7f44930364476a89e02cd5ec80191b9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandLegal::test 83a07a88a0386982c854a0223b64dd5c417f1a55a038e4ceba8f487983daadaf
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandWithRestrictions::test 166e2087aa0652bdd427e1908bc338659ec1d4dc8065c016612696d1f5dfd000
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear::test 9529acb9f3e1c335a50f8de6d63cc5711921de962546ff868811279d05826399
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear_Illegal::test 65bfc1db698470cf56dd8c6811e85ae373d1fca95cdbf82be66b7e32da311a2f
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear::test 340b60b8038dcd55320dc9aedc16beb9193e731ba7b659ca3cb2951a2d19b7ac
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear_illegal::test e7056e6e145430eb2180edb92593f59c07bcbdfa21629b1ca29ac93b2fca975e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached::test dc5239c77b9169cf3833c5a1dc765b381efe833f15b34ac7e57173c0a640942a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached_Illegal::test b56de057dece9cb8ece795d13d6bc42e7825d62f09f967f37a4dbf262d2b4456
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached::test a741cec23a985028b3dc2b09195255276a96e4f07fc4fe5f8cca6c1e3c940d71
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached_Illegal::test 1a4c9475a3b91a975b9861685dcaf899505b4f6727257618f9add9cecd3df54d
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:478968a5d14830de 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:8c124ee42e9ab944 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.ManualVersion::test 6f8493b201d69e1449d8311e434736f6f6b2bad04c9fe9c6adf94a94d9cbe597
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:442bdc765ad34e20 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:968af293ea2a53a1 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:ae9a221915e6e1bb f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddAttachRestrictionTests.cs::AddAttachRestrictionTests.AddAttach::test bb2c3495d7b6862fabe1007bcfccc2850d29eef1d9aa4eac6d13d6004dcc4e6b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddAttachRestrictionTests.cs::AddAttachRestrictionTests.AddAttach_Specific::test 0201965931ebba1c13a23bbb43a8787c1639b0b98851141faffd963173c51035
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddOutfitRestrictionTests.cs::AddOutfitRestrictionTests.AddOutfit::test d4902b4dda0a640d240c88af30431f6d247aae2a74a81126fd91ba1d930de3fb
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddOutfitRestrictionTests.cs::AddOutfitRestrictionTests.AddOutfit_part::test e7e5467b36484fb54b0336abccf682905fbe5bff9e04195645981815e2ffadeb
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AllowIdleRestrictionTests.cs::AllowIdleRestrictionTests.CanAllowIdle::test 6278bb1a70f024f687080cb8e8a56bbc923f679fb4adb61c6c91c3397a3de7fc
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AlwaysRunRestrictionTests.cs::AlwaysRunRestrictionTests.CanAlwaysRun::test 9c0a34e0960e3e2a834ccfc1c129a1f5a8f8c6cfd30b322671b4e5c4cd25a24c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis::test 39bc0c4581f8277f4d5c90ec715c40f4715b5ae7007a28a04fe762f2f6adfbfd
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive::test d051e7783e79bf91a8092cd2d29cf1aacec3b0af86ecf0c7ca590ce25bc8393c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Path::test b4db2b29ad376777b382f8c6f4f7b62643bb2dd43858de4be69ac2252f18c963
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Worn::test 6ecfc6ffe71896979a37dac6dd8149a015b8d3e7e952247954333c053da4961e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Attached::test 8ac38c77c6bdb03e4cbaa96600bead9a760eb5eec098504b05cfb3a1bdfb8557
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Attached_AddRem::test 495f288e0fa86059d13a027075700ba6308e9c9d585fa56e3d1adf4a71df912b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis::test 3a8a5acc4ad5cbec76737239ea23330a34f54146a4ff9d5d25082c220527a3e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_NotRecursive::test a5818b4e30d04aba7d6427b2b94e025d34e82eb3bdcb7ac80a23e55f2382ec29
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByPath::test 93e1721f171e24e540160e738f731b895ebd868d840bcdf7c16ba92f6eb4c49a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByRlvAttachmentPoint::test 90a562b2c120daa0ea2612befe9e09649bc2ffac59c2cd360fe4a37dedf85ae3
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByWornLayer::test a444d51c2091fa36f1a010e98ad896042aa0262153ea8a833a14dfcbf02de85e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByWornLayer_AddRem::test dd3d9a0d9b56f08f6be7a6200e1f50e834ecc7613de0cdf44ee89262b3abdb30
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatNormalTests.cs::ChatNormalTests.CanChatNormal::test 9a23c49327636e769c7ff2688a0649d441f3531406e8f51e152ec7186a312287
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatShoutRestrictionTests.cs::ChatShoutRestrictionTests.CanChatShout::test 493e1dd87afaaa7f8183e677df5c32d00f150ffcdd53f9afad8684672837aa28
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatWhisperRestrictionTests.cs::ChatWhisperRestrictionTests.CanChatWhisper::test 67c5d2cb8b3e9424fbcf08378c2a28368fe07aa83ec028df7cf88b91576d3e9f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DefaultWearRestrictionTests.cs::DefaultWearRestrictionTests.CanDefaultWear::test 64eef4c82d1c5a21bc923cfd44616ddc1a5e6403a9a1c5ad6bd2e5ee06e9704c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis::test ee74f952bd602bd23cfc7b203940a902e1b30e02cff60c1abc1f74da964c1f7d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive::test 2b6a646ee82484a6d1901ea4425b0e32fe553827f5bea37b506ffe29d1aec192
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Path::test 731244b623f23a8870d011280a062add751607ce2c58be3261485bb61d488297
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Worn::test d8424a48e64346edd683b7a68652dd5a0be615658f085b0390699ac7b4db5d2c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Attached::test f399592217e7a4638ea25d469681ab9cc58bf8a937af2bfff8895996f7bbc493
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Attached_AddRem::test 507273250b932ff93fa34f87190ad1ab289edeed275be6d2259bab05c5b055d1
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach_Default::test 8c5b165329ab6b46eb3ec7c9a07383e8ea1e54edf0882b43b14166d67cc45617
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach::test 50f5419aea3ea41aa9ebedd29202a549deb4ae6089c38965300a46fd5abf94bf
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach_AttachPoint::test a75fea134b92bca704b2e140135076d699d645c0d2854022d5b20d14be372589
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis::test bf6cdb48a5271d5116db4d0cbf12dbf63fc3cc93862bf718cf849d4abf9eb7cc
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_NotRecursive::test a8452e2b0abcf82447394bae981a1d25677147fad17828d8f6d0705264efa429
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByPath::test e6378e0db310005b8426cabd25969818ed36252e1995de97c6b29d5ab155ee58
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByRlvAttachmentPoint::test 278e4cbf0f9999efec04fcabade19da97439cca732e0e7e3e3c004e232c27224
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByWornLayer::test 66b7eba54e34ed58c59d594cdcb85d874c4db9bbbd871e5438c40fd3d47ad3f6
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByWornLayer_AddRem::test 7424bf38db1abd74132618ee3bcf95a79c32942da26086760dc82355a815d37e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditAttachRestrictionTests.cs::EditAttachRestrictionTests.CanEdit_Attachment::test 22bc9e267e270c2c762561851249af4ef64c0b5bd288950a95b1b636b2975b6e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditRestrictionTests.cs::EditRestrictionTests.CanEditFolderNameSpecifiesToAddInsteadOfReplace::test 6d82d0869826bbc935d89967445dfc991619bdaf3fa631550c5d3f91a13c4935
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditWorldRestrictionTests.cs::EditWorldRestrictionTests.CanEdit_World::test 1f335a2c81735bf58294b97ceedfd85192113e69c78a38804f0db923ce7a0241
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch::case:ccd63fc5b9c064fb a5568e0040a3c0ac8875a11596b7d0799ac5169b919e4fc65587555b2d3edd52
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch::case:ae3d093c6c7267ac a5568e0040a3c0ac8875a11596b7d0799ac5169b919e4fc65587555b2d3edd52
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Synonym::case:ccd63fc5b9c064fb c7aff866d539ceb26cc028532a901f18b58bb020f34da56444f08c9f4df1eb52
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Synonym::case:ae3d093c6c7267ac c7aff866d539ceb26cc028532a901f18b58bb020f34da56444f08c9f4df1eb52
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Default::case:ccd63fc5b9c064fb e894c744ea780a0a46cd2387157077c1a62c3c6b982303f3b7bff0b5d950816a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Default::case:ae3d093c6c7267ac e894c744ea780a0a46cd2387157077c1a62c3c6b982303f3b7bff0b5d950816a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:5788809ef8877342 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:b3ebeae1885ed5db 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:07cf5c5cabecfebf 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:8008f95bc76b47e9 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FlyRestrictionTests.cs::FlyRestrictionTests.CanFly::test 5f60149edccece6b8a6827bbdc6f593ffd863961c13b506f1171aa0cf37fd5b7
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/InteractRestrictionTests.cs::InteractRestrictionTests.CanInteract::test 935d319e07b613ba39b06db30cfd18306670f7dc97186db38c0374c3aac6901e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/InteractRestrictionTests.cs::InteractRestrictionTests.CanInteract_default::test 53b9d7f7cfd63a10538060624f81b7a6b1754a7462c230671ed909698dd18923
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/JumpRestrictionTests.cs::JumpRestrictionTests.CanJump::test 104374c66e6748d101b69ed5343d9972f29e937305cb17f90244ffa74fc7ed35
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/PermissiveRestrictionTests.cs::PermissiveRestrictionTests.Permissive_On::test 923519a1220e5b3007321fb9ee8cc9db27bc0bbc38bed69df0659e4365c610e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/PermissiveRestrictionTests.cs::PermissiveRestrictionTests.Permissive_Off::test b995698351bf04e00ab5aed459c8ee08292897545b8684338a90eaf42cd6c4aa
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatExceptionTests.cs::RecvChatExceptionTests.CanRecvChat::test 017906038e211352d7d2751fafbcab5028cd8b189e7aa29a6202ff578976a23c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatFromRestrictionTests.cs::RecvChatFromRestrictionTests.CanRecvChatFrom::test aaf24dc0b8533a7e93cc567fecbb866067b72da1837207869f879647840bfa21
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatSecExceptionTests.cs::RecvChatSecExceptionTests.CanRecvChat_Secure::test cba089ebe607088e37be285918a1d2c674f1acc4cad075733108afea3ad0279b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteFromRestrictionTests.cs::RecvEmoteFromRestrictionTests.CanRecvChat_RecvEmoteFrom::test d07ded724315cf135603d4dc5a684e5a59a5cf8415963acc30d402ad81916ac1
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteRestrictionTests.cs::RecvEmoteRestrictionTests.CanRecvChat_RecvEmote::test 438b72e6c44570580bf41aa7b8ed00afb800eff8836ee971eab9fc6a00fecc19
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteSecRestrictionTests.cs::RecvEmoteSecRestrictionTests.CanRecvChat_RecvEmote_Secure::test 9e1f72426762569b1c650fdf80c53e4a590b6476f8539fff6e110101e48459e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMFrom::test ebe072c7e1c8ba440b560c2e4a0aa5151ba546f5b6cd5505012958e901c58201
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMFrom_Group::test d3d155240723ca2d379f00111a3b27acb41786615a2f5b0ad2c968040d7f4447
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMTo_AllGroups::test dd1050e7ef3e9805b88964822485856d6b2e5e98ee647ee08251cbc5bd452208
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImRestrictionTests.cs::RecvImRestrictionTests.CanReceiveIM::test 9c88e79ed2686e571e32ccecbc93c130423b966ff4e65e72f228f1713e5047cd
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure::test e549fe9719efd180f8ab8c80b989701cd23ebf07cd004d9a5a18a0cc7db12e64
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure_Group::test 13653ee7443d2eca88f2940d0c3804de3685dcf6c9277a4717a42dad4c01fca4
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure_AllGroups::test d99435b52a3b774ab5d2bb6911824fa45803fe82cfe0b2c192a05473b72463c8
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemAttachRestrictionTests.cs::RemAttachRestrictionTests.RemAttach::test 7005409bfff88f7fb75e5cf87f6f52f4c6f048de32f651b844cf62a1cc16f55c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemAttachRestrictionTests.cs::RemAttachRestrictionTests.RemAttach_Specific::test 407cb5627753c42af2b469644ddc2857416fb4b181bfbb742b199ad7239d5e6f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemOutfitRestrictionTests.cs::RemOutfitRestrictionTests.RemOutfit::test 2aa5056c8aec09fb28d0da37bf6861220595cacb3190542d865f99034fc1c488
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemOutfitRestrictionTests.cs::RemOutfitRestrictionTests.RemOutfit_part::test f0c36209e33c9961b10ff685c8d4a32e279b4852e1c16a0e724f3cd481089576
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RezRestrictionTests.cs::RezRestrictionTests.CanRez::test 5cae348cc241a884803692031c0af4f33fb3a2ce8331129a9866c5364599eccb
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelRestrictionTests.cs::SendChannelRestrictionTests.CanSendChannel::test 8496734391f57cf2f2d8156f3b5a9ad9147c959e3bf99f9e76a4072e971a5b42
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelSecRestrictionTests.cs::SendChannelSecRestrictionTests.CanSendChannel_Secure::test 5bd9096e9af488d5cdb08ed78120ef46f81f9be1eaf132c49a955eb07ae904eb
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelSecRestrictionTests.cs::SendChannelSecRestrictionTests.CanSendChannel_Secure_Exception::test e675121ba9f6ab8f6e4484e66d76d0dd14f8ef39122c8fff2878ba5e6b3a7409
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChatRestrictionTests.cs::SendChatRestrictionTests.CanSendChat::test 36cfbe5123b4b37ee43f0b4ba6453ebbe2754960825b1a8481e77e4f3a0e8015
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChatRestrictionTests.cs::SendChatRestrictionTests.CanChat_SendChatRestriction::test 793a31da070038e90c41e4bdb1161daaf51376617a7444867f19c7125ad34313
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendGestureRestrictionTests.cs::SendGestureRestrictionTests.CanSendGesture::test 91367110c04e3c6ad173f56f209a166d828560850d3d084893e899bcc756428a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImRestrictionTests.cs::SendImRestrictionTests.CanSendIM::test c63ab3a41b6b302e7c84c54374c7193335840bafc40f2d0f2b1c3a2787b26203
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure::test 65422234501bcbf151f27e0d45c74726e670665f39d90df23396f79450ba2b91
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure_Group::test 4ed2e6416a86eb2406e20bbb7e60a380de25577ad034ba613530ed28f6001df9
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure_AllGroups::test a4b699c9ada01ca4ce4d535739178e5310affa938d02dfaede6d034488d24f5f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo::test 38258cda1081160b6b34f8e909adbc683a0f08efce8c63066bcac09835e5cdcc
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo_Group::test 1e12f7e3dbbee7d8dfb757fc8797644a353dfaa995e343e59124aa85126d70aa
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo_AllGroups::test bc9b87ab7b171c76987ddaf94f05c0ac2ad8dc0c1f24f5dfce2f4125e7b28df5
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetDebugRestrictionTests.cs::SetDebugRestrictionTests.CanSetDebug::test d4fb9da4879ef8d1be115e00b7a8de959fd58e32722bc9e2985bca8e97dd2ce3
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetEnvRestrictionTests.cs::SetEnvRestrictionTests.CanSetEnv::test bb4c82afd643d267264467282cdfe09095c804079e73dd15179e1aa0b063c08f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetGroupRestrictionTests.cs::SetGroupRestrictionTests.CanSetGroup::test 9d89210cbc5c188985a535ae045e44d296c796f700d4a1e2b7b4d75345cc4a6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareRestrictionTests.cs::ShareRestrictionTests.CanShare::test 23052e5792ff72624d45b54ccfd02fa5d8025d977010f1e8d34a90d27a4d0e29
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareSecRestrictionTests.cs::ShareSecRestrictionTests.CanShare_Secure_Default::test 6d61bafb190791ceaccb6c46cde3adf5b5479e6b5e76bafeadd0942400389248
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareSecRestrictionTests.cs::ShareSecRestrictionTests.CanShare_Secure::test e1aed5b3b8efccef47094788c3221e20240c671c1004d6d6bd899e5d9ddd51fa
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextAllRestrictionTests.cs::ShowHoverTextAllRestrictionTests.CanShowHoverTextAll::test 6a855738e87477d31dc7867d0c75ba1bf563e2b1e180f54759657a58b7da9793
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextHudRestrictionTests.cs::ShowHoverTextHudRestrictionTests.CanShowHoverTextHud::test 9d08e2a3eb303b14c4b222cae5d52537e81a7d9cfc9fcfe9625d513b6311a6ed
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextRestrictionTests.cs::ShowHoverTextRestrictionTests.CanShowHoverText::test 5642102d6832b227c37c14d0fbfc30921022c5789b811021805db6f3a2120f36
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextWorldRestrictionTests.cs::ShowHoverTextWorldRestrictionTests.CanShowHoverTextWorld::test 1be82408fbc87f1525dc7652e01fbbc17a993b70a2268f0b742d035b37cbf70c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowInvRestrictionTests.cs::ShowInvRestrictionTests.CanShowInv::test b7c8bb7ad9d2c02c1c0168531c8ac0636885817a40b13bc006f4f5b20d28591c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowLocRestrictionTests.cs::ShowLocRestrictionTests.CanShowLoc::test a8b154f2db967ab72781f31dcd7701d204f66ece1ef95a30cc67d788c78da617
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowMiniMapRestrictionTests.cs::ShowMiniMapRestrictionTests.CanShowMiniMap::test da901135b533aee1b025cf5dd925e857b4734ea00770ced4518f501453ea9736
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNameTagsRestrictionTests.cs::ShowNameTagsRestrictionTests.CanShowNameTags::test 74e8a6aefdefb9eb41509f6b4438e6854e5ad0ace38ab663f445aae484e94e22
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesRestrictionTests.cs::ShowNamesRestrictionTests.CanShowNames::test c44fe98d881a89af5db856e98f7bd7480d9bfb4378730002e518a7d1da412812
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure_Default::test 98d2c84d2f226fbb4b03c365f3ab007142d87b1980dda3666ce5ec36909fc599
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure::test 90ae29916dc2b60cd3de336e4a37683de8967f448fef26af360e3d24278773d3
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure_Except::test 457772321f7fd1ea88a279e99a4b0a955e462652bac1fb7953b8455f3d67a155
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNearbyRestrictionTests.cs::ShowNearbyRestrictionTests.CanShowNearby::test 4faa79795b1143934efbd8ebea7a926b270dd5d1e69f8a64f496063d570d868d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowWorldMapRestrictionTests.cs::ShowWorldMapRestrictionTests.CanShowWorldMap::test da16f247df929f83ed21377869790c00cb5922fa6086da3787e90570f5684f67
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitRestrictionTests.cs::SitRestrictionTests.CanSit::test 813906dbfd09bb02c129a794f40a2f5dcda6e73d232e167359a6360a350fa4b4
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Default::test ddcdba94af060ede43f0d585688966ccd923238a2365164b32a301b04d83cdfc
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Single::test 041c57829ab1032eed79e6f47c8b9026124b681fb6ffa4b3c5ac16b16d0b354b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_SingleSender::test feed9f3cca3395e1eb5a8d831304a4171e79f6e1d93f03a4aca0e27edba5ed6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_SingleSender_WithRemoval::test 4b26c525e0a13fbc79b280f0a6c3b0f9e3e0e664241e9f55a88eda3dd80b203a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_MultipleSenders::test cd9e3508d44e2e008609ac0cc12d3e207ec454a3f5c6e36aa325d33be9b6718f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Off::test e871d15d797e0f8f0b02613c2a421b47b87068c8757bbd0104cd15d406137854
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/StandTpRestrictionTests.cs::StandTpRestrictionTests.CanStandTp::test 0f694e59d32c3c97fbee072d591b74c89561f4648bd3440002d8f54db0058a94
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/StartImRestrictionTests.cs::StartImRestrictionTests.CanStartIM::test cc8318d5233b947ca96939369de3a2fdc2c21468cc13a87c87908126c6e45500
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/StartImToRestrictionTests.cs::StartImToRestrictionTests.CanStartIMTo::test 0c7e19de2ecf94a6db09ee409ff88ff503e02d8dd8f7f11f427cebc51a3ac09f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TempRunRestrictionTests.cs::TempRunRestrictionTests.CanTempRun::test 8893bb24bf10de7e914874c347ac5b73982d33925a1cf29ae8c361c3087be408
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAllRestrictionTests.cs::TouchAllRestrictionTests.TouchAll::test 06da3251125bf4d3b2d542cfba7fa0a7b0c18dc0f97024a57c0e0ddf6cfc8dd6
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAllRestrictionTests.cs::TouchAllRestrictionTests.TouchAll_default::test 9526d7bed6473afd41f97fb11ec950caae157865cec8eee719030ca109ab2681
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachOtherRestrictionTests.cs::TouchAttachOtherRestrictionTests.TouchAttachOther_default::test 1f8157f5fd5db8b5a4596d5be6a5d780704cac85370204c77eca08da286adb86
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachOtherRestrictionTests.cs::TouchAttachOtherRestrictionTests.TouchAttachOther_Specific::test add9d393d4aaf03768239611a8a64b2ef73fc4c8561dbbc51950a10c006198e6
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachRestrictionTests.cs::TouchAttachRestrictionTests.TouchAttach_default::test 4c4c65f8ed4b29367c353a02e52c91e9402788ffd35c75e5a6a40a827710e20a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachSelfRestrictionTests.cs::TouchAttachSelfRestrictionTests.TouchAttachSelf_default::test 09f7d7a45a9899746c1c63608f95db89ef2ae4a875437a2b594bb120da8139ff
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchHudRestrictionTests.cs::TouchHudRestrictionTests.TouchHud_default::test b15afadb1f45b51eb47651a9d890ed2a6b1de8066d986d9b1ccc33da734c0194
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchHudRestrictionTests.cs::TouchHudRestrictionTests.TouchHud_specific::test 4c4e1a9493e5cf34f220ebec54c5373e1b30c81044803deece263dced5f7155d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchWorldRestrictionTests.cs::TouchWorldRestrictionTests.TouchWorld_default::test 5995288721c44beaa329b266e15d619f2314c9ca74386145294183c7c509b42a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLmRestrictionTests.cs::TpLmRestrictionTests.CanTpLm::test 847bd3264fd831837d8dab25b235450f19591fef3b3bd0315021727453ad64ee
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocRestrictionTests.cs::TpLocRestrictionTests.CanTpLoc::test 8e5e2ab1b55b710ecce509b141ccac9bcd9ebbad479868496645ac89574bd089
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocalRestrictionTests.cs::TpLocalRestrictionTests.CanTpLocal_Default::test 4b251429c6561c1d29f19f8fbc33dd0fb11344fe0d10962e789823ffedb3777b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocalRestrictionTests.cs::TpLocalRestrictionTests.CanTpLocal::test f9dd3daf337533beab1f4c2dce488f44dea5d17880e8f61b33e3c17c1a4c776f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureRestrictionTests.cs::TpLureRestrictionTests.CanTpLure_Default::test 595e468736aab4136404842adf36a79f37b9900c3ee3993079621a5a6c96dec1
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureRestrictionTests.cs::TpLureRestrictionTests.CanTpLure::test a57f7803128d75a0f1ba35a1c7489f78ca99d7e5e540f06b84725da8a5cd10da
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureSecRestrictionTests.cs::TpLureSecRestrictionTests.CanTpLure_Secure_Default::test 577c2c8d22ba1aa8d4426832807ea4ed8cd243836b0d38b0ebc9f32a851c34f4
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureSecRestrictionTests.cs::TpLureSecRestrictionTests.CanTpLure_Secure::test 38f2894e39bdd7c3c8e1520fa6ed02573be3dfdef0bc5bd1073d9d2240917804
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestRestrictionTests.cs::TpRequestRestrictionTests.CanTpRequest::test 08ddf0e6dd1faf1f249bc7f7a9545d9e33efb5a438eacc3606b1495a83cf57db
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestRestrictionTests.cs::TpRequestRestrictionTests.CanTpRequest_Except::test 89ccb1dd172928c41079555cb6d7ff3fcbd34594dcff0399670cdebc739ac109
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestSecRestrictionTests.cs::TpRequestSecRestrictionTests.CanTpRequest_Secure_Default::test 87cb0ffa95d408d55045ade0966979360c28762e05729893b068801ed3b877ed
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestSecRestrictionTests.cs::TpRequestSecRestrictionTests.CanTpRequest_Secure::test 623310f5c9150f6d6527b0db0446e2c33bf873a849a8dc68b78a4173d130da93
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/UnsitRestrictionTests.cs::UnsitRestrictionTests.CanUnsit::test 2341a0d230eace08d612a1ae3f9aac7b5a1d3d914f04b6ada4726523e9bd3a37
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewNoteRestrictionTests.cs::ViewNoteRestrictionTests.CanViewNote::test 954472ccc5e060f987260c7d8f87f09dcb252e832c22810ed48dd316a173cf5e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewScriptRestrictionTests.cs::ViewScriptRestrictionTests.CanViewScript::test 5e9246991c14d80bc83aad4b5944bd9701dc32b354a701a378def8924f7b5315
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewTextureRestrictionTests.cs::ViewTextureRestrictionTests.CanViewTexture::test d1ee89e12ea9c2d971b4d11c82f3129412fd56fa28d2bd2fb923f082eda62571
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Single::test 5f3010d46f3f18ed57ea52916dd9e8bde27d75c707dbcc0c6d68eb9bbe6c3591
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_SingleSender::test 0df818c7a6c90358cb52f59f972e16c769d38f448619dbdfeddd5a602f64d1d9
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_SingleSender_WithRemoval::test ed19a63ef16a600c9367f45d1a704739fd8e20e7811c7055df009676884de7dd
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_MultipleSenders::test c8ce609cf7506ae2df6e17126ebe5174f958245bedea26fe39600fb90195bdda
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Off::test 8f8ec9da2b0196a51dfb3fea709de597bdb440196697523824f78ef359a5482a
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Default::test 5997b7c86a1b1dac59b7f6c03d38cd09f0fb12619f03f68e1167c85ebe02f7d0
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Single::test 75530a051696ffd586b5643f0c9b9f1ae1c05bd30f9c3068f94cb30abbdc6d2d
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_SingleSender::test 44d6a5b2a9462c83047f5b4ec9f4e66bb518f6547ec08df2b5420850129ff7cb
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_SingleSender_WithRemoval::test 4958ce547ff71cf18d31cd557ecaecb8ae0a19b169c2051bd6797769bbcde26e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_MultipleSenders::test 76346d0c1f4ecf22d09c1950aef99207d28ffe5576b7bc0be1212b91d6518f2c
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Off::test 88e2ec791d3f78bb6551b7d37a52cc5dc18c156ddd483bd6ba55288144005e5c
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin::test cf5f8bfbea933b64bc282211f498b01eefab0b31728800e2965a8a489f85b15d
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax::test 7441bff0655432365bb702cce92465ab0ab7b7dd195b732312a4e243f975ba48
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFovMin::test b433f776bfa059a889b1a13ebc0841c824715194b6b0634dea1dd5740d5b7bbe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFovMax::test e0f313a03073b283400130e5a91c8c4157c9b83f9001f1ad1badf15f80821663
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov::test 02118d87dfda863c31de56267a31beba94ff124ca225f56d67222b6ffaf0c6f9
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov_Restricted::test 34b9c620b61777ece7ad140fc15dde6d2b77d877af597cf2a1b5d5f768cd5fc7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov_Restricted_Synonym::test d8824c6f673ea7c101d309643ed4dbacc0fd6b17c0bda13f8cbb16b956529db4
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMax::test 61206ccc9664f63057389d0d9540022ba82da88b1e213387a9a7f0d0cec050b3
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMax_Synonym::test 9742afe1eb83fe3b63f6ce195bb1fb08058a6272e9817b3d1e09c50ca914a66a
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMin::test be661f7ae623eafe2c00a7eb80a716ab832cd56be904725cfa01c16ab219d10e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMin_Synonym::test da29486a2c8bc2801805774269743566457ca1b9b316dc6846cf499b60aa588d
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawAlphaMax::test 96e0f72499cdf258062ca0610594137c72f232ddf936c0cc929429368957d3ed
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMin::test 53a901a99baeb1f8d45a07d1347a6491d66ad8ca76cdef5304c64738e486e7a9
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMin_Small::test 3f531bfcd6e08830912fd4d619a8ffc5e3ab40e9d036769f742ae0d06207400e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMax::test 71ab081b330b9fc4cc73a06b214f52e577ab25c0ff15439e18737dfb220d7aaf
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMax_Small::test 72d0752ae72ba5288d2b96fca3e0a29c162406b38588160e6801b211c82fac11
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawAlphaMin::test 697fafc1837d56255cdf5e2a09634dcc740651d45df04a712c030a224a58d0c2
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor::test b3bc0346dbcf6c6b03d9c2c38b225e7903754fcbc56c74d098dbdcb617d2426d
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Default::test fedba7874c0b897309caca0e007cb9fbcbce8cd5155c91ec94bf6d1f391d47a1
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Large::test 6d2f0a4a24e71afbca88f3dfe574ff8ee5825e4df9a08552ac4af22a0a6b9f5e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Negative::test 5f7ae954b3f75c5a86da8222a5eadc42ac3fee6ac4134455fb2a7a2e24101081
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Removal::test 81322059c2a6e0054c1d2131e0698c614942eec69958f72315545e9b1517fcb5
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Multi::test 21b9615f5a7e809ec83442035588414101fdf3862f282f1a501fb15d904f981e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CanSetCamUnlock::test 3983d83fb0086bc71a585eeda9b561c738ba1eb99365182115a673ab38e166a1
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CanCamUnlock::test b116d0b63222b30c67da7c08d48f10701f5def2bdd3584166939d713a86a8cd4
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamAvDist::test 4c5641b0e975136e815bfaf8d9821240f0ac2bc615ed105fa5190dfdbcddc158
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures::case:0fdad12f3bfb0585 4b5058bfacb3e7f282bb83d0068ff9c7c7464b0d4119f879d670ddaf34d469b6
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures::case:19c11fd923cc347d 4b5058bfacb3e7f282bb83d0068ff9c7c7464b0d4119f879d670ddaf34d469b6
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Single::case:0fdad12f3bfb0585 abe9a6cff61faf1afbd29c4b073d34d67cf5e77058df44b68cbed7e1d9569814
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Single::case:19c11fd923cc347d abe9a6cff61faf1afbd29c4b073d34d67cf5e77058df44b68cbed7e1d9569814
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:1c2423e3f02a5f03 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:57689650dc307766 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:081becc69dc8e183 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:d96d157e365ded15 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamAvDistMin::test 60d28627494c147228930839a18016e3cbfa8eb042167965647794902eb340a6
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamAvDistMax::test a7cf7887d2934984cc13e10f3afa3248a5e677c9fac680af2a68c3a27d76c3da
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFovMin::test 25a040ca69bf4c2a303d45314fec99e70371bf6ac46e1793384e0a626deb4e75
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFovMax::test 19153fa188ef6bd763235a03048771d1a1d824c1aeaf64841b7e6e70c35813ae
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamZoomMin::test 8cd72b3f1922b913c6bde59b928f362fa191574dc1df3cfb4668d4ccf00515a9
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFov::test f4031d095b9a7e87d1f1d94e52c15c3c9b2b43aa1ba039c83e391e58ea994c40
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:6e89e27b90f28739 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:82ff323c4cfaad18 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:c64b136643c55ed8 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:32ad2cfbbfcf0638 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:21855f1f68a52025 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:065ec3bc69e3f2b0 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_EmptyByDefault::test 9bd5c937815547d2d4b9dcfcb5c35d69e224cc4dc256273735c69b8be150c3a8
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_ValidBehavior_AddsToBlacklist::test dbf7650afeab51abc22fc48881a06e4908f373b6b0077fe58fc4d4e50ea0e0f5
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_CaseInsensitive_NormalizesToLowercase::test dbc4161b4cd5dd7f3609b11f1c6f4f6e1e243b2ba65a444afa67c70cf649c5d3
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_DuplicateBehavior_OnlyAddsOnce::test 53644a5123b90e32f162a9106c945a57d05b17de1a8ab0bf1930283deaf28018
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:12ae32cb1ec02d01 d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:52109349dabf6910 d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:729e2865c247816a d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:d7a5e915306d21dc d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_ExistingBehavior_RemovesFromBlacklist::test 47501ced70145add192d357c6a2647ca4a923bdaab3b1eff1c3857cebc5020db
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_CaseInsensitive_RemovesCorrectBehavior::test b5f4a87e8dc603a08a9f1225a35e44962d4240a3e5b9e605c948d19b268ed1bd
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NonExistentBehavior_DoesNothing::test 495314ef0e42ec419b804108907c02ffe9520a1657344f391aa491f91129ecc5
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:12ae32cb1ec02d01 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:52109349dabf6910 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:729e2865c247816a 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:d7a5e915306d21dc 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_BlacklistedBehavior_ReturnsTrue::test 2cfeda6f45d63514216d0ffccdee89ee4b7f78e775f43fb12ee78324f9cfde35
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_CaseInsensitive_ReturnsTrue::test 1b4c6ed072b97dd9abcc0f730533691d8a65122d1839d40736e98a0f5c43f07d
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NonBlacklistedBehavior_ReturnsFalse::test f4cc9018c5d111b06dc8c2ce0d6ed042eb063331f35ef1665e65f4d8606d3cd3
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:12ae32cb1ec02d01 ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:52109349dabf6910 ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:729e2865c247816a ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:d7a5e915306d21dc ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_MultipleItems_ReturnsOrderedCollection::test db9bd586b7a4f79ffd2d2c48c8131ccd4bd44d8de444696e9a7c53614ef37ed5
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_ReturnsImmutableCopy::test 64db7441c81ea4f0d2e52e79b479cf658fbd2c2d1d23b918edcfa03db1233a3a
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistWorkflow_AddMultipleBehaviors_WorksCorrectly::test 75d84bd0b26b16821ba107bef2bbb2ae58a2726496a757092b24dff6170f8872
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_IntegrationWithRestrictionsBase_WorksCorrectly::test f7347786e3a579dc0102dc20fb73823362866ea71658777aa6835a28a58daea9
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_EmptyString_ResultsInEmptyBlacklist::test 63555a93fbcc2b7691fdd2b79fe0db8cb305beef2c153b80f0040ba8f4f7117e
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_WithSpaces_HandlesCorrectly::test ddd764a51e179fa6c349ab2a62bdedde1e62e4ff2ae33aa41a4ebb2359974404
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:7da68a0c44d86b61 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:d4dfd612ab268dc7 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:58d5bce9d704814b 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:7c453569c08c0a0f 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:ace2eedabcda99e6 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:1a967cd76f5fa058 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:f6b796736de6a5d8 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:787d37133953ab32 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:d2056032186a0a97 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:c1f038c1236211aa cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:564c3e282f3b402f c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:1d03935868fa6124 c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:12ae32cb1ec02d01 c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_NoRestrictions_ReturnsEmptyCollection::test 327086a5aa514ddf8b2cc40891f7ae5e8039788f5cbfeda86f04bd9161f39ded
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_SingleRestriction_ReturnsSingleId::test 85a822c9e2e8beb2e70748513a397b8ccbb2977c0581b0519bd8ad43e699ad57
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MultipleRestrictionsFromSameObject_ReturnsSingleId::test 933070f933b0a5a39b3d0cd5fd9be9423a538609d0106b352a7d9c339665d6d1
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MultipleObjects_ReturnsAllUniqueIds::test 8c2afe66145e4815e73d7849f83cfec50e4a7a49793cc757917cd608c9387419
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MixedRestrictionsAndExceptions_ReturnsAllUniqueIds::test 25ea3c36aba93d5183816962bf49bfdbc3e17e6b06d73a41dee5b51407a84746
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_AfterRemovingRestriction_DoesNotReturnRemovedObjectId::test af3d5328e5c829bd2de2b72c3f4ede6f083efa789ccef1d73d752612a177360f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_AfterClearingAllRestrictions_ReturnsEmptyCollection::test 191a8cc3dba7e68155083a6892f1b4a29ab589023e22cffbc8cd69c005884cca
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_EmptyInput_NoEffect::test 8718e08bb2bf951a94803b4947943b5f7f9eb85e906b4ac6c639cb8cd065cf9d
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_NonExistentId_NoEffect::test 882d2315f40317cce9c9a026eda498325b6227886652795ed45e87cc4e5697ac
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_SingleObject_RemovesAllRestrictionsFromObject::test 73ab6ee30a336372f6aef5bc4a99dbb58215b9445daea5d9708d0ea9cabe8bd1
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_MultipleObjects_RemovesOnlySpecifiedObjects::test 03b6a6a3e02f6a6a5f296ff1d6cca31c9fc53982cbc9c27e73cfb698ed82acf5
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_PartialMatch_RemovesOnlyMatchingObjects::test 00a26d807882b2bbb375c5ce7cf1074d3227acd891e859602e78abbdc6eefb6a
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_WithNotificationRestrictions_SendsNotifications::test ba82b183dfdb01b36f9b45520e1808290c360f327d4afa833ba3b8c7a7cecffb
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_WithComplexRestrictions_RemovesCorrectly::test 631de2d39fa56b29014fae4ce3b57c480f540ad41ce08a0037b7f8bbfcb3c502
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_TriggersRestrictionUpdatedEvent::test 318f1f4207b04d01076d3498aceea781c4889b05cdbef199cdbea43dde355f4c

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,400 @@
// Exact Rust translations of the direct attachment, outfit, detach, edit, and permissive restrictions.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{
InventoryMap, RlvAttachmentPoint, RlvPermissionsServiceObjectLocation as ObjectLocation,
RlvWearableType,
};
const PRIM_1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
const PRIM_2: &str = "11111111-0002-4aaa-8aaa-ffffffffffff";
const PRIM_3: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn provide_inventory(h: &RlvHarness, root: libremetaverse_rlv::RlvSharedFolder) {
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(root, vec![]).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddAttachRestrictionTests.cs::AddAttachRestrictionTests.AddAttach::test bb2c3495d7b6862fabe1007bcfccc2850d29eef1d9aa4eac6d13d6004dcc4e6b translated
#[test]
fn add_attach_restricts_all_attachment_points() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.happy_shirt
.set_attached_prim_id(Some(Some(guid(PRIM_1))));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@addattach=n")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap()
);
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddAttachRestrictionTests.cs::AddAttachRestrictionTests.AddAttach_Specific::test 0201965931ebba1c13a23bbb43a8787c1639b0b98851141faffd963173c51035 translated
#[test]
fn add_attach_restricts_one_attachment_point() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Groin)));
tree.happy_shirt
.set_attached_prim_id(Some(Some(guid(PRIM_1))));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@addattach:groin=n")).unwrap());
let permissions = h.service.permissions();
assert!(
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap()
);
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddOutfitRestrictionTests.cs::AddOutfitRestrictionTests.AddOutfit::test d4902b4dda0a640d240c88af30431f6d247aae2a74a81126fd91ba1d930de3fb translated
#[test]
fn add_outfit_restricts_all_layers() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Skull)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Shirt)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Hair)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process_from("@addoutfit=n", PRIM_3, "Party Hat (Spine)")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap()
);
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddOutfitRestrictionTests.cs::AddOutfitRestrictionTests.AddOutfit_part::test e7e5467b36484fb54b0336abccf682905fbe5bff9e04195645981815e2ffadeb translated
#[test]
fn add_outfit_restricts_one_layer() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Shirt)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Hair)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@addoutfit:shirt=n")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap()
);
assert!(
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap()
);
}
const OBJECT_1: &str = "00000000-0000-4000-8000-000000000000";
const OBJECT_PRIM_1: &str = "00000000-0000-4000-8000-ffffffffffff";
const OBJECT_2: &str = "11111111-1111-4111-8111-111111111111";
const OBJECT_PRIM_2: &str = "11111111-1111-4111-8111-ffffffffffff";
const FOLDER: &str = "99999999-9999-4999-8999-999999999999";
fn can_detach(
h: &RlvHarness,
item: &str,
prim: Option<&str>,
shared: bool,
point: Option<RlvAttachmentPoint>,
wearable: Option<RlvWearableType>,
) -> bool {
h.service
.permissions()
.can_detach_with_nullable_nullable_nullable_boolean_nullable_nullable(
Some(Some(guid(item))),
prim.map(|value| Some(guid(value))),
Some(Some(guid(FOLDER))),
shared,
point.map(Some),
wearable.map(Some),
)
.unwrap()
}
fn detach_defaults(h: &RlvHarness) -> [bool; 6] {
[
can_detach(h, OBJECT_1, None, false, None, None),
can_detach(
h,
OBJECT_1,
Some(OBJECT_PRIM_1),
false,
Some(RlvAttachmentPoint::Chest),
None,
),
can_detach(h, OBJECT_1, None, false, None, Some(RlvWearableType::Shirt)),
can_detach(h, OBJECT_2, None, true, None, None),
can_detach(
h,
OBJECT_2,
Some(OBJECT_PRIM_2),
true,
Some(RlvAttachmentPoint::Chest),
None,
),
can_detach(h, OBJECT_2, None, true, None, Some(RlvWearableType::Shirt)),
]
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach_Default::test 8c5b165329ab6b46eb3ec7c9a07383e8ea1e54edf0882b43b14166d67cc45617 translated
#[test]
fn detach_default() {
assert_eq!(detach_defaults(&harness()), [true; 6]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach::test 50f5419aea3ea41aa9ebedd29202a549deb4ae6089c38965300a46fd5abf94bf translated
#[test]
fn detach_restricts_sender_prim() {
let h = harness();
assert!(block_on(h.process_from("@detach=n", OBJECT_PRIM_2, "objectPrimId2")).unwrap());
assert_eq!(detach_defaults(&h), [true, true, true, true, false, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach_AttachPoint::test a75fea134b92bca704b2e140135076d699d645c0d2854022d5b20d14be372589 translated
#[test]
fn detach_restricts_attachment_point() {
let h = harness();
assert!(block_on(h.process("@detach:skull=n")).unwrap());
for shared in [false, true] {
assert!(can_detach(&h, OBJECT_1, None, shared, None, None));
assert!(can_detach(
&h,
OBJECT_1,
Some(if shared { OBJECT_PRIM_2 } else { OBJECT_PRIM_1 }),
shared,
Some(RlvAttachmentPoint::Chest),
None
));
assert!(!can_detach(
&h,
OBJECT_1,
Some(if shared { OBJECT_PRIM_2 } else { OBJECT_PRIM_1 }),
shared,
Some(RlvAttachmentPoint::Skull),
None
));
assert!(can_detach(
&h,
OBJECT_1,
None,
shared,
None,
Some(RlvWearableType::Shirt)
));
}
}
fn edit_matrix(command: &str) -> [[bool; 3]; 2] {
let h = harness();
block_on(h.process(command)).unwrap();
[None, Some(Some(guid(OBJECT_1)))].map(|object| {
[
h.service
.permissions()
.can_edit(ObjectLocation::Hud, object)
.unwrap(),
h.service
.permissions()
.can_edit(ObjectLocation::Attached, object)
.unwrap(),
h.service
.permissions()
.can_edit(ObjectLocation::RezzedInWorld, object)
.unwrap(),
]
})
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditAttachRestrictionTests.cs::EditAttachRestrictionTests.CanEdit_Attachment::test 22bc9e267e270c2c762561851249af4ef64c0b5bd288950a95b1b636b2975b6e translated
#[test]
fn edit_attachment_restriction() {
assert_eq!(edit_matrix("@editattach=n"), [[true, false, true]; 2]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditRestrictionTests.cs::EditRestrictionTests.CanEditFolderNameSpecifiesToAddInsteadOfReplace::test 6d82d0869826bbc935d89967445dfc991619bdaf3fa631550c5d3f91a13c4935 translated
#[test]
fn edit_everywhere_restriction() {
assert_eq!(edit_matrix("@edit=n"), [[false, false, false]; 2]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditWorldRestrictionTests.cs::EditWorldRestrictionTests.CanEdit_World::test 1f335a2c81735bf58294b97ceedfd85192113e69c78a38804f0db923ce7a0241 translated
#[test]
fn edit_world_restriction() {
assert_eq!(edit_matrix("@editworld=n"), [[true, true, false]; 2]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/PermissiveRestrictionTests.cs::PermissiveRestrictionTests.Permissive_On::test 923519a1220e5b3007321fb9ee8cc9db27bc0bbc38bed69df0659e4365c610e8 translated
#[test]
fn permissive_on_command_disables_permissive_mode() {
let h = harness();
block_on(h.process("@permissive=n")).unwrap();
assert!(!h.service.permissions().is_permissive().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/PermissiveRestrictionTests.cs::PermissiveRestrictionTests.Permissive_Off::test b995698351bf04e00ab5aed459c8ee08292897545b8684338a90eaf42cd6c4aa translated
#[test]
fn permissive_off_command_restores_permissive_mode() {
let h = harness();
block_on(h.process("@permissive=n")).unwrap();
block_on(h.process("@permissive=y")).unwrap();
assert!(h.service.permissions().is_permissive().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemAttachRestrictionTests.cs::RemAttachRestrictionTests.RemAttach::test 7005409bfff88f7fb75e5cf87f6f52f4c6f048de32f651b844cf62a1cc16f55c translated
#[test]
fn remove_attachment_restriction() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@remattach=n")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap()
);
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemAttachRestrictionTests.cs::RemAttachRestrictionTests.RemAttach_Specific::test 407cb5627753c42af2b469644ddc2857416fb4b181bfbb742b199ad7239d5e6f translated
#[test]
fn remove_specific_attachment_restriction() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Spine)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_2))));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@remattach:spine=n")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_detach_with_rlv_inventory_item(tree.party_hat)
.unwrap()
);
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap()
);
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemOutfitRestrictionTests.cs::RemOutfitRestrictionTests.RemOutfit::test 2aa5056c8aec09fb28d0da37bf6861220595cacb3190542d865f99034fc1c488 translated
#[test]
fn remove_outfit_restriction() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@remoutfit=n")).unwrap());
let permissions = h.service.permissions();
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap()
);
assert!(
!permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemOutfitRestrictionTests.cs::RemOutfitRestrictionTests.RemOutfit_part::test f0c36209e33c9961b10ff685c8d4a32e279b4852e1c16a0e724f3cd481089576 translated
#[test]
fn remove_specific_outfit_layer_restriction() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@remoutfit:pants=n")).unwrap());
let permissions = h.service.permissions();
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap()
);
assert!(
!permissions
.can_detach_with_rlv_inventory_item(tree.retro_pants)
.unwrap()
);
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap()
);
}

View File

@@ -0,0 +1,335 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs.
// Source SHA-256: 01957800d5baff9ab13cf22bc496a5506e26f9be194917a94a3558a8456a761c
use libremetaverse_compat_tests::rlv_support::RlvHarness;
use libremetaverse_types::Error;
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn blacklist_behavior(value: &str) -> Result<(), Error> {
harness()
.service
.blacklist()
.blacklist_behavior(value.into())
}
fn unblacklist_behavior(value: &str) -> Result<(), Error> {
harness()
.service
.blacklist()
.un_blacklist_behavior(value.into())
}
fn is_blacklisted(value: &str) -> bool {
harness()
.service
.blacklist()
.is_blacklisted(value.into())
.unwrap()
}
fn seed(h: &RlvHarness, values: &str) {
for value in values
.split(',')
.map(str::trim)
.filter(|value| !value.is_empty())
{
h.service
.blacklist()
.blacklist_behavior(value.into())
.unwrap();
}
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_EmptyByDefault::test 9bd5c937815547d2d4b9dcfcb5c35d69e224cc4dc256273735c69b8be150c3a8 translated
#[test]
fn blacklist_is_empty_by_default() {
assert!(
harness()
.service
.blacklist()
.get_blacklist()
.unwrap()
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_ValidBehavior_AddsToBlacklist::test dbf7650afeab51abc22fc48881a06e4908f373b6b0077fe58fc4d4e50ea0e0f5 translated
#[test]
fn blacklist_adds_valid_behavior() {
let h = harness();
h.service
.blacklist()
.blacklist_behavior("testbehavior".into())
.unwrap();
let values = h.service.blacklist().get_blacklist().unwrap();
assert_eq!(values.len(), 1);
assert!(values.contains(&"testbehavior".into()));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_CaseInsensitive_NormalizesToLowercase::test dbc4161b4cd5dd7f3609b11f1c6f4f6e1e243b2ba65a444afa67c70cf649c5d3 translated
#[test]
fn blacklist_normalizes_to_lowercase() {
let h = harness();
h.service
.blacklist()
.blacklist_behavior("TestBehavior".into())
.unwrap();
let values = h.service.blacklist().get_blacklist().unwrap();
assert_eq!(values, vec!["testbehavior"]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_DuplicateBehavior_OnlyAddsOnce::test 53644a5123b90e32f162a9106c945a57d05b17de1a8ab0bf1930283deaf28018 translated
#[test]
fn blacklist_deduplicates_case_insensitively() {
let h = harness();
for value in ["testbehavior", "testbehavior", "TESTBEHAVIOR"] {
h.service
.blacklist()
.blacklist_behavior(value.into())
.unwrap();
}
assert_eq!(
h.service.blacklist().get_blacklist().unwrap(),
vec!["testbehavior"]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:12ae32cb1ec02d01 d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17 translated
#[test]
fn blacklist_rejects_empty_behavior() {
assert_eq!(blacklist_behavior(""), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:52109349dabf6910 d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17 translated
#[test]
fn blacklist_rejects_spaces_behavior() {
assert_eq!(blacklist_behavior(" "), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:729e2865c247816a d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17 translated
#[test]
fn blacklist_rejects_tab_behavior() {
assert_eq!(blacklist_behavior("\t"), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:d7a5e915306d21dc d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17 translated
#[test]
fn blacklist_rejects_newline_behavior() {
assert_eq!(blacklist_behavior("\n"), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_ExistingBehavior_RemovesFromBlacklist::test 47501ced70145add192d357c6a2647ca4a923bdaab3b1eff1c3857cebc5020db translated
#[test]
fn unblacklist_removes_existing_behavior() {
let h = harness();
seed(&h, "testbehavior");
h.service
.blacklist()
.un_blacklist_behavior("testbehavior".into())
.unwrap();
assert!(h.service.blacklist().get_blacklist().unwrap().is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_CaseInsensitive_RemovesCorrectBehavior::test b5f4a87e8dc603a08a9f1225a35e44962d4240a3e5b9e605c948d19b268ed1bd translated
#[test]
fn unblacklist_is_case_insensitive() {
let h = harness();
seed(&h, "TestBehavior");
h.service
.blacklist()
.un_blacklist_behavior("testbehavior".into())
.unwrap();
assert!(h.service.blacklist().get_blacklist().unwrap().is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NonExistentBehavior_DoesNothing::test 495314ef0e42ec419b804108907c02ffe9520a1657344f391aa491f91129ecc5 translated
#[test]
fn unblacklist_nonexistent_behavior_does_nothing() {
let h = harness();
seed(&h, "existingbehavior");
h.service
.blacklist()
.un_blacklist_behavior("nonexistentbehavior".into())
.unwrap();
assert_eq!(
h.service.blacklist().get_blacklist().unwrap(),
vec!["existingbehavior"]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:12ae32cb1ec02d01 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f translated
#[test]
fn unblacklist_rejects_empty_behavior() {
assert_eq!(unblacklist_behavior(""), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:52109349dabf6910 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f translated
#[test]
fn unblacklist_rejects_spaces_behavior() {
assert_eq!(unblacklist_behavior(" "), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:729e2865c247816a 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f translated
#[test]
fn unblacklist_rejects_tab_behavior() {
assert_eq!(unblacklist_behavior("\t"), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:d7a5e915306d21dc 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f translated
#[test]
fn unblacklist_rejects_newline_behavior() {
assert_eq!(unblacklist_behavior("\n"), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_BlacklistedBehavior_ReturnsTrue::test 2cfeda6f45d63514216d0ffccdee89ee4b7f78e775f43fb12ee78324f9cfde35 translated
#[test]
fn is_blacklisted_returns_true_for_added_behavior() {
let h = harness();
seed(&h, "testbehavior");
assert!(
h.service
.blacklist()
.is_blacklisted("testbehavior".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_CaseInsensitive_ReturnsTrue::test 1b4c6ed072b97dd9abcc0f730533691d8a65122d1839d40736e98a0f5c43f07d translated
#[test]
fn is_blacklisted_is_case_insensitive() {
let h = harness();
seed(&h, "TestBehavior");
for value in ["testbehavior", "TESTBEHAVIOR", "TestBehavior"] {
assert!(h.service.blacklist().is_blacklisted(value.into()).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NonBlacklistedBehavior_ReturnsFalse::test f4cc9018c5d111b06dc8c2ce0d6ed042eb063331f35ef1665e65f4d8606d3cd3 translated
#[test]
fn is_blacklisted_returns_false_for_missing_behavior() {
let h = harness();
seed(&h, "existingbehavior");
assert!(
!h.service
.blacklist()
.is_blacklisted("nonexistentbehavior".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:12ae32cb1ec02d01 ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa translated
#[test]
fn is_blacklisted_returns_false_for_empty_behavior() {
assert!(!is_blacklisted(""));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:52109349dabf6910 ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa translated
#[test]
fn is_blacklisted_returns_false_for_spaces_behavior() {
assert!(!is_blacklisted(" "));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:729e2865c247816a ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa translated
#[test]
fn is_blacklisted_returns_false_for_tab_behavior() {
assert!(!is_blacklisted("\t"));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:d7a5e915306d21dc ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa translated
#[test]
fn is_blacklisted_returns_false_for_newline_behavior() {
assert!(!is_blacklisted("\n"));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_MultipleItems_ReturnsOrderedCollection::test db9bd586b7a4f79ffd2d2c48c8131ccd4bd44d8de444696e9a7c53614ef37ed5 translated
#[test]
fn get_blacklist_returns_ordered_collection() {
let h = harness();
seed(&h, "zebra,alpha,beta,charlie");
assert_eq!(
h.service.blacklist().get_blacklist().unwrap(),
vec!["alpha", "beta", "charlie", "zebra"]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_ReturnsImmutableCopy::test 64db7441c81ea4f0d2e52e79b479cf658fbd2c2d1d23b918edcfa03db1233a3a translated
#[test]
fn get_blacklist_returns_independent_copy() {
let h = harness();
seed(&h, "testbehavior");
let first = h.service.blacklist().get_blacklist().unwrap();
seed(&h, "anotherbehavior");
let second = h.service.blacklist().get_blacklist().unwrap();
assert_eq!(first, vec!["testbehavior"]);
assert_eq!(second, vec!["anotherbehavior", "testbehavior"]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistWorkflow_AddMultipleBehaviors_WorksCorrectly::test 75d84bd0b26b16821ba107bef2bbb2ae58a2726496a757092b24dff6170f8872 translated
#[test]
fn blacklist_workflow_adds_and_removes_behaviors() {
let h = harness();
seed(&h, "sendim,recvim,tpto,fly");
for value in ["sendim", "recvim", "tpto", "fly"] {
assert!(h.service.blacklist().is_blacklisted(value.into()).unwrap());
}
h.service
.blacklist()
.un_blacklist_behavior("sendim".into())
.unwrap();
h.service
.blacklist()
.un_blacklist_behavior("fly".into())
.unwrap();
assert!(
!h.service
.blacklist()
.is_blacklisted("sendim".into())
.unwrap()
);
assert!(
h.service
.blacklist()
.is_blacklisted("recvim".into())
.unwrap()
);
assert!(h.service.blacklist().is_blacklisted("tpto".into()).unwrap());
assert!(!h.service.blacklist().is_blacklisted("fly".into()).unwrap());
assert_eq!(
h.service.blacklist().get_blacklist().unwrap(),
vec!["recvim", "tpto"]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_IntegrationWithRestrictionsBase_WorksCorrectly::test f7347786e3a579dc0102dc20fb73823362866ea71658777aa6835a28a58daea9 translated
#[test]
fn seed_blacklist_adds_each_comma_separated_behavior() {
let h = harness();
seed(&h, "sendim,recvim,tpto");
for value in ["sendim", "recvim", "tpto"] {
assert!(h.service.blacklist().is_blacklisted(value.into()).unwrap());
}
assert!(!h.service.blacklist().is_blacklisted("fly".into()).unwrap());
assert_eq!(h.service.blacklist().get_blacklist().unwrap().len(), 3);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_EmptyString_ResultsInEmptyBlacklist::test 63555a93fbcc2b7691fdd2b79fe0db8cb305beef2c153b80f0040ba8f4f7117e translated
#[test]
fn seed_blacklist_empty_string_adds_nothing() {
let h = harness();
seed(&h, "");
assert!(h.service.blacklist().get_blacklist().unwrap().is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_WithSpaces_HandlesCorrectly::test ddd764a51e179fa6c349ab2a62bdedde1e62e4ff2ae33aa41a4ebb2359974404 translated
#[test]
fn seed_blacklist_trims_spaces() {
let h = harness();
seed(&h, "sendim, recvim , tpto");
for value in ["sendim", "recvim", "tpto"] {
assert!(h.service.blacklist().is_blacklisted(value.into()).unwrap());
}
assert_eq!(h.service.blacklist().get_blacklist().unwrap().len(), 3);
}

View File

@@ -0,0 +1,691 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs.
// Source SHA-256: 3bd6f2996fc1948e3f7c3087642ef68e0b959e49100cc70d443c5f110d0e3001
use libremetaverse_compat_tests::assert_close;
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::CameraRestrictions;
use libremetaverse_types::compat::{Guid, Vector3};
const SENDER_2: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const SENDER_3: &str = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const TEXTURE_1: &str = "00000000-0000-4000-8000-000000000000";
const TEXTURE_2: &str = "11111111-1111-4111-8111-111111111111";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn restrictions(commands: &[(&str, Option<(&str, &str)>)]) -> CameraRestrictions {
let h = harness();
for (command, sender) in commands {
let result = match sender {
Some((id, name)) => block_on(h.process_from(command, id, name)),
None => block_on(h.process(command)),
};
result.unwrap();
}
h.service.permissions().get_camera_restrictions().unwrap()
}
fn scalar_matches(
commands: &[(&str, Option<(&str, &str)>)],
getter: fn(&CameraRestrictions) -> Option<Option<f32>>,
expected: Option<f32>,
) -> bool {
let value = getter(&restrictions(commands)).flatten();
match expected {
Some(expected) => {
value.is_some_and(|actual| (f64::from(actual) - f64::from(expected)).abs() <= 0.00001)
}
None => value.is_none(),
}
}
fn texture(command: &str) -> Option<Guid> {
restrictions(&[(command, None)]).texture().flatten()
}
fn camera_query(command: &str) -> (bool, Vec<(i32, String)>) {
let h = harness();
h.queries.lock().unwrap().camera_settings = Some([1.23, 123.45, 45.60, 130.0, 12.34, 91.34]);
let processed = block_on(h.process(command)).unwrap();
let replies = h.actions.lock().unwrap().replies.clone();
(processed, replies)
}
fn missing_camera_settings(command: &str) -> (bool, Vec<(i32, String)>) {
let h = harness();
let processed = block_on(h.process(command)).unwrap();
let replies = h.actions.lock().unwrap().replies.clone();
(processed, replies)
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Single::test 5f3010d46f3f18ed57ea52916dd9e8bde27d75c707dbcc0c6d68eb9bbe6c3591 translated
#[test]
fn cam_zoom_min_single() {
assert!(scalar_matches(
&[("@CamZoomMin:1.5=n", None)],
CameraRestrictions::zoom_min,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_SingleSender::test 0df818c7a6c90358cb52f59f972e16c769d38f448619dbdfeddd5a602f64d1d9 translated
#[test]
fn cam_zoom_min_multiple_single_sender() {
assert!(scalar_matches(
&[
("@CamZoomMin:3.5=n", None),
("@CamZoomMin:4.5=n", None),
("@CamZoomMin:1.5=n", None),
],
CameraRestrictions::zoom_min,
Some(4.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_SingleSender_WithRemoval::test ed19a63ef16a600c9367f45d1a704739fd8e20e7811c7055df009676884de7dd translated
#[test]
fn cam_zoom_min_removes_matching_value() {
assert!(scalar_matches(
&[
("@CamZoomMin:3.5=n", None),
("@CamZoomMin:4.5=n", None),
("@CamZoomMin:1.5=n", None),
("@CamZoomMin:8.5=n", None),
("@CamZoomMin:8.5=y", None),
],
CameraRestrictions::zoom_min,
Some(4.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_MultipleSenders::test c8ce609cf7506ae2df6e17126ebe5174f958245bedea26fe39600fb90195bdda translated
#[test]
fn cam_zoom_min_multiple_senders() {
assert!(scalar_matches(
&[
("@CamZoomMin:3.5=n", None),
("@CamZoomMin:4.5=n", Some((SENDER_2, "Sender 2"))),
("@CamZoomMin:1.5=n", Some((SENDER_3, "Sender 3"))),
],
CameraRestrictions::zoom_min,
Some(4.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Off::test 8f8ec9da2b0196a51dfb3fea709de597bdb440196697523824f78ef359a5482a translated
#[test]
fn cam_zoom_min_off() {
assert!(scalar_matches(
&[("@CamZoomMin:1.5=n", None), ("@CamZoomMin:1.5=y", None)],
CameraRestrictions::zoom_min,
None,
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Default::test 5997b7c86a1b1dac59b7f6c03d38cd09f0fb12619f03f68e1167c85ebe02f7d0 translated
#[test]
fn cam_zoom_max_default() {
assert!(scalar_matches(&[], CameraRestrictions::zoom_max, None));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Single::test 75530a051696ffd586b5643f0c9b9f1ae1c05bd30f9c3068f94cb30abbdc6d2d translated
#[test]
fn cam_zoom_max_single() {
assert!(scalar_matches(
&[("@CamZoomMax:1.5=n", None)],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_SingleSender::test 44d6a5b2a9462c83047f5b4ec9f4e66bb518f6547ec08df2b5420850129ff7cb translated
#[test]
fn cam_zoom_max_multiple_single_sender() {
assert!(scalar_matches(
&[
("@CamZoomMax:3.5=n", None),
("@CamZoomMax:4.5=n", None),
("@CamZoomMax:1.5=n", None),
],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_SingleSender_WithRemoval::test 4958ce547ff71cf18d31cd557ecaecb8ae0a19b169c2051bd6797769bbcde26e translated
#[test]
fn cam_zoom_max_removes_matching_value() {
assert!(scalar_matches(
&[
("@CamZoomMax:3.5=n", None),
("@CamZoomMax:4.5=n", None),
("@CamZoomMax:1.5=n", None),
("@CamZoomMax:0.5=n", None),
("@CamZoomMax:0.5=y", None),
],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_MultipleSenders::test 76346d0c1f4ecf22d09c1950aef99207d28ffe5576b7bc0be1212b91d6518f2c translated
#[test]
fn cam_zoom_max_multiple_senders() {
assert!(scalar_matches(
&[
("@CamZoomMax:3.5=n", None),
("@CamZoomMax:4.5=n", Some((SENDER_2, "Sender 2"))),
("@CamZoomMax:1.5=n", Some((SENDER_3, "Sender 3"))),
],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Off::test 88e2ec791d3f78bb6551b7d37a52cc5dc18c156ddd483bd6ba55288144005e5c translated
#[test]
fn cam_zoom_max_off() {
assert!(scalar_matches(
&[("@CamZoomMax:1.5=n", None), ("@CamZoomMax:1.5=y", None)],
CameraRestrictions::zoom_max,
None,
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin::test cf5f8bfbea933b64bc282211f498b01eefab0b31728800e2965a8a489f85b15d translated
#[test]
fn cam_zoom_min_command() {
assert!(scalar_matches(
&[("@CamZoomMin:0.5=n", None)],
CameraRestrictions::zoom_min,
Some(0.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax::test 7441bff0655432365bb702cce92465ab0ab7b7dd195b732312a4e243f975ba48 translated
#[test]
fn cam_zoom_max_command() {
assert!(scalar_matches(
&[("@CamZoomMax:1.5=n", None)],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFovMin::test b433f776bfa059a889b1a13ebc0841c824715194b6b0634dea1dd5740d5b7bbe translated
#[test]
fn set_cam_fov_min() {
assert!(scalar_matches(
&[("@setcam_fovmin:15=n", None)],
CameraRestrictions::fov_min,
Some(15.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFovMax::test e0f313a03073b283400130e5a91c8c4157c9b83f9001f1ad1badf15f80821663 translated
#[test]
fn set_cam_fov_max() {
assert!(scalar_matches(
&[("@setcam_fovmax:45=n", None)],
CameraRestrictions::fov_max,
Some(45.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov::test 02118d87dfda863c31de56267a31beba94ff124ca225f56d67222b6ffaf0c6f9 translated
#[test]
fn set_cam_fov_records_exact_value() {
let h = harness();
assert!(block_on(h.process("@setcam_fov:1.75=force")).unwrap());
assert_eq!(h.actions.lock().unwrap().camera_fovs, vec![1.75]);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov_Restricted::test 34b9c620b61777ece7ad140fc15dde6d2b77d877af597cf2a1b5d5f768cd5fc7 translated
#[test]
fn set_cam_fov_restricted() {
let h = harness();
block_on(h.process("@setcam_unlock=n")).unwrap();
assert!(!block_on(h.process("@setcam_fov:1.75=force")).unwrap());
assert!(h.actions.lock().unwrap().camera_fovs.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov_Restricted_Synonym::test d8824c6f673ea7c101d309643ed4dbacc0fd6b17c0bda13f8cbb16b956529db4 translated
#[test]
fn set_cam_fov_restricted_by_synonym() {
let h = harness();
block_on(h.process("@camunlock=n")).unwrap();
assert!(!block_on(h.process("@setcam_fov:1.75=force")).unwrap());
assert!(h.actions.lock().unwrap().camera_fovs.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMax::test 61206ccc9664f63057389d0d9540022ba82da88b1e213387a9a7f0d0cec050b3 translated
#[test]
fn set_cam_av_dist_max() {
assert!(scalar_matches(
&[("@setcam_avdistmax:30=n", None)],
CameraRestrictions::av_dist_max,
Some(30.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMax_Synonym::test 9742afe1eb83fe3b63f6ce195bb1fb08058a6272e9817b3d1e09c50ca914a66a translated
#[test]
fn set_cam_av_dist_max_synonym() {
assert!(scalar_matches(
&[("@camdistmax:30=n", None)],
CameraRestrictions::av_dist_max,
Some(30.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMin::test be661f7ae623eafe2c00a7eb80a716ab832cd56be904725cfa01c16ab219d10e translated
#[test]
fn set_cam_av_dist_min() {
assert!(scalar_matches(
&[("@setcam_avdistmin:0.3=n", None)],
CameraRestrictions::av_dist_min,
Some(0.3),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMin_Synonym::test da29486a2c8bc2801805774269743566457ca1b9b316dc6846cf499b60aa588d translated
#[test]
fn set_cam_av_dist_min_synonym() {
assert!(scalar_matches(
&[("@camdistmin:0.3=n", None)],
CameraRestrictions::av_dist_min,
Some(0.3),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawAlphaMax::test 96e0f72499cdf258062ca0610594137c72f232ddf936c0cc929429368957d3ed translated
#[test]
fn cam_draw_alpha_max() {
assert!(scalar_matches(
&[("@CamDrawAlphaMax:0.9=n", None)],
CameraRestrictions::draw_alpha_max,
Some(0.9),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMin::test 53a901a99baeb1f8d45a07d1347a6491d66ad8ca76cdef5304c64738e486e7a9 translated
#[test]
fn cam_draw_min() {
assert!(scalar_matches(
&[("@camdrawmin:1.75=n", None)],
CameraRestrictions::draw_min,
Some(1.75),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMin_Small::test 3f531bfcd6e08830912fd4d619a8ffc5e3ab40e9d036769f742ae0d06207400e translated
#[test]
fn cam_draw_min_rejects_too_small_value() {
let h = harness();
assert!(!block_on(h.process("@camdrawmin:0.15=n")).unwrap());
assert!(
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.draw_min()
.flatten()
.is_none()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMax::test 71ab081b330b9fc4cc73a06b214f52e577ab25c0ff15439e18737dfb220d7aaf translated
#[test]
fn cam_draw_max() {
assert!(scalar_matches(
&[("@camdrawmax:1.75=n", None)],
CameraRestrictions::draw_max,
Some(1.75),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMax_Small::test 72d0752ae72ba5288d2b96fca3e0a29c162406b38588160e6801b211c82fac11 translated
#[test]
fn cam_draw_max_rejects_too_small_value() {
let h = harness();
assert!(!block_on(h.process("@camdrawmax:0.15=n")).unwrap());
assert!(
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.draw_max()
.flatten()
.is_none()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawAlphaMin::test 697fafc1837d56255cdf5e2a09634dcc740651d45df04a712c030a224a58d0c2 translated
#[test]
fn cam_draw_alpha_min() {
assert!(scalar_matches(
&[("@camdrawalphamin:1.75=n", None)],
CameraRestrictions::draw_alpha_min,
Some(1.75),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor::test b3bc0346dbcf6c6b03d9c2c38b225e7903754fcbc56c74d098dbdcb617d2426d translated
#[test]
fn cam_draw_color() {
let Vector3(value) = restrictions(&[("@CamDrawColor:0.1;0.2;0.3=n", None)])
.draw_color()
.flatten()
.unwrap();
for (actual, expected) in value.into_iter().zip([0.1, 0.2, 0.3]) {
assert_close(f64::from(actual), expected, 0.00001);
}
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Default::test fedba7874c0b897309caca0e007cb9fbcbce8cd5155c91ec94bf6d1f391d47a1 translated
#[test]
fn cam_draw_color_default() {
assert!(restrictions(&[]).draw_color().flatten().is_none());
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Large::test 6d2f0a4a24e71afbca88f3dfe574ff8ee5825e4df9a08552ac4af22a0a6b9f5e translated
#[test]
#[allow(clippy::float_cmp)] // The C# test requires exact clamped endpoint values.
fn cam_draw_color_clamps_large_components() {
let Vector3(value) = restrictions(&[("@CamDrawColor:5;6;7=n", None)])
.draw_color()
.flatten()
.unwrap();
assert_eq!(value, [1.0, 1.0, 1.0]);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Negative::test 5f7ae954b3f75c5a86da8222a5eadc42ac3fee6ac4134455fb2a7a2e24101081 translated
#[test]
#[allow(clippy::float_cmp)] // The C# test requires exact clamped endpoint values.
fn cam_draw_color_clamps_negative_components() {
let Vector3(value) = restrictions(&[("@CamDrawColor:-5;-6;-7=n", None)])
.draw_color()
.flatten()
.unwrap();
assert_eq!(value, [0.0, 0.0, 0.0]);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Removal::test 81322059c2a6e0054c1d2131e0698c614942eec69958f72315545e9b1517fcb5 translated
#[test]
fn cam_draw_color_removal() {
assert!(
restrictions(&[
("@CamDrawColor:0.1;0.2;0.3=n", None),
("@CamDrawColor:0.1;0.2;0.3=y", None),
])
.draw_color()
.flatten()
.is_none()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Multi::test 21b9615f5a7e809ec83442035588414101fdf3862f282f1a501fb15d904f981e translated
#[test]
fn cam_draw_color_averages_multiple_values() {
let Vector3(value) = restrictions(&[
("@CamDrawColor:0.1;0.2;0.3=n", None),
("@CamDrawColor:0.2;0.3;0.6=n", None),
])
.draw_color()
.flatten()
.unwrap();
for (actual, expected) in value.into_iter().zip([0.15, 0.25, 0.45]) {
assert_close(f64::from(actual), expected, 0.00001);
}
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CanSetCamUnlock::test 3983d83fb0086bc71a585eeda9b561c738ba1eb99365182115a673ab38e166a1 translated
#[test]
fn set_cam_unlock_toggles_lock() {
let h = harness();
block_on(h.process("@setcam_unlock=n")).unwrap();
assert!(
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.is_locked()
);
block_on(h.process("@setcam_unlock=y")).unwrap();
assert!(
!h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.is_locked()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CanCamUnlock::test b116d0b63222b30c67da7c08d48f10701f5def2bdd3584166939d713a86a8cd4 translated
#[test]
fn cam_unlock_synonym_toggles_lock() {
let h = harness();
block_on(h.process("@camunlock=n")).unwrap();
assert!(
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.is_locked()
);
block_on(h.process("@camunlock=y")).unwrap();
assert!(
!h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.is_locked()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamAvDist::test 4c5641b0e975136e815bfaf8d9821240f0ac2bc615ed105fa5190dfdbcddc158 translated
#[test]
fn cam_av_dist() {
assert!(scalar_matches(
&[("@CamAvDist:5=n", None)],
CameraRestrictions::av_dist,
Some(5.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures::case:0fdad12f3bfb0585 4b5058bfacb3e7f282bb83d0068ff9c7c7464b0d4119f879d670ddaf34d469b6 translated
#[test]
fn set_cam_textures_empty_uuid() {
assert_eq!(texture("@setcam_textures=n"), Some(Guid([0; 16])));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures::case:19c11fd923cc347d 4b5058bfacb3e7f282bb83d0068ff9c7c7464b0d4119f879d670ddaf34d469b6 translated
#[test]
fn cam_textures_empty_uuid() {
assert_eq!(texture("@camtextures=n"), Some(Guid([0; 16])));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Single::case:0fdad12f3bfb0585 abe9a6cff61faf1afbd29c4b073d34d67cf5e77058df44b68cbed7e1d9569814 translated
#[test]
fn set_cam_textures_single() {
assert_eq!(
texture(&format!("@setcam_textures:{TEXTURE_1}=n")),
Some(guid(TEXTURE_1))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Single::case:19c11fd923cc347d abe9a6cff61faf1afbd29c4b073d34d67cf5e77058df44b68cbed7e1d9569814 translated
#[test]
fn cam_textures_single() {
assert_eq!(
texture(&format!("@camtextures:{TEXTURE_1}=n")),
Some(guid(TEXTURE_1))
);
}
fn texture_synonyms(first: &str, second: &str) -> [Option<Guid>; 2] {
let h = harness();
block_on(h.process(&format!("@{first}:{TEXTURE_1}=n"))).unwrap();
block_on(h.process(&format!("@{second}:{TEXTURE_2}=n"))).unwrap();
let second_texture = h
.service
.permissions()
.get_camera_restrictions()
.unwrap()
.texture()
.flatten();
block_on(h.process(&format!("@{first}:{TEXTURE_2}=y"))).unwrap();
[
second_texture,
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.texture()
.flatten(),
]
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:1c2423e3f02a5f03 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7 translated
#[test]
fn set_cam_textures_then_set_cam_textures() {
assert_eq!(
texture_synonyms("setcam_textures", "setcam_textures"),
[Some(guid(TEXTURE_2)), Some(guid(TEXTURE_1))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:57689650dc307766 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7 translated
#[test]
fn set_cam_textures_then_cam_textures() {
assert_eq!(
texture_synonyms("setcam_textures", "camtextures"),
[Some(guid(TEXTURE_2)), Some(guid(TEXTURE_1))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:081becc69dc8e183 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7 translated
#[test]
fn cam_textures_then_cam_textures() {
assert_eq!(
texture_synonyms("camtextures", "camtextures"),
[Some(guid(TEXTURE_2)), Some(guid(TEXTURE_1))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:d96d157e365ded15 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7 translated
#[test]
fn cam_textures_then_set_cam_textures() {
assert_eq!(
texture_synonyms("camtextures", "setcam_textures"),
[Some(guid(TEXTURE_2)), Some(guid(TEXTURE_1))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamAvDistMin::test 60d28627494c147228930839a18016e3cbfa8eb042167965647794902eb340a6 translated
#[test]
fn get_cam_av_dist_min() {
assert_eq!(
camera_query("@getcam_avdistmin=1234"),
(true, vec![(1234, "1.23".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamAvDistMax::test a7cf7887d2934984cc13e10f3afa3248a5e677c9fac680af2a68c3a27d76c3da translated
#[test]
fn get_cam_av_dist_max() {
assert_eq!(
camera_query("@getcam_avdistmax=1234"),
(true, vec![(1234, "123.45".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFovMin::test 25a040ca69bf4c2a303d45314fec99e70371bf6ac46e1793384e0a626deb4e75 translated
#[test]
fn get_cam_fov_min() {
assert_eq!(
camera_query("@getcam_fovmin=1234"),
(true, vec![(1234, "45.6".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFovMax::test 19153fa188ef6bd763235a03048771d1a1d824c1aeaf64841b7e6e70c35813ae translated
#[test]
fn get_cam_fov_max() {
assert_eq!(
camera_query("@getcam_fovmax=1234"),
(true, vec![(1234, "130".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamZoomMin::test 8cd72b3f1922b913c6bde59b928f362fa191574dc1df3cfb4668d4ccf00515a9 translated
#[test]
fn get_cam_zoom_min() {
assert_eq!(
camera_query("@getcam_zoommin=1234"),
(true, vec![(1234, "12.34".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFov::test f4031d095b9a7e87d1f1d94e52c15c3c9b2b43aa1ba039c83e391e58ea994c40 translated
#[test]
fn get_cam_fov() {
assert_eq!(
camera_query("@getcam_fov=1234"),
(true, vec![(1234, "91.34".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:6e89e27b90f28739 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_zoom_min() {
assert_eq!(
missing_camera_settings("@getcam_zoommin=1234"),
(false, vec![])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:82ff323c4cfaad18 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_fov() {
assert_eq!(missing_camera_settings("@getcam_fov=1234"), (false, vec![]));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:c64b136643c55ed8 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_fov_max() {
assert_eq!(
missing_camera_settings("@getcam_fovmax=1234"),
(false, vec![])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:32ad2cfbbfcf0638 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_av_dist_min() {
assert_eq!(
missing_camera_settings("@getcam_avdistmin=1234"),
(false, vec![])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:21855f1f68a52025 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_av_dist_max() {
assert_eq!(
missing_camera_settings("@getcam_avdistmax=1234"),
(false, vec![])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:065ec3bc69e3f2b0 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_fov_min() {
assert_eq!(
missing_camera_settings("@getcam_fovmin=1234"),
(false, vec![])
);
}

View File

@@ -0,0 +1,119 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/RlvCommonTests.cs.
// Source SHA-256: 1e3e097f189cb39e9204a82d881be38847d696870debe7d62e3ddf13b9951a6f
use libremetaverse_rlv::{RlvAttachmentPoint, RlvCommon};
#[allow(clippy::option_option)]
fn point(item_name: &str) -> (bool, Option<Option<RlvAttachmentPoint>>) {
let mut actual = None;
let found = RlvCommon::try_get_attachment_point_from_item_name(item_name.into(), &mut actual);
(found, actual)
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:7da68a0c44d86b61 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_spine() {
assert_eq!(
point("(spine)"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:d4dfd612ab268dc7 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_repeated_spine() {
assert_eq!(
point("(spine)(spine)"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:58d5bce9d704814b 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_uses_last_known_tag() {
assert_eq!(
point("My (mouth) item (spine) has a lot of tags"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:7c453569c08c0a0f 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_ignores_unknown_tag() {
assert_eq!(
point("My item (l upper leg) and some random unknown tag (unknown)"),
(true, Some(Some(RlvAttachmentPoint::LeftUpperLeg)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:ace2eedabcda99e6 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_avatar_center() {
assert_eq!(
point("Central item (avatar center)"),
(true, Some(Some(RlvAttachmentPoint::AvatarCenter)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:1a967cd76f5fa058 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_root_alias() {
assert_eq!(
point("Central item (root)"),
(true, Some(Some(RlvAttachmentPoint::AvatarCenter)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:f6b796736de6a5d8 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c translated
#[test]
fn attachment_point_uppercase_spine() {
assert_eq!(
point("(SPINE)"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:787d37133953ab32 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c translated
#[test]
fn attachment_point_titlecase_spine() {
assert_eq!(
point("(Spine)"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:d2056032186a0a97 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c translated
#[test]
fn attachment_point_titlecase_avatar_center() {
assert_eq!(
point("Central item (Avatar center)"),
(true, Some(Some(RlvAttachmentPoint::AvatarCenter)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:c1f038c1236211aa cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c translated
#[test]
fn attachment_point_lowercase_left_upper_leg() {
assert_eq!(
point("Another item (l upper leg)"),
(true, Some(Some(RlvAttachmentPoint::LeftUpperLeg)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:564c3e282f3b402f c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34 translated
#[test]
fn attachment_point_rejects_unknown_tags() {
assert_eq!(point("(unknown)(hand tag)(spine tag)"), (false, None));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:1d03935868fa6124 c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34 translated
#[test]
fn attachment_point_rejects_untagged_name() {
assert_eq!(point("Hat"), (false, None));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:12ae32cb1ec02d01 c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34 translated
#[test]
fn attachment_point_rejects_empty_name() {
assert_eq!(point(""), (false, None));
}

View File

@@ -0,0 +1,115 @@
//! Exact Rust translations of `DetachAllCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
use libremetaverse_types::compat::Guid;
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const FANCY: &str = "d1111111-dddd-4ddd-8ddd-dddddddddddd";
#[derive(Clone, Copy)]
enum Setup {
Default,
Restricted,
PrivateTarget,
PrivateSubfolder,
NoStripFolder,
NoStripLink,
NoStripItem,
}
fn run(setup: Setup) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
tree.retro_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.retro_pants
.set_attached_prim_id(Some(Some(guid("11111111-0002-4aaa-8aaa-ffffffffffff"))));
tree.glasses.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Pants)));
if !matches!(setup, Setup::NoStripItem) {
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid("11111111-0003-4aaa-8aaa-ffffffffffff"))));
}
match setup {
Setup::PrivateTarget => tree.clothing.set_name(".clothing".into()),
Setup::PrivateSubfolder => {
tree.clothing.set_name(".clothing".into());
tree.hats.set_name(".hats".into());
}
Setup::NoStripFolder | Setup::NoStripLink => {
tree.clothing.set_name(".clothing".into());
tree.hats.set_name("nostrip hats".into());
}
Setup::NoStripItem => tree.happy_shirt.set_name("nostrip Happy Shirt".into()),
_ => {}
}
if matches!(setup, Setup::NoStripLink) {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid("11111111-0004-4aaa-8aaa-ffffffffffff"))));
tree.fancy_hat.set_is_link(true);
}
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
if matches!(setup, Setup::Restricted) {
block_on(h.process("@detachthis:Clothing=n")).unwrap();
}
let path = if matches!(
setup,
Setup::PrivateTarget | Setup::PrivateSubfolder | Setup::NoStripFolder | Setup::NoStripLink
) {
".clothing"
} else {
"Clothing"
};
block_on(h.process(&format!("@detachall:{path}=force"))).unwrap();
let mut result = h.actions.lock().unwrap().detachments[0].clone();
result.sort_by_key(|id| id.0);
result
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut v: Vec<_> = values.iter().map(|s| guid(s)).collect();
v.sort_by_key(|id| id.0);
v
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive::test 45405dbca6c2b8bb9f439736d53c2ff60056252f4cdf6296bedcc14d2be9248e translated
#[test]
fn detach_all_recursive() {
assert_eq!(run(Setup::Default), ids(&[FANCY, HAPPY, RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_EnforceRestrictions::test 6186f5923009fb984daef726e8df44aff7cb65f74c2e381dd8cc9968f5534e43 translated
#[test]
fn detach_all_enforces_restrictions() {
assert_eq!(run(Setup::Restricted), ids(&[FANCY]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_PrivateTargetDir::test 300a323967b6258d1202190bbd3de7b91699231f7a5afa86204ba627cb61215f translated
#[test]
fn detach_all_private_target() {
assert_eq!(run(Setup::PrivateTarget), ids(&[FANCY, HAPPY, RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_PrivateSubFolders::test e688b64d13f0a07f4bfeae0715fbfbf98c1d1fa64b0aefbd0e4e3d3d4dd98eee translated
#[test]
fn detach_all_skips_private_subfolders() {
assert_eq!(run(Setup::PrivateSubfolder), ids(&[HAPPY, RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripSubFolders::test 22cf1a159861c98c8a0f14ac63bafcbef21466c2ac01e615fe9ca4630d16f956 translated
#[test]
fn detach_all_honors_nostrip_subfolders() {
assert_eq!(run(Setup::NoStripFolder), ids(&[HAPPY, RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripSubFolders_LinkException::test cbe38368a6d4c59d72291195688d0c70898be5c3cceb02f09c5d386c3668fb07 translated
#[test]
fn detach_all_honors_link_exception() {
assert_eq!(run(Setup::NoStripLink), ids(&[HAPPY, RETRO, FANCY]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripItemName::test ea0fab47cb1829338948f605919fcf1dca4f88d7965cdca4c7f457e399e4fbfc translated
#[test]
fn detach_all_honors_nostrip_item() {
assert_eq!(run(Setup::NoStripItem), ids(&[RETRO]));
}

View File

@@ -0,0 +1,226 @@
//! Exact Rust translations of `DetachAllThisCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
use libremetaverse_types::compat::Guid;
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const GLASSES: &str = "c1111111-cccc-4ccc-8ccc-cccccccccccc";
const FANCY: &str = "d1111111-dddd-4ddd-8ddd-dddddddddddd";
const PRIM1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
#[derive(Clone, Copy)]
enum Setup {
Normal,
NoStrip,
NoStripLink,
Point,
PointNoStrip,
PointLink,
Wearable,
WearableNoStrip,
WearableLink,
WearablePrivate,
}
fn attach(item: &mut libremetaverse_rlv::RlvInventoryItem, point: RlvAttachmentPoint, prim: &str) {
item.set_attached_to(Some(Some(point)));
item.set_attached_prim_id(Some(Some(guid(prim))));
}
fn run(command: &str, setup: Setup, sender_item: bool) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
attach(
&mut tree.retro_pants,
RlvAttachmentPoint::Pelvis,
"11111111-0002-4aaa-8aaa-ffffffffffff",
);
attach(
&mut tree.fancy_hat,
RlvAttachmentPoint::Chin,
"11111111-0003-4aaa-8aaa-ffffffffffff",
);
if matches!(
setup,
Setup::Wearable | Setup::WearableNoStrip | Setup::WearableLink | Setup::WearablePrivate
) {
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.glasses.set_worn_on(Some(Some(RlvWearableType::Pants)));
} else {
attach(&mut tree.happy_shirt, RlvAttachmentPoint::Chest, PRIM1);
attach(
&mut tree.glasses,
RlvAttachmentPoint::Chest,
"11111111-0004-4aaa-8aaa-ffffffffffff",
);
}
if matches!(
setup,
Setup::NoStrip
| Setup::NoStripLink
| Setup::PointNoStrip
| Setup::PointLink
| Setup::WearableNoStrip
| Setup::WearableLink
) {
tree.hats.set_name("nostrip Hats".into());
tree.retro_pants.set_name("nostrip Retro Pants".into());
}
if matches!(
setup,
Setup::NoStripLink | Setup::PointLink | Setup::WearableLink
) {
tree.fancy_hat.set_is_link(true);
attach(
&mut tree.party_hat,
RlvAttachmentPoint::Chin,
"11111111-0005-4aaa-8aaa-ffffffffffff",
);
}
if matches!(setup, Setup::WearablePrivate) {
tree.hats.set_name(".hats".into());
}
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
if sender_item {
block_on(h.process_from(command, PRIM1, "Happy Shirt")).unwrap();
} else {
block_on(h.process(command)).unwrap();
}
let mut v = h.actions.lock().unwrap().detachments[0].clone();
v.sort_by_key(|id| id.0);
v
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut v: Vec<_> = values.iter().map(|s| guid(s)).collect();
v.sort_by_key(|id| id.0);
v
}
fn normal() -> Vec<Guid> {
ids(&[HAPPY, RETRO, FANCY])
}
fn nostrip() -> Vec<Guid> {
ids(&[HAPPY])
}
fn link() -> Vec<Guid> {
ids(&[HAPPY, FANCY])
}
fn selected() -> Vec<Guid> {
ids(&[HAPPY, RETRO, GLASSES, FANCY])
}
fn selected_nostrip() -> Vec<Guid> {
ids(&[HAPPY, GLASSES])
}
fn selected_link() -> Vec<Guid> {
ids(&[HAPPY, GLASSES, FANCY])
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Default::test 8fe4eacf8cc5841e638d69540e2ab080efc3e64534346ece854429d0476f8a84 translated
#[test]
fn detach_all_this_default() {
assert_eq!(run("@detachallthis=force", Setup::Normal, true), normal());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Nostrip::test 754bd01f2f0b77c05ee5d1548f76337da93d980a48ad0922d80f34707c4fe68b translated
#[test]
fn detach_all_this_honors_nostrip() {
assert_eq!(run("@detachallthis=force", Setup::NoStrip, true), nostrip());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Nostrip_LinkException::test 0cce15f7cfda160733c305b0867be31875e1814b38e2e980525d960e0214ad51 translated
#[test]
fn detach_all_this_honors_link_exception() {
assert_eq!(
run("@detachallthis=force", Setup::NoStripLink, true),
link()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById::test 2f657ffed317d4d7f97f6111942ea8214996872da6294f7c66d07890647f7f63 translated
#[test]
fn detach_all_this_by_id() {
assert_eq!(
run(
&format!("@detachallthis:{PRIM1}=force"),
Setup::Normal,
false
),
normal()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById_Nostrip::test 48ab7aec02efd652478ca3110dd39011fd9b79a1e0a1336f53e9f77b2f56e635 translated
#[test]
fn detach_all_this_by_id_honors_nostrip() {
assert_eq!(
run(
&format!("@detachallthis:{PRIM1}=force"),
Setup::NoStrip,
false
),
nostrip()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById_Nostrip_LinkException::test 5d882f00bfe73cecfc3e96c26ff18a20c00481619996b25ed2ce851eff9a86ce translated
#[test]
fn detach_all_this_by_id_honors_link_exception() {
assert_eq!(
run(
&format!("@detachallthis:{PRIM1}=force"),
Setup::NoStripLink,
false
),
link()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint::test 30e6806d5c484bf2a2f9a3b1fcdb5e88272874b0e755462c3b0bfa97326d180c translated
#[test]
fn detach_all_this_by_attachment_point() {
assert_eq!(
run("@detachallthis:chest=force", Setup::Point, false),
selected()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint_NoStrip::test 657125be7aec668f72e744cc87cae38f022c8ccf9e8980c8ef4bea7e0557fdd1 translated
#[test]
fn detach_all_this_by_attachment_point_honors_nostrip() {
assert_eq!(
run("@detachallthis:chest=force", Setup::PointNoStrip, false),
selected_nostrip()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint_NoStrip_LinkException::test fe019191a9a3df9a43fd500db775ba5f874f4b767096365cba390480b2b2189f translated
#[test]
fn detach_all_this_by_attachment_point_honors_link_exception() {
assert_eq!(
run("@detachallthis:chest=force", Setup::PointLink, false),
selected_link()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType::test ccf302d870f323790af63873fcbb172f084c4e7400a728e480378706b5fb9947 translated
#[test]
fn detach_all_this_by_wearable() {
assert_eq!(
run("@detachallthis:pants=force", Setup::Wearable, false),
selected()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_NoStrip::test 1947e7c9cfe8bb931ee7ad50c6f505515feeb9d30b236702a2d68fb4734a30f0 translated
#[test]
fn detach_all_this_by_wearable_honors_nostrip() {
assert_eq!(
run("@detachallthis:pants=force", Setup::WearableNoStrip, false),
selected_nostrip()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_NoStrip_LinkException::test 50ec101ab557e78d947ac7f9878acd4df4957482f358a7ce02371df8754add94 translated
#[test]
fn detach_all_this_by_wearable_honors_link_exception() {
assert_eq!(
run("@detachallthis:pants=force", Setup::WearableLink, false),
selected_link()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_PrivateFolder::test 2ba745b093f0348d8754f74073c6a6a0f18383b5ce4a73721b39b01f0306a994 translated
#[test]
fn detach_all_this_by_wearable_skips_private_folder() {
assert_eq!(
run("@detachallthis:pants=force", Setup::WearablePrivate, false),
ids(&[HAPPY, RETRO, GLASSES])
);
}

View File

@@ -0,0 +1,81 @@
//! Exact Rust translations of `DetachMeCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint};
use libremetaverse_types::compat::Guid;
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const PRIM2: &str = "11111111-0002-4aaa-8aaa-ffffffffffff";
const PRIM3: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
fn run(nostrip: bool, copy: bool, locked: bool) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
if nostrip {
tree.clothing.set_name("nostrip Clothing".into());
tree.retro_pants.set_name("nostrip Retro Pants".into());
}
tree.retro_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.retro_pants
.set_attached_prim_id(Some(Some(guid(PRIM2))));
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Spine)));
tree.happy_shirt
.set_attached_prim_id(Some(Some(guid(PRIM3))));
if copy {
tree.hats
.add_item(
guid(RETRO),
if nostrip {
"nostrip Retro Pants"
} else {
"Retro Pants"
}
.into(),
false,
Some(Some(RlvAttachmentPoint::Pelvis)),
Some(Some(guid(PRIM2))),
None,
None,
)
.unwrap();
}
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
if locked {
block_on(h.process("@detachthis:Clothing/Hats=n")).unwrap();
}
block_on(h.process_from(
"@detachme=force",
PRIM2,
if nostrip {
"nostrip Retro Pants"
} else {
"Retro Pants"
},
))
.unwrap();
h.actions.lock().unwrap().detachments[0].clone()
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce::test fde065233689ec75c12e9607acf06c5859a91efea58e143ecc508ebec784a567 translated
#[test]
fn detach_me() {
assert_eq!(run(false, false, false), vec![guid(RETRO)]);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_WithNoStripItemName_SpecialException::test ee511230131312be9b788033aac8766ea3cb3c1f8d7c5b9b26a4bd6a83cd695c translated
#[test]
fn detach_me_ignores_nostrip() {
assert_eq!(run(true, false, false), vec![guid(RETRO)]);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_WithLockedFolderRestriction::test 05fefae0563306af0c491006f18915ff1b250b7972c82c160f20f06e07335887 translated
#[test]
fn detach_me_honors_locked_linked_folder() {
assert!(run(false, true, true).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_MultipleLinksSameItem::test 1ae8a318762625819371fb109fd673e0d31a2c0354add1e65802eb54cb71e303 translated
#[test]
fn detach_me_deduplicates_multiple_links() {
assert_eq!(run(false, true, false), vec![guid(RETRO)]);
}

View File

@@ -0,0 +1,229 @@
//! Exact Rust translations of `DetachThisCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
use libremetaverse_types::compat::Guid;
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const GLASSES: &str = "c1111111-cccc-4ccc-8ccc-cccccccccccc";
const PRIM1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
#[derive(Clone, Copy)]
enum Setup {
Normal,
NoStripItem,
NoStripFolder,
NoStripLink,
Point,
PointNoStrip,
PointLink,
Wearable,
WearableNoStrip,
WearableLink,
WearablePrivate,
}
fn attach(item: &mut libremetaverse_rlv::RlvInventoryItem, point: RlvAttachmentPoint, prim: &str) {
item.set_attached_to(Some(Some(point)));
item.set_attached_prim_id(Some(Some(guid(prim))));
}
fn run(command: &str, setup: Setup, sender_item: bool) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
attach(
&mut tree.retro_pants,
RlvAttachmentPoint::Pelvis,
"11111111-0002-4aaa-8aaa-ffffffffffff",
);
attach(
&mut tree.fancy_hat,
RlvAttachmentPoint::Chin,
"11111111-0003-4aaa-8aaa-ffffffffffff",
);
if matches!(
setup,
Setup::Wearable | Setup::WearableNoStrip | Setup::WearableLink | Setup::WearablePrivate
) {
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.glasses.set_worn_on(Some(Some(RlvWearableType::Pants)));
} else {
attach(&mut tree.happy_shirt, RlvAttachmentPoint::Chest, PRIM1);
attach(
&mut tree.glasses,
RlvAttachmentPoint::Chest,
"11111111-0004-4aaa-8aaa-ffffffffffff",
);
}
match setup {
Setup::NoStripItem | Setup::PointNoStrip | Setup::WearableNoStrip => {
tree.happy_shirt.set_name("nostrip Happy Shirt".into());
}
_ => {}
}
if matches!(setup, Setup::NoStripFolder | Setup::NoStripLink) {
tree.clothing.set_name("nostrip Clothing".into());
}
if matches!(
setup,
Setup::PointNoStrip | Setup::PointLink | Setup::WearableNoStrip | Setup::WearableLink
) {
tree.accessories.set_name("nostrip Accessories".into());
}
if matches!(setup, Setup::NoStripLink) {
tree.retro_pants.set_is_link(true);
}
if matches!(setup, Setup::PointLink | Setup::WearableLink) {
tree.glasses.set_is_link(true);
}
if matches!(setup, Setup::WearablePrivate) {
tree.clothing.set_name(".clothing".into());
}
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
if sender_item {
block_on(h.process_from(command, PRIM1, "Happy Shirt")).unwrap();
} else {
block_on(h.process(command)).unwrap();
}
let mut result = h.actions.lock().unwrap().detachments[0].clone();
result.sort_by_key(|id| id.0);
result
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut v: Vec<_> = values.iter().map(|s| guid(s)).collect();
v.sort_by_key(|id| id.0);
v
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_Default::test ae8c0fd737f869ef3e2dbd97ae28974b35c6bbc5327151c0074d531efdaaf54e translated
#[test]
fn detach_this_default() {
assert_eq!(
run("@detachthis=force", Setup::Normal, true),
ids(&[HAPPY, RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStrip::test 3aa17222f7539814f8329e07de548cca4bb702f4b0409e793ea551327b0c57d0 translated
#[test]
fn detach_this_honors_item_nostrip() {
assert_eq!(
run("@detachthis=force", Setup::NoStripItem, true),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStripFolder::test 16b74c3bf8312ccb885e61f933ec9d292988d2e1fad05e0188006df5630681f8 translated
#[test]
fn detach_this_honors_folder_nostrip() {
assert!(run("@detachthis=force", Setup::NoStripFolder, true).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStripFolder_LinkException::test b86b22a0ab30d0ded0cd6fbc7d34fae77e521861f5672b44a25a77325e594ab4 translated
#[test]
fn detach_this_honors_folder_link_exception() {
assert_eq!(
run("@detachthis=force", Setup::NoStripLink, true),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById::test 3c4a211e5fefb44b42f50f6e6e58f8f852c8cf2d732bb6c3f737c3d6a592fa22 translated
#[test]
fn detach_this_by_id() {
assert_eq!(
run(&format!("@detachthis:{PRIM1}=force"), Setup::Normal, false),
ids(&[HAPPY, RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripItemName::test f32926ca6f4328afdd3ddeb9f7bec8ff2ee01e9563555921ac8c663d20005551 translated
#[test]
fn detach_this_by_id_honors_item_nostrip() {
assert_eq!(
run(
&format!("@detachthis:{PRIM1}=force"),
Setup::NoStripItem,
false
),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripFolderName::test bec3216bf016c2543a3410b069abd786167e04a7527253887f158127644656a8 translated
#[test]
fn detach_this_by_id_honors_folder_nostrip() {
assert!(
run(
&format!("@detachthis:{PRIM1}=force"),
Setup::NoStripFolder,
false
)
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripFolderName_LinkException::test 1b5eb3a0bdef8ea65b800533ab3153dc6b3ea21d2f4f27e4820d0a0df48891a2 translated
#[test]
fn detach_this_by_id_honors_link_exception() {
assert_eq!(
run(
&format!("@detachthis:{PRIM1}=force"),
Setup::NoStripLink,
false
),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint::test 7e8f3a4d8b2cbdb5cc81eea598da6ef6395834b1cb7a629dc8d7ee2bfd80fab5 translated
#[test]
fn detach_this_by_attachment_point() {
assert_eq!(
run("@detachthis:chest=force", Setup::Point, false),
ids(&[HAPPY, RETRO, GLASSES])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint_NoStrip::test f6ff482bdb8d28414e01952201e37e49316b3e2345b0ff85dd4cb059193d1816 translated
#[test]
fn detach_this_by_attachment_point_honors_nostrip() {
assert_eq!(
run("@detachthis:chest=force", Setup::PointNoStrip, false),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint_NoStrip_LinkException::test 289f8cc48f0e6a412d58258876e4aca08d8116d549642a0011bbdaf9b2223e83 translated
#[test]
fn detach_this_by_attachment_point_honors_link_exception() {
assert_eq!(
run("@detachthis:chest=force", Setup::PointLink, false),
ids(&[RETRO, GLASSES])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType::test 51607294f12279974c2b44b47ba2eadca9846180a39bcde6a28c020dc4466254 translated
#[test]
fn detach_this_by_wearable() {
assert_eq!(
run("@detachthis:pants=force", Setup::Wearable, false),
ids(&[HAPPY, RETRO, GLASSES])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_NoStrip::test 30dec183993b2a644c2812ffc1c863e1714df134942f7827df818d9200e47c38 translated
#[test]
fn detach_this_by_wearable_honors_nostrip() {
assert_eq!(
run("@detachthis:pants=force", Setup::WearableNoStrip, false),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_NoStrip_LinkException::test 62f59cf66f21dcac15cf3166dcec2183181c0b434e9eacba796eb7025c4f1ab3 translated
#[test]
fn detach_this_by_wearable_honors_link_exception() {
assert_eq!(
run("@detachthis:pants=force", Setup::WearableLink, false),
ids(&[RETRO, GLASSES])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_PrivateFolder::test dd40588598bd081189e7c4f284af3851a140155e2ede0ae2121dd59a156dc988 translated
#[test]
fn detach_this_by_wearable_skips_private_folder() {
assert_eq!(
run("@detachthis:pants=force", Setup::WearablePrivate, false),
ids(&[GLASSES])
);
}

View File

@@ -0,0 +1,743 @@
// Exact Rust translations of the non-folder RLV exception tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SENDER_ID, guid};
use libremetaverse_rlv::{
RlvPermissionsServiceObjectLocation as ObjectLocation,
RlvPermissionsServiceTouchLocation as TouchLocation,
};
const USER_1: &str = "00000000-0000-4000-8000-000000000000";
const USER_2: &str = "11111111-1111-4111-8111-111111111111";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process(h: &RlvHarness, commands: &[String]) {
for command in commands {
block_on(h.process(command)).unwrap();
}
}
#[allow(clippy::option_option)]
fn touch_matches(
h: &RlvHarness,
location: TouchLocation,
object: libremetaverse_types::compat::Guid,
user: Option<Option<libremetaverse_types::compat::Guid>>,
distance: Option<Option<f32>>,
expected: bool,
) -> bool {
h.service
.permissions()
.can_touch(location, object, user, distance)
.unwrap()
== expected
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptPermissionExceptionTests.cs::AcceptPermissionExceptionTests.AcceptPermission::test a5ffc51718e89fb872c6df8b8667f6d231618d47a2ffc71d596e8e10e15cb02e translated
#[test]
fn accept_permission_add_and_remove() {
let h = harness();
assert!(block_on(h.process("@acceptpermission=add")).unwrap());
assert!(
h.service
.permissions()
.is_auto_accept_permissions()
.unwrap()
);
assert!(block_on(h.process("@acceptpermission=rem")).unwrap());
assert!(
!h.service
.permissions()
.is_auto_accept_permissions()
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpExceptionTests.cs::AcceptTpExceptionTests.CanAutoAcceptTp_User::test e988496e81a717eae1a96c5501e748a441fa64f637aaa47a6ae7a8d571c30f6e translated
#[test]
fn accept_tp_specific_user() {
let h = harness();
block_on(h.process(&format!("@accepttp:{USER_1}=add"))).unwrap();
let permissions = h.service.permissions();
assert!(
permissions
.is_auto_accept_tp(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!permissions
.is_auto_accept_tp(Some(Some(guid(USER_2))))
.unwrap()
);
assert!(!permissions.is_auto_accept_tp(None).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpExceptionTests.cs::AcceptTpExceptionTests.CanAutoAcceptTp_All::test 428ec184c9d09f6ec57ac3429180f327ed1b79e9d9dea9815df3bb6f0f6244fd translated
#[test]
fn accept_tp_all_users() {
let h = harness();
block_on(h.process("@accepttp=add")).unwrap();
let permissions = h.service.permissions();
assert!(
permissions
.is_auto_accept_tp(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
permissions
.is_auto_accept_tp(Some(Some(guid(USER_2))))
.unwrap()
);
assert!(permissions.is_auto_accept_tp(None).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpRequestExceptionTests.cs::AcceptTpRequestExceptionTests.CanAutoAcceptTpRequest_User::test 3a5af1a55e74b5e75a04abc11826ded17c327ac2ed99ab2a423674fbb0e61f31 translated
#[test]
fn accept_tp_request_specific_user() {
let h = harness();
block_on(h.process(&format!("@accepttprequest:{USER_1}=add"))).unwrap();
let permissions = h.service.permissions();
assert!(
permissions
.is_auto_accept_tp_request(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!permissions
.is_auto_accept_tp_request(Some(Some(guid(USER_2))))
.unwrap()
);
assert!(!permissions.is_auto_accept_tp_request(None).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpRequestExceptionTests.cs::AcceptTpRequestExceptionTests.CanAutoAcceptTpRequest_All::test 8e2cf7c4d17dcec4d7855fc430092699416108966fb5d97c170c13f0bcd04cfe translated
#[test]
fn accept_tp_request_all_users() {
let h = harness();
block_on(h.process("@accepttprequest=add")).unwrap();
let permissions = h.service.permissions();
assert!(
permissions
.is_auto_accept_tp_request(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
permissions
.is_auto_accept_tp_request(Some(Some(guid(USER_2))))
.unwrap()
);
assert!(permissions.is_auto_accept_tp_request(None).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DenyPermissionExceptionTests.cs::DenyPermissionExceptionTests.DenyPermission::test c2284b63e7b4a93f8613a3afe34466d14e1c6ed8528656d54ae64ca6d081cdd5 translated
#[test]
fn deny_permission_add_and_remove() {
let h = harness();
assert!(block_on(h.process("@denypermission=add")).unwrap());
assert!(h.service.permissions().is_auto_deny_permissions().unwrap());
assert!(block_on(h.process("@denypermission=rem")).unwrap());
assert!(!h.service.permissions().is_auto_deny_permissions().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/EditExceptionTests.cs::EditExceptionTests.CanEdit_Exception::test e435b03faef04dfe06d0cbec76e94cbf30e61ad7bc08502728f9239cf47292f8 translated
#[test]
fn edit_exception_allows_one_object() {
let h = harness();
process(&h, &["@edit=n".into(), format!("@edit:{USER_1}=add")]);
let permissions = h.service.permissions();
for location in [
ObjectLocation::Hud,
ObjectLocation::Attached,
ObjectLocation::RezzedInWorld,
] {
assert!(!permissions.can_edit(location, None).unwrap());
assert!(
permissions
.can_edit(location, Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!permissions
.can_edit(location, Some(Some(guid(USER_2))))
.unwrap()
);
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/EditExceptionTests.cs::EditExceptionTests.CanEdit_Specific::test db097167497bc650c6729f0687924adedda7097b4089107fc5ea03716c1cb4e5 translated
#[test]
fn edit_object_restricts_only_one_object() {
let h = harness();
block_on(h.process(&format!("@editobj:{USER_1}=n"))).unwrap();
let permissions = h.service.permissions();
for location in [
ObjectLocation::Hud,
ObjectLocation::Attached,
ObjectLocation::RezzedInWorld,
] {
assert!(permissions.can_edit(location, None).unwrap());
assert!(
!permissions
.can_edit(location, Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
permissions
.can_edit(location, Some(Some(guid(USER_2))))
.unwrap()
);
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/EmoteExceptionTests.cs::EmoteExceptionTests.CanEmote::test a643401539d7258ae04ddebaf9c82876f59c4433b11ee61bfe8b416058c9fe38 translated
#[test]
fn emote_exception_add_and_remove() {
let h = harness();
block_on(h.process("@emote=n")).unwrap();
assert!(!h.service.permissions().can_emote().unwrap());
block_on(h.process("@emote=y")).unwrap();
assert!(h.service.permissions().can_emote().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvChatExceptionTests.cs::RecvChatExceptionTests.CanRecvChat_Except::test b34881785cf2df3d8f4e5ba971adcf2144d8de4db00acfbe136c79457742ec33 translated
#[test]
fn receive_chat_exception_allows_user_chat_and_emote() {
let h = harness();
let user = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
process(&h, &["@recvchat=n".into(), format!("@recvchat:{user}=add")]);
assert!(
h.service
.permissions()
.can_receive_chat("Hello world".into(), guid(user))
.unwrap()
);
assert!(
h.service
.permissions()
.can_receive_chat("/me says Hello world".into(), guid(user))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvEmoteExceptionTests.cs::RecvEmoteExceptionTests.CanRecvChat_RecvEmote_Except::test d4647d71c02e05405ae2acf7b58522aae559b1c90a4f7a1521c9a9a383220f8a translated
#[test]
fn receive_emote_exception_only_allows_selected_user_emotes() {
let h = harness();
process(
&h,
&["@recvemote=n".into(), format!("@recvemote:{USER_1}=add")],
);
let permissions = h.service.permissions();
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
!permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_2))
.unwrap()
);
}
fn im_exception_matches(command: &str, receive: bool, group: Option<&str>) -> bool {
let h = harness();
let behavior = if receive { "recvim" } else { "sendim" };
process(
&h,
&[
format!("@{behavior}=n"),
format!("@{behavior}:{command}=add"),
],
);
let user = Some(Some(guid(USER_1)));
if receive {
h.service
.permissions()
.can_receive_im("Hello world".into(), user, group.map(Into::into))
.unwrap()
} else {
h.service
.permissions()
.can_send_im("Hello world".into(), user, group.map(Into::into))
.unwrap()
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception::test 2e1afba517b29e8e7f2e0605340eb6e87443282857400eba259f0ebdf4874e23 translated
#[test]
fn receive_im_exception_for_user() {
assert!(im_exception_matches(USER_1, true, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception_SingleGroup::test 9ec57daeed225caf960d00f0c83378d1836e86b1896063703ee1c3a38c7b582a translated
#[test]
fn receive_im_exception_for_group() {
assert!(im_exception_matches("Group Name", true, Some("Group Name")));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception_AllGroups::test 633b8c680b583a6f8d80335c26f4ebcec77f9d8d5231e49bea562dcb66f00267 translated
#[test]
fn receive_im_exception_for_all_groups() {
assert!(im_exception_matches("allgroups", true, Some("Group name")));
}
fn redirect_channels_match(command: &str, expected: &[i32], emote: bool) -> bool {
let h = harness();
for channel in expected {
block_on(h.process(&format!("@{command}:{channel}=add"))).unwrap();
}
let mut channels = Vec::new();
let found = if emote {
h.service
.permissions()
.try_get_redir_emote_channels(&mut channels)
} else {
h.service
.permissions()
.try_get_redir_chat_channels(&mut channels)
};
found && channels == expected
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat::test 1eb25c5579789db22ee242c4b52c65989bd26dce6d7577021c329c6c49be9414 translated
#[test]
fn redirect_chat_channel() {
assert!(redirect_channels_match("redirchat", &[1234], false));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_Removed::test 62e03ff1db1e790d8bc1e38ac1495fc12723ba2eb5c9d6035d73c9fdb91a44ad translated
#[test]
fn redirect_chat_channel_removed() {
let h = harness();
process(
&h,
&["@redirchat:1234=add".into(), "@redirchat:1234=rem".into()],
);
assert!(
!h.service
.permissions()
.try_get_redir_chat_channels(&mut Vec::new())
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_MultipleChannels::test c7d0c428d121ab80eee9b6b5855cbe50e7a4cd74e81c369da09df04d55c7554f translated
#[test]
fn redirect_chat_multiple_channels() {
assert!(redirect_channels_match("redirchat", &[1234, 12345], false));
}
fn redirected_message_matches(
command: &str,
message: &str,
channels: &[i32],
expected: &[(i32, &str)],
) -> bool {
let h = harness();
for channel in channels {
block_on(h.process(&format!("@{command}:{channel}=add"))).unwrap();
}
block_on(h.service.report_send_public_message(message.into(), None)).unwrap();
let expected: Vec<_> = expected
.iter()
.map(|(channel, text)| (*channel, (*text).into()))
.collect();
h.actions.lock().unwrap().replies == expected
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChat::test c4a083e495a578c1ed0855c43680d5b05144bf627f06df48c82e089e6f0699bf translated
#[test]
fn redirect_chat_sends_public_message() {
assert!(redirected_message_matches(
"redirchat",
"Hello World",
&[1234],
&[(1234, "Hello World")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChatMultiple::test 5ff8665440d8d02e0aa900121e591034d51e2b48ca62fdec2fbc9135f8c83428 translated
#[test]
fn redirect_chat_sends_to_multiple_channels() {
assert!(redirected_message_matches(
"redirchat",
"Hello World",
&[1234, 5678],
&[(1234, "Hello World"), (5678, "Hello World")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChatEmote::test 5d88009e3e8d365c52315a9b189f6cffdc9d04fdb70aa26bcc03d6bc16227189 translated
#[test]
fn redirect_chat_does_not_redirect_emote() {
assert!(redirected_message_matches(
"redirchat",
"/me says Hello World",
&[1234],
&[]
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote::test 02170a2b3eb0cbb88921517c9742d2fc0baaea7a621e5a3c3264a7a17d5efb61 translated
#[test]
fn redirect_emote_channel() {
assert!(redirect_channels_match("rediremote", &[1234], true));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_Removed::test 6ee89cedfd1e2d79d2447f2f48d1e2d1ac96295485b7509fe09f98e3bfcd9766 translated
#[test]
fn redirect_emote_channel_removed() {
let h = harness();
process(
&h,
&["@rediremote:1234=add".into(), "@rediremote:1234=rem".into()],
);
assert!(
!h.service
.permissions()
.try_get_redir_emote_channels(&mut Vec::new())
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_MultipleChannels::test 1a95f4cc5db96cf033fed0c1a4e573b1cb1ac17ef72b76e0ce115c051f10528a translated
#[test]
fn redirect_emote_multiple_channels() {
assert!(redirect_channels_match("rediremote", &[1234, 12345], true));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmote::test 525297be5b5ff466fc9a61f2bc87af38bd637cbef8e0c794e897e021d0cca464 translated
#[test]
fn redirect_emote_sends_emote() {
assert!(redirected_message_matches(
"rediremote",
"/me says Hello World",
&[1234],
&[(1234, "/me says Hello World")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmoteMultiple::test fd6af49a90e111ed6424c85565242e1205e13604b529909f7be0260e93f0b1c6 translated
#[test]
fn redirect_emote_sends_to_multiple_channels() {
let h = harness();
process(
&h,
&["@rediremote:1234=add".into(), "@rediremote:5678=n".into()],
);
block_on(
h.service
.report_send_public_message("/me says Hello World".into(), None),
)
.unwrap();
assert_eq!(
h.actions.lock().unwrap().replies,
vec![
(1234, "/me says Hello World".into()),
(5678, "/me says Hello World".into()),
]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmoteChat::test e8b78a6a34e3d3acdfc6d454b46a939d341260362ae5327dc4b70164d41431aa translated
#[test]
fn redirect_emote_does_not_redirect_chat() {
assert!(redirected_message_matches(
"rediremote",
"Hello World",
&[1234],
&[]
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendChannelExceptExceptionTests.cs::SendChannelExceptExceptionTests.CanSendChannelExcept::test 08c309d08681fe067f67315a72014d0a05c87d6e14632fa04f6f2fb617d61be3 translated
#[test]
fn send_channel_exception_blocks_only_selected_channel() {
let h = harness();
block_on(h.process("@sendchannel_except:456=add")).unwrap();
assert!(
h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
assert!(
!h.service
.permissions()
.can_chat(456, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendChannelExceptionTests.cs::SendChannelExceptionTests.CanSendChannel_Exception::test 49bcacb6fb31d596ce9afc73099f8aaf645156ee222262174e1d7fed08393cf9 translated
#[test]
fn send_channel_adds_allowed_channel() {
let h = harness();
process(&h, &["@sendchannel=n".into(), "@sendchannel:123=n".into()]);
assert!(
h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception::test 8124011921e8d4caf6840e960bd9f98d21df9db476e1726e0d54550cb8527ceb translated
#[test]
fn send_im_exception_for_user() {
assert!(im_exception_matches(USER_1, false, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception_SingleGroup::test b55a4bdba1d33652f3809c3478047afc65757fbe1dec6c5292e17b71a04b206c translated
#[test]
fn send_im_exception_for_group() {
assert!(im_exception_matches(
"Group Name",
false,
Some("Group Name")
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception_AllGroups::test 4190ff51848f63dce5682317db79da23fa19ad9e53004534382f3eb6e8544788 translated
#[test]
fn send_im_exception_for_all_groups() {
assert!(im_exception_matches("allgroups", false, Some("Group name")));
}
fn nullable_user_exception(
behavior: &str,
permission: fn(
&libremetaverse_rlv::RlvPermissionsService,
Option<Option<libremetaverse_types::compat::Guid>>,
) -> Result<bool, libremetaverse_types::Error>,
) -> [bool; 3] {
let h = harness();
process(
&h,
&[
format!("@{behavior}=n"),
format!("@{behavior}:{USER_1}=add"),
],
);
let permissions = h.service.permissions();
[
permission(&permissions, None).unwrap(),
permission(&permissions, Some(Some(guid(USER_1)))).unwrap(),
permission(&permissions, Some(Some(guid(USER_2)))).unwrap(),
]
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShareExceptionTests.cs::ShareExceptionTests.CanShare_Except::test 37297059a814bfde94c466e263a429258cce11ae258afd7953d26f65f9178f1d translated
#[test]
fn share_exception_for_user() {
assert_eq!(
nullable_user_exception(
"share",
libremetaverse_rlv::RlvPermissionsService::can_share,
),
[false, true, false]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShowNameTagsExceptionTests.cs::ShowNameTagsExceptionTests.CanShowNameTags_Except::test 5d1fe4ec1fa289623d473ffae1682ed725735cbdf48bdf5b7fed086237e32a1a translated
#[test]
fn show_name_tags_exception_for_user() {
assert_eq!(
nullable_user_exception(
"shownametags",
libremetaverse_rlv::RlvPermissionsService::can_show_name_tags,
),
[false, true, false]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShowNamesExceptionTests.cs::ShowNamesExceptionTests.CanShowNames_Except::test b11578e758631037440dd56a683a3ffc25b576eaa25e7388c950d8d647eb2a75 translated
#[test]
fn show_names_exception_for_user() {
assert_eq!(
nullable_user_exception(
"shownames",
libremetaverse_rlv::RlvPermissionsService::can_show_names,
),
[false, true, false]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/StartImExceptionTests.cs::StartImExceptionTests.CanStartIM_Exception::test e0001ffc665f0f39833cf2376ea1fcb7559bdb87a48ea60bb348e14b078880e4 translated
#[test]
fn start_im_exception_for_user() {
let h = harness();
process(&h, &["@startim=n".into(), format!("@startim:{USER_1}=add")]);
assert!(h.service.permissions().can_start_im(guid(USER_1)).unwrap());
assert!(!h.service.permissions().can_start_im(guid(USER_2)).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchMeExceptionTests.cs::TouchMeExceptionTests.TouchMe_default::test a0f3ffd3c70263738c074e258d9271e0a825f163c40d9c7ee8d20865873eb304 translated
#[test]
fn touch_me_exception_allows_sender_and_hud() {
let h = harness();
process(&h, &["@touchall=n".into(), "@touchme=add".into()]);
let object = guid(USER_1);
let sender = guid(SENDER_ID);
let user = Some(Some(guid("55555555-5555-4555-8555-555555555555")));
assert!(touch_matches(
&h,
TouchLocation::AttachedSelf,
object,
None,
None,
false
));
assert!(touch_matches(
&h,
TouchLocation::AttachedOther,
object,
user,
None,
false
));
assert!(touch_matches(
&h,
TouchLocation::RezzedInWorld,
object,
None,
Some(Some(5.0)),
false,
));
assert!(touch_matches(
&h,
TouchLocation::Hud,
object,
None,
None,
true
));
for (location, callback_user, distance) in [
(TouchLocation::AttachedSelf, None, None),
(TouchLocation::AttachedOther, user, None),
(TouchLocation::RezzedInWorld, None, Some(Some(5.0))),
(TouchLocation::Hud, None, None),
] {
assert!(touch_matches(
&h,
location,
sender,
callback_user,
distance,
true
));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchThisExceptionTests.cs::TouchThisExceptionTests.TouchThis_default::test e7e6c9e14badb0159f81adc96e17fcf3ebe2cf5351ec6465f03c430de06d85d2 translated
#[test]
fn touch_this_exception_blocks_only_selected_prim() {
let h = harness();
block_on(h.process(&format!("@touchthis:{USER_1}=add"))).unwrap();
let user = Some(Some(guid("55555555-5555-4555-8555-555555555555")));
for (location, callback_user, distance) in [
(TouchLocation::AttachedSelf, None, None),
(TouchLocation::AttachedOther, user, None),
(TouchLocation::RezzedInWorld, None, Some(Some(5.0))),
(TouchLocation::Hud, None, None),
] {
assert!(touch_matches(
&h,
location,
guid(USER_1),
callback_user,
distance,
false
));
assert!(touch_matches(
&h,
location,
guid(USER_2),
callback_user,
distance,
true
));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchWorldExceptionTests.cs::TouchWorldExceptionTests.TouchWorld_Exception::test ffef2f112b5718bab7b01fc1b624e588c181dadc5c50fd85de4404a501ee6f37 translated
#[test]
fn touch_world_exception_allows_selected_world_prim() {
let h = harness();
process(
&h,
&["@touchworld=n".into(), format!("@touchworld:{USER_2}=add")],
);
let user = Some(Some(guid("55555555-5555-4555-8555-555555555555")));
assert!(touch_matches(
&h,
TouchLocation::AttachedSelf,
guid(USER_1),
None,
None,
true,
));
assert!(touch_matches(
&h,
TouchLocation::AttachedOther,
guid(USER_1),
user,
None,
true,
));
assert!(touch_matches(
&h,
TouchLocation::RezzedInWorld,
guid(USER_1),
None,
Some(Some(5.0)),
false,
));
assert!(touch_matches(
&h,
TouchLocation::Hud,
guid(USER_1),
None,
None,
true
));
for (location, callback_user, distance) in [
(TouchLocation::AttachedSelf, None, None),
(TouchLocation::AttachedOther, user, None),
(TouchLocation::RezzedInWorld, None, Some(Some(5.0))),
(TouchLocation::Hud, None, None),
] {
assert!(touch_matches(
&h,
location,
guid(USER_2),
callback_user,
distance,
true
));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/TpLureExceptionTests.cs::TpLureExceptionTests.CanTpLure_Except::test a32f4cdda5b48ffcaced683b2e77fc129c1c321951aa2e16623eea022f2aa0b9 translated
#[test]
fn tp_lure_exception_for_user() {
assert_eq!(
nullable_user_exception(
"tplure",
libremetaverse_rlv::RlvPermissionsService::can_tp_lure,
),
[false, true, false]
);
}

View File

@@ -0,0 +1,253 @@
// Exact Rust translations of the recursive folder exception tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint};
const PRIM: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
const HATS_EXCEPTED: [bool; 7] = [true, true, false, false, false, true, true];
const CLOTHING_EXCEPTED: [bool; 7] = [true; 7];
const NO_EXCEPTIONS: [bool; 7] = [false, false, false, false, false, true, true];
#[derive(Clone, Copy)]
enum Mode {
Attach,
Detach,
}
fn exception_case_matches(
commands: &[&str],
mode: Mode,
expected_items: [bool; 7],
expected_exception_counts: Option<[usize; 3]>,
) -> bool {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().expect("sample inventory tree");
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM))));
let folder_ids = [tree.clothing.id(), tree.hats.id(), tree.sub_hats.id()];
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
for command in commands {
if !block_on(h.process_from(command, PRIM, "Business Pants (Pelvis)")).unwrap() {
return false;
}
}
let permissions = h.service.permissions();
let actual = match mode {
Mode::Attach => [
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.party_hat, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.business_pants, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.retro_pants, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.glasses, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.watch, true)
.unwrap(),
],
Mode::Detach => [
permissions
.can_detach_with_rlv_inventory_item(tree.party_hat)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.business_pants)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.happy_shirt)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.retro_pants)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.glasses)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap(),
],
};
if actual != expected_items {
return false;
}
if let Some(expected_counts) = expected_exception_counts {
let locked = h.service.restrictions().get_locked_folders().unwrap();
if locked.len() != 3 {
return false;
}
for (index, id) in folder_ids.iter().enumerate() {
let Some(folder) = locked.get(id) else {
return false;
};
let matches = folder.is_locked()
&& match mode {
Mode::Attach => {
folder.attach_exceptions().len() == expected_counts[index]
&& folder.attach_restrictions().len() == 1
&& folder.detach_exceptions().is_empty()
&& folder.detach_restrictions().is_empty()
}
Mode::Detach => {
folder.attach_exceptions().is_empty()
&& folder.attach_restrictions().is_empty()
&& folder.detach_exceptions().len() == expected_counts[index]
&& folder.detach_restrictions().len() == 1
}
};
if !matches {
return false;
}
}
}
true
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll::test 1daa414beb2a767518f335f6ae59e711395375ed9d7912fbbc139fa0998dfdb1 translated
#[test]
fn attach_all_this_except_subtree() {
assert!(exception_case_matches(
&[
"@attachallthis=n",
"@attachallthis_except:Clothing/Hats=add",
],
Mode::Attach,
HATS_EXCEPTED,
Some([0, 1, 1]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll_Recursive::test 6e0c78d6ed78bedca9a8c6a9a83fd9f90f7123da433eb4c560e6f5c0b6fe6d94 translated
#[test]
fn attach_all_this_except_recursive_subtree() {
assert!(exception_case_matches(
&["@attachallthis=n", "@attachallthis_except:Clothing=add"],
Mode::Attach,
CLOTHING_EXCEPTED,
Some([1, 1, 1]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll_Recursive_AddRem::test 9423ed205501604501d31909414ecf6ef99a0d56d4efae100f5576b31b71a858 translated
#[test]
fn attach_all_this_recursive_exception_removed() {
assert!(exception_case_matches(
&[
"@attachallthis=n",
"@attachallthis_except:Clothing=add",
"@attachallthis_except:Clothing=rem",
],
Mode::Attach,
NO_EXCEPTIONS,
Some([0, 0, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachThisExceptExceptionTests.cs::AttachThisExceptExceptionTests.AttachThisExcept_Default::test b8e6e55d8f2654429c9826e38ffc8522eec44ab2521891b68616db61ac662db0 translated
#[test]
fn attach_this_except_folder() {
assert!(exception_case_matches(
&["@attachallthis=n", "@attachthis_except:Clothing/Hats=add"],
Mode::Attach,
HATS_EXCEPTED,
Some([0, 1, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachThisExceptExceptionTests.cs::AttachThisExceptExceptionTests.AttachThisExcept_AddRem::test 05bc7eab5dd02a0a3e60f85eb51b374623aaa29c9ce2b522748a3478b8ee44ea translated
#[test]
fn attach_this_exception_removed() {
assert!(exception_case_matches(
&[
"@attachallthis=n",
"@attachthis_except:Clothing/Hats=add",
"@attachthis_except:Clothing/Hats=rem",
],
Mode::Attach,
NO_EXCEPTIONS,
Some([0, 0, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll::test 75e7ab22f6d9d058580fd83741d65f7e5babb7ad54805eaeb16bec8cd65370ed translated
#[test]
fn detach_all_this_except_subtree() {
assert!(exception_case_matches(
&[
"@detachallthis=n",
"@detachallthis_except:Clothing/Hats=add",
],
Mode::Detach,
HATS_EXCEPTED,
None,
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll_Recursive::test 3fb8bb13d6a917d9be18265d90767488cde66746badc6584025bbbaf84f020ad translated
#[test]
fn detach_all_this_except_recursive_subtree() {
assert!(exception_case_matches(
&["@detachallthis=n", "@detachallthis_except:Clothing=add"],
Mode::Detach,
CLOTHING_EXCEPTED,
Some([1, 1, 1]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll_Recursive_AddRem::test fb5fd8a4eda181d22d1756ec0cae700c4b90895a74dc79c24c67c1705cfd37c8 translated
#[test]
fn detach_all_this_recursive_exception_removed() {
assert!(exception_case_matches(
&[
"@detachallthis=n",
"@detachallthis_except:Clothing=add",
"@detachallthis_except:Clothing=rem",
],
Mode::Detach,
NO_EXCEPTIONS,
Some([0, 0, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachThisExceptExceptionTests.cs::DetachThisExceptExceptionTests.DetachAllThis_Recursive_Except::test 3222d97d73d8b54bd11212f8cd3de26279040321f0bc330e061ff93880053f3e translated
#[test]
fn detach_this_except_folder() {
assert!(exception_case_matches(
&["@detachallthis=n", "@detachthis_except:Clothing/Hats=add"],
Mode::Detach,
HATS_EXCEPTED,
Some([0, 1, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachThisExceptExceptionTests.cs::DetachThisExceptExceptionTests.DetachAllThis_Recursive_Except_AddRem::test d25b2c533b9b51428c0c2414d687c466a3c80c4a573dd36763504de19e8dc6f8 translated
#[test]
fn detach_this_exception_removed() {
assert!(exception_case_matches(
&[
"@detachallthis=n",
"@detachthis_except:Clothing/Hats=add",
"@detachthis_except:Clothing/Hats=rem",
],
Mode::Detach,
NO_EXCEPTIONS,
Some([0, 0, 0]),
));
}

View File

@@ -0,0 +1,269 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/InventoryMapTests.cs.
use libremetaverse_compat_tests::rlv_support::{SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
fn path_matches(
clothing_name: Option<&str>,
hats_name: Option<&str>,
path: &str,
skip_private: bool,
expected: Option<&str>,
) -> bool {
let mut tree = SampleInventoryTree::build().expect("sample inventory tree");
if let Some(name) = clothing_name {
tree.clothing.set_name(name.into());
}
if let Some(name) = hats_name {
tree.hats.set_name(name.into());
}
let expected_id = expected.map(|folder| match folder {
"clothing" => tree.clothing.id(),
"hats" => tree.hats.id(),
_ => unreachable!(),
});
let map = InventoryMap::new(tree.root, vec![]).unwrap();
let mut found = None;
map.try_get_folder_from_path(path.into(), skip_private, &mut found) == expected_id.is_some()
&& found.map(|folder| folder.id()) == expected_id
}
fn folder_ids(
folders: impl Iterator<Item = libremetaverse_rlv::RlvSharedFolder>,
) -> Vec<libremetaverse_types::compat::Guid> {
let mut ids: Vec<_> = folders.map(|folder| folder.id()).collect();
ids.sort_by_key(|id| id.0);
ids
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_Normal::test 97787ac6b51198e317ed391e91125724ce1b580924c40500f81186812b45f625 translated
#[test]
fn try_get_folder_from_normal_path() {
assert!(path_matches(
None,
None,
"Clothing/Hats",
true,
Some("hats")
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_EmptyPath::test 0ffd4f32e285ba94e94f63ac312d3be20bf144b769e8d18af32e15f481042ed7 translated
#[test]
fn try_get_folder_rejects_empty_path() {
assert!(path_matches(None, None, "", true, None));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameContainsForwardSlash::test 90ae520739ea1a2612f491bb110b0870ed4dcb8a983aad9526ed25d8c5cbe687 translated
#[test]
fn try_get_folder_when_name_contains_slash() {
assert!(path_matches(
Some("Clo/thing"),
None,
"Clo/thing/Hats",
true,
Some("hats"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameContainsForwardSlashes::test 8c0ed3c6cc16b916f9df8d25d55618e82299fd1bcd66983f682219c338853028 translated
#[test]
fn try_get_folder_when_names_contain_multiple_slashes() {
assert!(path_matches(
Some("/Clo//thing//"),
Some("//h/ats/"),
"/Clo//thing/////h/ats/",
true,
Some("hats"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashPrefix::test 8a86081d6b25ae50b3cf8cdcb1c58c8539264931ab74f395dfc7345ee7f4f861 translated
#[test]
fn try_get_folder_with_slash_prefix() {
assert!(path_matches(
Some("/Clothing"),
None,
"/Clothing",
true,
Some("clothing")
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashSuffix::test 04afafa569b7a10d6add8c1e9d8f26ac502791f1da2dbdb3e37407e945c87872 translated
#[test]
fn try_get_folder_with_slash_suffix() {
assert!(path_matches(
Some("Clothing/"),
None,
"Clothing/",
true,
Some("clothing")
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashAffix::test 7eaec38fa6b545f133748b502169fab575308c9c4e60548cfbfd704452bd9761 translated
#[test]
fn try_get_folder_with_slash_affix() {
assert!(path_matches(
Some("/Clothing/"),
None,
"/Clothing/",
true,
Some("clothing"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_ContendingFoldersWithSlashes::test 96a8189266746a564072122342f36b3321998f3e0cbe0094f3e4c83d29bc53d5 translated
#[test]
fn try_get_folder_prefers_exact_slash_match() {
let mut tree = SampleInventoryTree::build().unwrap();
tree.root
.add_child(
guid("12345678-0001-4ddd-8ddd-dddddddddddd"),
"Clothing".into(),
)
.unwrap();
tree.root
.add_child(
guid("12345678-0002-4ddd-8ddd-dddddddddddd"),
"+Clothing///".into(),
)
.unwrap();
tree.root
.add_child(
guid("12345678-0003-4ddd-8ddd-dddddddddddd"),
"+Clothing///".into(),
)
.unwrap();
tree.clothing.set_name("Clothing///".into());
tree.hats.set_name("//h/ats/".into());
let expected = tree.hats.id();
let map = InventoryMap::new(tree.root, vec![]).unwrap();
let mut found = None;
assert!(map.try_get_folder_from_path("Clothing//////h/ats/".into(), true, &mut found,));
assert_eq!(found.unwrap().id(), expected);
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_InvalidPath::test 547def910ded67bc7950b211ad929f775d4eff26e351d11612f146b3e863510e translated
#[test]
fn try_get_folder_rejects_invalid_path() {
assert!(path_matches(None, None, "Clothing/Hats123", true, None));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_IgnoreFolderPrefix::test 5039b79496d215d3921427ab6f65867ba7a4ea5239864f1f5a1e38ea3e5bb426 translated
#[test]
fn try_get_folder_ignores_tilde_and_plus_prefixes() {
assert!(path_matches(
Some("~Clothing"),
Some("+Hats"),
"Clothing/Hats",
true,
Some("hats"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FailOnHiddenFolder::test bb0c7e531584128d251b06a4ac23b8cfad16ec4b117be79a53dea3c54aed4510 translated
#[test]
fn try_get_folder_skips_hidden_folder() {
assert!(path_matches(
Some(".Clothing"),
None,
".Clothing",
true,
None
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_AllowHiddenFolder::test 9217cb5bd9c325fc792303e5ab53cefd71e95a5acf9e5a1601957ba8bf807346 translated
#[test]
fn try_get_folder_allows_hidden_folder() {
assert!(path_matches(
Some(".Clothing"),
None,
".Clothing",
false,
Some("clothing"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ById::test fc89036c3472dcc2ea4d3fcb55636238e3d2c75b490f46d328b5f91f28301ed0 translated
#[test]
fn find_folders_containing_by_prim_id() {
let mut tree = SampleInventoryTree::build().unwrap();
let prim = guid("11111111-0002-4aaa-8aaa-ffffffffffff");
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Spine)));
tree.party_hat.set_attached_prim_id(Some(Some(prim)));
let expected = vec![tree.hats.id()];
let map = InventoryMap::new(tree.root, vec![]).unwrap();
assert_eq!(
folder_ids(
map.find_folders_containing(false, Some(Some(prim)), None, None)
.unwrap()
),
expected
);
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByAttachmentType::test 90b36c29312b87c824c158987e551ca31522cf53a68f5f6bd3eae8fe03e914ed translated
#[test]
fn find_folders_containing_by_attachment_point() {
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.happy_shirt
.set_attached_prim_id(Some(Some(guid("11111111-0001-4aaa-8aaa-ffffffffffff"))));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid("11111111-0003-4aaa-8aaa-ffffffffffff"))));
let mut expected = vec![tree.clothing.id(), tree.hats.id()];
expected.sort_by_key(|id| id.0);
let map = InventoryMap::new(tree.root, vec![]).unwrap();
assert_eq!(
folder_ids(
map.find_folders_containing(false, None, Some(Some(RlvAttachmentPoint::Chin)), None,)
.unwrap()
),
expected
);
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByAttachmentType_SingleResult::test a973bf8087abb0c68cd80d76949fac2735474bf6ccbe743933051f60527d93ce translated
#[test]
fn find_folders_containing_by_attachment_point_single_result() {
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
let expected = vec![tree.hats.id()];
let map = InventoryMap::new(tree.root, vec![]).unwrap();
assert_eq!(
folder_ids(
map.find_folders_containing(true, None, Some(Some(RlvAttachmentPoint::Chin)), None,)
.unwrap()
),
expected
);
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByWearType::test d6712cbeacd6ddf25a1f76dc1eeb10f4c0d8967a7591c249127f9b6387f0df8a translated
#[test]
fn find_folders_containing_by_wearable_type() {
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Hair)));
let expected = vec![tree.clothing.id()];
let map = InventoryMap::new(tree.root, vec![]).unwrap();
assert_eq!(
folder_ids(
map.find_folders_containing(false, None, None, Some(Some(RlvWearableType::Pants)),)
.unwrap()
),
expected
);
}

View File

@@ -0,0 +1,782 @@
//! Exact Rust translations of the RLV inventory-query tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvInventoryItem, RlvWearableType};
const PRIM1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
const PRIM2: &str = "11111111-0002-4aaa-8aaa-ffffffffffff";
const PRIM3: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
const PRIM4: &str = "11111111-0004-4aaa-8aaa-ffffffffffff";
const PRIM5: &str = "11111111-0005-4aaa-8aaa-ffffffffffff";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn install_inventory(h: &RlvHarness, tree: SampleInventoryTree, external: Vec<RlvInventoryItem>) {
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, external).unwrap());
}
fn query_matches(h: &RlvHarness, command: &str, expected: &str) -> bool {
block_on(h.process(command)).unwrap()
&& h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}
fn external_item(
id: &str,
name: &str,
folder: &str,
point: Option<RlvAttachmentPoint>,
prim: Option<&str>,
wearable: Option<RlvWearableType>,
) -> RlvInventoryItem {
RlvInventoryItem::new(
guid(id),
name.into(),
false,
Some(Some(guid(folder))),
point.map(Some),
prim.map(|id| Some(guid(id))),
wearable.map(Some),
None,
)
.unwrap()
}
fn empty_tree_query(command: &str, expected: &str) -> bool {
let h = harness();
install_inventory(&h, SampleInventoryTree::build().unwrap(), vec![]);
query_matches(&h, command, expected)
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_MultipleTerms::test a1f04e5ab064772c25feefc21ea57d65b1044f0fa3254aeb2a3bfedf68d8e0ca translated
#[test]
fn find_folder_multiple_terms() {
assert!(empty_tree_query(
"@findfolder:at&&ub=1234",
"Clothing/Hats/Sub Hats"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_SearchOrder::test 4cba32dd316f49713c18a71bf5a932e1c28c94944add38c25852e8611ef0f987 translated
#[test]
fn find_folder_search_order() {
assert!(empty_tree_query("@findfolder:at=1234", "Clothing/Hats"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_IgnorePrivate::test 54c5ec1f6a6ae5611221e3afdc47db0c2d0ecb0da460dd8f2c506ed34c221ff8 translated
#[test]
fn find_folder_ignores_private_folder() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.hats.set_name(".Hats".into());
install_inventory(&h, tree, vec![]);
assert!(query_matches(&h, "@findfolder:at=1234", ""));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_IgnoreTildePrefix::test 9f6635f5e14dbc14d1592a19b62d67748a60201128a75893e47ea1751c83b6d7 translated
#[test]
fn find_folder_ignores_tilde_prefixed_folder() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.hats.set_name("~Hats".into());
install_inventory(&h, tree, vec![]);
assert!(query_matches(&h, "@findfolder:at=1234", ""));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFoldersQueryTests.cs::FindFoldersQueryTests.FindFolders::test 09dbc17be4b28cc4a63d0f837960586ba7cd03e184f0013b26ed27db15703d84 translated
#[test]
fn find_folders() {
assert!(empty_tree_query(
"@findfolders:at=1234",
"Clothing/Hats,Clothing/Hats/Sub Hats",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFoldersQueryTests.cs::FindFoldersQueryTests.FindFolders_Separator::test 51caa783dded41b99c878066618a10a7fe32c681ef4385c9a72f154870312b1f translated
#[test]
fn find_folders_with_separator() {
assert!(empty_tree_query(
"@findfolders:at; AND =1234",
"Clothing/Hats AND Clothing/Hats/Sub Hats",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingNothing::test 41fc967c6c174ac39ce3f6de7e273e6db1845bc2ad6acd393f27a6705a3555df translated
#[test]
fn get_attach_wearing_nothing() {
assert!(empty_tree_query(
"@getattach=1234",
"00000000000000000000000000000000000000000000000000000000",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_ExternalItems::test 3f8e640aad5deeaf00b07af2d12c33b0a93257260d057d7b5dd5488f846f467a translated
#[test]
fn get_attach_external_items() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "12312312-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
install_inventory(
&h,
tree,
vec![
external_item(
"12312312-0001-4aaa-8aaa-aaaaaaaaaaaa",
"External Tattoo",
folder,
None,
None,
Some(RlvWearableType::Tattoo),
),
external_item(
"12312312-0002-4aaa-8aaa-aaaaaaaaaaaa",
"External Jaw Thing",
folder,
Some(RlvAttachmentPoint::Jaw),
Some("12312312-0002-4aaa-8aaa-ffffffffffff"),
None,
),
],
);
assert!(query_matches(
&h,
"@getattach=1234",
"00000000000000000000000000000000000000000000000100000000",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingSomeItems::test c209cd826958306f1350a685b29985cb8335a55ebcb9c0bec5c5a21279bb0a1a translated
#[test]
fn get_attach_wearing_some_items() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
install_inventory(
&h,
tree,
vec![
external_item(
"c0000000-cccc-4ccc-8ccc-cccccccccccc",
"My Socks",
folder,
Some(RlvAttachmentPoint::LeftFoot),
Some("c0000000-cccc-4ccc-8ccc-ffffffffffff"),
None,
),
external_item(
"c0000001-cccc-4ccc-8ccc-cccccccccccc",
"My Hair",
folder,
Some(RlvAttachmentPoint::Skull),
Some("c0000001-cccc-4ccc-8ccc-ffffffffffff"),
None,
),
],
);
assert!(query_matches(
&h,
"@getattach=1234",
"00100001000000000000000000000000000000000000000000000000",
));
}
const ATTACHMENT_POINTS: [RlvAttachmentPoint; 56] = [
RlvAttachmentPoint::Default,
RlvAttachmentPoint::Chest,
RlvAttachmentPoint::Skull,
RlvAttachmentPoint::LeftShoulder,
RlvAttachmentPoint::RightShoulder,
RlvAttachmentPoint::LeftHand,
RlvAttachmentPoint::RightHand,
RlvAttachmentPoint::LeftFoot,
RlvAttachmentPoint::RightFoot,
RlvAttachmentPoint::Spine,
RlvAttachmentPoint::Pelvis,
RlvAttachmentPoint::Mouth,
RlvAttachmentPoint::Chin,
RlvAttachmentPoint::LeftEar,
RlvAttachmentPoint::RightEar,
RlvAttachmentPoint::LeftEyeball,
RlvAttachmentPoint::RightEyeball,
RlvAttachmentPoint::Nose,
RlvAttachmentPoint::RightUpperArm,
RlvAttachmentPoint::RightForearm,
RlvAttachmentPoint::LeftUpperArm,
RlvAttachmentPoint::LeftForearm,
RlvAttachmentPoint::RightHip,
RlvAttachmentPoint::RightUpperLeg,
RlvAttachmentPoint::RightLowerLeg,
RlvAttachmentPoint::LeftHip,
RlvAttachmentPoint::LeftUpperLeg,
RlvAttachmentPoint::LeftLowerLeg,
RlvAttachmentPoint::Stomach,
RlvAttachmentPoint::LeftPec,
RlvAttachmentPoint::RightPec,
RlvAttachmentPoint::HUDCenter2,
RlvAttachmentPoint::HUDTopRight,
RlvAttachmentPoint::HUDTop,
RlvAttachmentPoint::HUDTopLeft,
RlvAttachmentPoint::HUDCenter,
RlvAttachmentPoint::HUDBottomLeft,
RlvAttachmentPoint::HUDBottom,
RlvAttachmentPoint::HUDBottomRight,
RlvAttachmentPoint::Neck,
RlvAttachmentPoint::AvatarCenter,
RlvAttachmentPoint::LeftHandRing,
RlvAttachmentPoint::RightHandRing,
RlvAttachmentPoint::TailBase,
RlvAttachmentPoint::TailTip,
RlvAttachmentPoint::LeftWing,
RlvAttachmentPoint::RightWing,
RlvAttachmentPoint::Jaw,
RlvAttachmentPoint::AltLeftEar,
RlvAttachmentPoint::AltRightEar,
RlvAttachmentPoint::AltLeftEye,
RlvAttachmentPoint::AltRightEye,
RlvAttachmentPoint::Tongue,
RlvAttachmentPoint::Groin,
RlvAttachmentPoint::LeftHindFoot,
RlvAttachmentPoint::RightHindFoot,
];
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingEverything::test 4adb25030cd3c125242a4b1f770bfd3afdcabd85c23d37c34df9c8f273489e5b translated
#[test]
fn get_attach_wearing_everything() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "99999999-9999-4999-8999-999999999999";
let external = ATTACHMENT_POINTS
.into_iter()
.map(|point| {
external_item(
&format!("c{:07}-cccc-4ccc-8ccc-cccccccccccc", point as i32),
&format!("External {point:?}"),
folder,
Some(point),
Some(PRIM1),
None,
)
})
.collect();
install_inventory(&h, tree, external);
assert!(query_matches(
&h,
"@getattach=1234",
"11111111111111111111111111111111111111111111111111111111",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_Specific_Exists::test 7d8ccf26629911b6b20dc26c5c549975827d7378b4d85259a8b9724a3622892b translated
#[test]
fn get_attach_specific_exists() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
install_inventory(
&h,
tree,
vec![external_item(
"c0000000-cccc-4ccc-8ccc-cccccccccccc",
"My Socks",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
Some(RlvAttachmentPoint::LeftFoot),
Some("c0000000-cccc-4ccc-8ccc-ffffffffffff"),
None,
)],
);
assert!(query_matches(&h, "@getattach:left foot=1234", "1"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_Specific_NotExists::test 08d9852205987a266608ad17c12fa498894d7c3216e873cffb9db4584cfd100d translated
#[test]
fn get_attach_specific_not_exists() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
install_inventory(
&h,
tree,
vec![external_item(
"c0000001-cccc-4ccc-8ccc-cccccccccccc",
"My Hair",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
Some(RlvAttachmentPoint::Skull),
Some("c0000001-cccc-4ccc-8ccc-ffffffffffff"),
None,
)],
);
assert!(query_matches(&h, "@getattach:left foot=1234", "0"));
}
fn get_inv(command: &str, expected: &str) -> bool {
empty_tree_query(command, expected)
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv::test 7476602b4103b47ed7dff44146a7ba90a1d62dc0d502f7b9e37b7863d9441ceb translated
#[test]
fn get_inventory_root() {
assert!(get_inv("@getinv=1234", "Clothing,Accessories"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits::test d60a78bb35cc8fcdbdc2465889333b25567ea5e1c9279a8fb7b4162f4a35eae2 translated
#[test]
fn get_inventory_outfits() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let outfits = tree
.root
.add_child(
guid("12312399-9999-4999-8999-999999999999"),
".outfits".into(),
)
.unwrap();
outfits
.add_child(
guid("12312399-0001-4999-8999-999999999999"),
"First outfit".into(),
)
.unwrap();
outfits
.add_child(
guid("12312399-0002-4999-8999-999999999999"),
"Second outfit".into(),
)
.unwrap();
outfits
.add_item(
guid("12312399-0001-0001-8999-999999999999"),
"First Item".into(),
false,
None,
None,
None,
None,
)
.unwrap();
outfits
.add_item(
guid("12312399-0001-0002-8999-999999999999"),
"Second Item".into(),
false,
None,
None,
None,
None,
)
.unwrap();
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getinv:.outfits=1234",
"First outfit,Second outfit"
));
}
fn get_my_outfits(command: &str) -> bool {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let outfits = tree
.root
.add_child(
guid("12312399-9999-4999-8999-999999999999"),
"~MyOutfits".into(),
)
.unwrap();
outfits
.add_child(
guid("12312399-0001-4999-8999-999999999999"),
"First outfit".into(),
)
.unwrap();
install_inventory(&h, tree, vec![]);
query_matches(&h, command, "First outfit")
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreLeadingSlash::test add33ed33e1940f26362332b89486253c6af1a56e601bafab49511b6607ed50a translated
#[test]
fn get_inventory_ignores_leading_slash() {
assert!(get_my_outfits("@getinv:/~MyOutfits=1234"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreTrailingSlash::test 8f89302126be19f89d075d87d5194cc000fb7819f92ea7d54e6a63c1df9ca1ee translated
#[test]
fn get_inventory_ignores_trailing_slash() {
assert!(get_my_outfits("@getinv:~MyOutfits/=1234"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreLeadingAndTrailingSlash::test c660447f93fb8508dbe4c874c92fd776a6e13596bbe3036bfb4664e35ee22306 translated
#[test]
fn get_inventory_ignores_leading_and_trailing_slash() {
assert!(get_my_outfits("@getinv:/~MyOutfits/=1234"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_Inventory::test 7db6f75e2f109d0e8d852d181ddd721f688e27144ad8a5604384b37de9f8c3eb translated
#[test]
fn get_inventory_outfit_items_are_not_folders() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let outfits = tree
.root
.add_child(
guid("12312399-9999-4999-8999-999999999999"),
".outfits".into(),
)
.unwrap();
let first = outfits
.add_child(
guid("12312399-0001-4999-8999-999999999999"),
"First outfit".into(),
)
.unwrap();
first
.add_item(
guid("12312399-0001-0001-8999-999999999999"),
"First Item".into(),
false,
None,
None,
None,
None,
)
.unwrap();
first
.add_item(
guid("12312399-0001-0002-8999-999999999999"),
"Second Item".into(),
false,
None,
None,
None,
None,
)
.unwrap();
install_inventory(&h, tree, vec![]);
assert!(query_matches(&h, "@getinv:.outfits/First outfit=1234", ""));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Subfolder::test 6a5effe8012e9a446021b83f9b5314f6f9b66587222b447fa79028582830b3a1 translated
#[test]
fn get_inventory_subfolder() {
assert!(get_inv("@getinv:Clothing/Hats=1234", "Sub Hats"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Empty::test 2dd9f242eb71826066482ff4faa80b952ef89f855723cdc0c01cc4714abf8751 translated
#[test]
fn get_inventory_empty_folder() {
assert!(get_inv("@getinv:Clothing/Hats/Sub Hats=1234", ""));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Invalid::test 92595df155e79568e70bceb1538c23f10de99a6a138a0a5d9b8a2626588fdae9 translated
#[test]
fn get_inventory_invalid_folder() {
assert!(get_inv("@getinv:Invalid Folder=1234", ""));
}
fn attach(item: &mut RlvInventoryItem, point: RlvAttachmentPoint, prim: &str) {
item.set_attached_to(Some(Some(point)));
item.set_attached_prim_id(Some(Some(guid(prim))));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn::test 472d70fb14f393d43f8698bb81d1855426f570d85c9e592fa86607eb79ce366e translated
#[test]
fn get_inventory_worn() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.business_pants, RlvAttachmentPoint::Pelvis, PRIM1);
attach(&mut tree.happy_shirt, RlvAttachmentPoint::Pelvis, PRIM2);
attach(&mut tree.fancy_hat, RlvAttachmentPoint::Chin, PRIM3);
attach(&mut tree.party_hat, RlvAttachmentPoint::Spine, PRIM4);
attach(&mut tree.glasses, RlvAttachmentPoint::Chin, PRIM5);
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.party_hat
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getinvworn=1234",
"|03,Clothing|33,Accessories|33"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_PartialRoot::test ce4c640a901a6684a27b2b259c4fc3b25f2d6b870107babff3b930ced64a150b translated
#[test]
fn get_inventory_worn_partial_root() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.business_pants, RlvAttachmentPoint::Pelvis, PRIM1);
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getinvworn=1234",
"|02,Clothing|22,Accessories|22"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_Naked::test fa8994189c5d9cda7d613dfb8f6ffbb1808c8bae54a3647530fb872d47c43dd5 translated
#[test]
fn get_inventory_worn_naked() {
assert!(empty_tree_query(
"@getinvworn=1234",
"|01,Clothing|11,Accessories|11"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_EmptyFolder::test ab6fc753f4d4170e17f49b708d7e62816f197e83234feda1fdcf63dcdc0bc6c4 translated
#[test]
fn get_inventory_worn_empty_folder() {
assert!(empty_tree_query(
"@getinvworn:Clothing/Hats/Sub Hats=1234",
"|00"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_PartialWorn::test ceb446f2aa6eaa5232a99147d5d993386ee9e2e5fefd93ef582f27a6b8ece948 translated
#[test]
fn get_inventory_worn_partial_folder() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.party_hat, RlvAttachmentPoint::Spine, PRIM1);
attach(&mut tree.fancy_hat, RlvAttachmentPoint::Chin, PRIM2);
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getinvworn:Clothing/Hats=1234",
"|33,Sub Hats|00"
));
}
const WEARABLES: [RlvWearableType; 17] = [
RlvWearableType::Shape,
RlvWearableType::Skin,
RlvWearableType::Hair,
RlvWearableType::Eyes,
RlvWearableType::Shirt,
RlvWearableType::Pants,
RlvWearableType::Shoes,
RlvWearableType::Socks,
RlvWearableType::Jacket,
RlvWearableType::Gloves,
RlvWearableType::Undershirt,
RlvWearableType::Underpants,
RlvWearableType::Skirt,
RlvWearableType::Alpha,
RlvWearableType::Tattoo,
RlvWearableType::Physics,
RlvWearableType::Universal,
];
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingNothing::test 27befef9fdef993d82a641980f2b1ad7f458f07a50c7d008b6d311aeedfb4939 translated
#[test]
fn get_outfit_wearing_nothing() {
assert!(empty_tree_query("@getoutfit=1234", "0000000000000000"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_ExternalItems::test f88d149572ae35e880f16a5a92b4a9db73a3f26c5e8e61e4b1c01440151bd64b translated
#[test]
fn get_outfit_external_items() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "12312312-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
install_inventory(
&h,
tree,
vec![
external_item(
"12312312-0001-4aaa-8aaa-aaaaaaaaaaaa",
"External Tattoo",
folder,
None,
None,
Some(RlvWearableType::Tattoo),
),
external_item(
"12312312-0002-4aaa-8aaa-aaaaaaaaaaaa",
"External Jaw Thing",
folder,
Some(RlvAttachmentPoint::Jaw),
Some("12312312-0002-4aaa-8aaa-ffffffffffff"),
None,
),
],
);
assert!(query_matches(&h, "@getoutfit=1234", "0000000000000010"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingSomeItems::test 4e9ef77ab72f1fd16c4fad69f00eb80ab46421597d41b61df80b1f87370f42d3 translated
#[test]
fn get_outfit_wearing_some_items() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
install_inventory(
&h,
tree,
vec![
external_item(
"c0000000-cccc-4ccc-8ccc-cccccccccccc",
"My Socks",
folder,
None,
None,
Some(RlvWearableType::Socks),
),
external_item(
"c0000001-cccc-4ccc-8ccc-cccccccccccc",
"My Hair",
folder,
None,
None,
Some(RlvWearableType::Hair),
),
],
);
assert!(query_matches(&h, "@getoutfit=1234", "0000001000010000"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingEverything::test a840b239174cdb5dee4beb875bf9129209af3ba310564319528ad5b19764aae0 translated
#[test]
fn get_outfit_wearing_everything() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "99999999-9999-4999-8999-999999999999";
let external = WEARABLES
.into_iter()
.map(|wearable| {
external_item(
&format!("c{:07}-cccc-4ccc-8ccc-cccccccccccc", wearable as i32),
&format!("External {wearable:?}"),
folder,
None,
None,
Some(wearable),
)
})
.collect();
install_inventory(&h, tree, external);
assert!(query_matches(&h, "@getoutfit=1234", "1111111111111111"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_Specific_Exists::test a402fd67ed8ddfc12d09863f08f9b15b34262ffa12b4b5aa965826eac89abae5 translated
#[test]
fn get_outfit_specific_exists() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
install_inventory(
&h,
tree,
vec![external_item(
"c0000000-cccc-4ccc-8ccc-cccccccccccc",
"My Socks",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
None,
None,
Some(RlvWearableType::Socks),
)],
);
assert!(query_matches(&h, "@getoutfit:socks=1234", "1"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_Specific_NotExists::test d7e891a620b5e5407fe337f507874b63eb5a21589767a01362bd8bc43d19ba4a translated
#[test]
fn get_outfit_specific_not_exists() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
install_inventory(
&h,
tree,
vec![external_item(
"c0000001-cccc-4ccc-8ccc-cccccccccccc",
"My Hair",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
None,
None,
Some(RlvWearableType::Hair),
)],
);
assert!(query_matches(&h, "@getoutfit:socks=1234", "0"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_BySender::test e7e87c01e83967a7160509d76f49d2a4b18d34b9b3fbed370c174d64ddb2c2b5 translated
#[test]
fn get_path_new_by_sender() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.party_hat, RlvAttachmentPoint::Spine, PRIM1);
install_inventory(&h, tree, vec![]);
assert!(block_on(h.process_from("@getpathnew=1234", PRIM1, "Party Hat (Spine)")).unwrap());
assert_eq!(
h.actions.lock().unwrap().replies,
vec![(1234, "Clothing/Hats".into())]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByUUID::test 3a7d242966286258ed075c8e5c69eaf54ba0e71b8607432615a1199f5aeb6dcf translated
#[test]
fn get_path_new_by_uuid() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.party_hat, RlvAttachmentPoint::Spine, PRIM1);
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
&format!("@getpathnew:{PRIM1}=1234"),
"Clothing/Hats"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByUUID_Unknown::test c3c206661594026c36dfcfea110631548cd362d824db268c170e4d04b24b674a translated
#[test]
fn get_path_new_by_unknown_uuid() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.fancy_hat.set_attached_to(None);
tree.party_hat.set_attached_to(None);
tree.business_pants.set_attached_to(None);
tree.happy_shirt.set_attached_to(None);
tree.glasses.set_attached_to(None);
tree.retro_pants.set_worn_on(None);
tree.watch.set_worn_on(None);
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getpathnew:BADBADBA-DBAD-4BAD-8BAD-BADBADBADBAD=1234",
"",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByAttach::test f8858e6141b660cec8a09c016891f2275dd9364157b1aa614b63fca5abb7620c translated
#[test]
fn get_path_new_by_attachment_point() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.business_pants, RlvAttachmentPoint::Pelvis, PRIM1);
attach(&mut tree.fancy_hat, RlvAttachmentPoint::Groin, PRIM2);
attach(&mut tree.glasses, RlvAttachmentPoint::Groin, PRIM3);
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getpathnew:groin=1234",
"Accessories,Clothing/Hats"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByWorn::test eed31d9aaf34578368cc4f590de1da7f47e3f6c5e663215866f7f8e6946f974b translated
#[test]
fn get_path_new_by_wearable() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Pants)));
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getpathnew:pants=1234",
"Accessories,Clothing/Hats"
));
}

View File

@@ -0,0 +1,495 @@
// Exact Rust translations of NotifyQueryTests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::{RlvAttachmentPoint, RlvWearableType};
const ITEM_1: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const ITEM_2: &str = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const ITEM_3: &str = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
const PRIM: &str = "aaaaaaaa-aaaa-4aaa-8aaa-ffffffffffff";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process(h: &RlvHarness, commands: &[&str]) {
for command in commands {
block_on(h.process(command)).unwrap();
}
}
fn replies_match(h: &RlvHarness, expected: &[(i32, &str)]) -> bool {
h.actions.lock().unwrap().replies
== expected
.iter()
.map(|(channel, text)| (*channel, (*text).into()))
.collect::<Vec<_>>()
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.Notify::test 082ff4cd00faf29a73aca158d4e24ed9fd3e7844ed6cefbf962d8727846a3c27 translated
#[test]
fn notify_every_restriction() {
let h = harness();
process(
&h,
&[
"@notify:1234=add",
"@sendim=n",
"@alwaysrun=n",
"@sendim:group_name=add",
],
);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/sendim=n"),
(1234, "/alwaysrun=n"),
(1234, "/sendim:group_name=n"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyFiltered::test e00e51aeadd0d7a107105684129a6ae74fbf918be4c563d92d7cdaa223d2c03c translated
#[test]
fn notify_filtered() {
let h = harness();
process(
&h,
&[
"@notify:1234;run=add",
"@sendim=n",
"@alwaysrun=n",
"@sendim:group_name=add",
],
);
assert!(replies_match(&h, &[(1234, "/alwaysrun=n")]));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiCommand::test 77f3950214a1bd1e3816fa6f7b0ca69727e9e18be5fb7b37f19490408ca023dc translated
#[test]
fn notify_multi_command() {
let h = harness();
process(
&h,
&[
"@notify:1234=add",
"@sendim=n,sendim:group_name=add,alwaysrun=n",
],
);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/sendim=n"),
(1234, "/sendim:group_name=n"),
(1234, "/alwaysrun=n"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannels::test 12a0a6e0a0a6632960de98236670e063f2c1aa16cf6b6c8d718bde0e0abfd9b9 translated
#[test]
fn notify_multiple_channels() {
let h = harness();
process(&h, &["@notify:1234=add", "@notify:12345=add", "@sendim=n"]);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/notify:12345=n"),
(12345, "/notify:12345=n"),
(1234, "/sendim=n"),
(12345, "/sendim=n"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannelsFiltered::test bff8ca8465c2299d0d2ef60adfa4164270d08cee7223361bb27b86a7e4daeec9 translated
#[test]
fn notify_multiple_channels_filtered() {
let h = harness();
process(
&h,
&["@notify:1234=add", "@notify:12345;im=add", "@sendim=n"],
);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/notify:12345;im=n"),
(1234, "/sendim=n"),
(12345, "/sendim=n"),
],
));
}
fn notify_synonym(command: &str, expected_reply: &str) -> bool {
let h = harness();
process(&h, &["@notify:1234=add", command]);
replies_match(&h, &[(1234, "/notify:1234=n"), (1234, expected_reply)])
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:9e893d263294d04d 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camdistmax() {
assert!(notify_synonym("@camdistmax:123=n", "/camdistmax:123=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:fc6b17eb4e9e7a00 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_setcam_avdistmax() {
assert!(notify_synonym(
"@setcam_avdistmax:123=n",
"/setcam_avdistmax:123=n"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:b37376c5865a6fe8 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camdistmin() {
assert!(notify_synonym("@camdistmin:123=n", "/camdistmin:123=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:5d497faea315b624 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_setcam_avdistmin() {
assert!(notify_synonym(
"@setcam_avdistmin:123=n",
"/setcam_avdistmin:123=n"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:282fa0139ccbba29 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camunlock() {
assert!(notify_synonym("@camunlock=n", "/camunlock=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:f08c6eb7b4d12fac 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_setcam_unlock() {
assert!(notify_synonym("@setcam_unlock=n", "/setcam_unlock=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:37f0f73ed7492dd0 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camtextures() {
assert!(notify_synonym(
"@camtextures:1cdbc6a2-ae6b-3130-9348-3d3b1ca84c53=n",
"/camtextures:1cdbc6a2-ae6b-3130-9348-3d3b1ca84c53=n",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:d75917941e63732c 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_touchfar() {
assert!(notify_synonym("@touchfar:5=n", "/touchfar:5=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:2f72da33fdbcd8be 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_fartouch() {
assert!(notify_synonym("@fartouch:5=n", "/fartouch:5=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear_Filtered::test f3e0550a53faca13679421318eee85f010c1b8668e3edfae6e2548d39dbcafd7 translated
#[test]
fn notify_clear_filtered() {
let h = harness();
process(&h, &["@notify:1234=add", "@fly=n", "@clear=fly"]);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/fly=n"),
(1234, "/fly=y"),
(1234, "/clear:fly"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear::test 61d7419956a83be04eeb13557c6a2120419b2f0f1c529149c4fb57871bb6506e translated
#[test]
fn notify_clear() {
let h = harness();
block_on(h.process_from("@notify:1234=add", ITEM_3, "Main")).unwrap();
process(&h, &["@fly=n", "@clear"]);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/fly=n"),
(1234, "/fly=y"),
(1234, "/clear"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyInventoryOffer::test 2bbac63ab86ec77f6d0a4558a14ee913a7f44930364476a89e02cd5ec80191b9 translated
#[test]
fn notify_inventory_offer() {
let h = harness();
process(&h, &["@notify:1234=add"]);
block_on(
h.service
.report_inventory_offer_accepted("#RLV/~MyCuffs".into(), None),
)
.unwrap();
block_on(
h.service
.report_inventory_offer_accepted("Objects/New Folder (3)".into(), None),
)
.unwrap();
block_on(
h.service
.report_inventory_offer_declined("#RLV/Foo/Bar".into(), None),
)
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/accepted_in_rlv inv_offer ~MyCuffs"),
(1234, "/accepted_in_inv inv_offer Objects/New Folder (3)"),
(1234, "/declined inv_offer Foo/Bar"),
],
));
}
fn report_sit_and_unsit(h: &RlvHarness) {
block_on(h.service.report_sit(Some(Some(guid(ITEM_3))), None)).unwrap();
block_on(h.service.report_unsit(Some(Some(guid(ITEM_3))), None)).unwrap();
block_on(h.service.report_sit(None, None)).unwrap();
block_on(h.service.report_unsit(None, None)).unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandLegal::test 83a07a88a0386982c854a0223b64dd5c417f1a55a038e4ceba8f487983daadaf translated
#[test]
fn notify_sit_and_stand_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
report_sit_and_unsit(&h);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(
1234,
"/sat object legally 11111111-1111-4111-8111-111111111111",
),
(
1234,
"/unsat object legally 11111111-1111-4111-8111-111111111111",
),
(1234, "/sat ground legally"),
(1234, "/unsat ground legally"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandWithRestrictions::test 166e2087aa0652bdd427e1908bc338659ec1d4dc8065c016612696d1f5dfd000 translated
#[test]
fn notify_sit_and_stand_illegal() {
let h = harness();
process(&h, &["@sit=n", "@unsit=n", "@notify:1234=add"]);
report_sit_and_unsit(&h);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(
1234,
"/sat object illegally 11111111-1111-4111-8111-111111111111",
),
(
1234,
"/unsat object illegally 11111111-1111-4111-8111-111111111111",
),
(1234, "/sat ground illegally"),
(1234, "/unsat ground illegally"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear::test 9529acb9f3e1c335a50f8de6d63cc5711921de962546ff868811279d05826399 translated
#[test]
fn notify_wear_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
block_on(
h.service
.report_item_worn(guid(ITEM_2), false, RlvWearableType::Skin, None),
)
.unwrap();
block_on(
h.service
.report_item_worn(guid(ITEM_3), true, RlvWearableType::Tattoo, None),
)
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/worn legally skin"),
(1234, "/worn legally tattoo"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear_Illegal::test 65bfc1db698470cf56dd8c6811e85ae373d1fca95cdbf82be66b7e32da311a2f translated
#[test]
fn notify_wear_illegal() {
let h = harness();
process(&h, &["@addoutfit:skin=n", "@notify:1234=add"]);
block_on(
h.service
.report_item_worn(guid(ITEM_1), false, RlvWearableType::Skin, None),
)
.unwrap();
assert!(replies_match(
&h,
&[(1234, "/notify:1234=n"), (1234, "/worn illegally skin")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear::test 340b60b8038dcd55320dc9aedc16beb9193e731ba7b659ca3cb2951a2d19b7ac translated
#[test]
fn notify_unwear_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
block_on(h.service.report_item_unworn(
guid(ITEM_1),
guid(ITEM_2),
false,
RlvWearableType::Skin,
None,
))
.unwrap();
block_on(h.service.report_item_unworn(
guid(ITEM_1),
guid(ITEM_3),
true,
RlvWearableType::Tattoo,
None,
))
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/unworn legally skin"),
(1234, "/unworn legally tattoo"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear_illegal::test e7056e6e145430eb2180edb92593f59c07bcbdfa21629b1ca29ac93b2fca975e translated
#[test]
fn notify_unwear_illegal() {
let h = harness();
process(&h, &["@remoutfit:skin=n", "@notify:1234=add"]);
block_on(h.service.report_item_unworn(
guid(ITEM_1),
guid(ITEM_1),
false,
RlvWearableType::Skin,
None,
))
.unwrap();
assert!(replies_match(
&h,
&[(1234, "/notify:1234=n"), (1234, "/unworn illegally skin")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached::test dc5239c77b9169cf3833c5a1dc765b381efe833f15b34ac7e57173c0a640942a translated
#[test]
fn notify_attached_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
block_on(
h.service
.report_item_attached(guid(ITEM_1), false, RlvAttachmentPoint::Chest, None),
)
.unwrap();
block_on(h.service.report_item_attached(
guid(ITEM_2),
true,
RlvAttachmentPoint::AvatarCenter,
None,
))
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/attached legally Chest"),
(1234, "/attached legally Avatar Center"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached_Illegal::test b56de057dece9cb8ece795d13d6bc42e7825d62f09f967f37a4dbf262d2b4456 translated
#[test]
fn notify_attached_illegal() {
let h = harness();
process(&h, &["@addattach:chest=n", "@notify:1234=add"]);
block_on(
h.service
.report_item_attached(guid(ITEM_1), false, RlvAttachmentPoint::Chest, None),
)
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/attached illegally Chest"),
],
));
}
fn report_detached(h: &RlvHarness, folder: &str, shared: bool, point: RlvAttachmentPoint) {
block_on(h.service.report_item_detached(
guid(ITEM_1),
guid(PRIM),
guid(folder),
shared,
point,
None,
))
.unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached::test a741cec23a985028b3dc2b09195255276a96e4f07fc4fe5f8cca6c1e3c940d71 translated
#[test]
fn notify_detached_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
report_detached(&h, ITEM_2, false, RlvAttachmentPoint::Chest);
report_detached(&h, ITEM_3, true, RlvAttachmentPoint::Skull);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/detached legally Chest"),
(1234, "/detached legally Skull"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached_Illegal::test 1a4c9475a3b91a975b9861685dcaf899505b4f6727257618f9add9cecd3df54d translated
#[test]
fn notify_detached_illegal() {
let h = harness();
process(&h, &["@remattach:chest=n", "@notify:1234=add"]);
report_detached(&h, ITEM_1, false, RlvAttachmentPoint::Chest);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/detached illegally Chest"),
],
));
}

View File

@@ -0,0 +1,225 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/PermissionsTests.cs.
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::{
RlvPermissionsServiceHoverTextLocation as HoverTextLocation,
RlvPermissionsServiceObjectLocation as ObjectLocation,
};
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn hover_text_defaults() -> [bool; 2] {
let permissions = harness().service.permissions();
let object = Some(Some(guid("00000000-0000-4000-8000-000000000000")));
[
permissions
.can_show_hover_text(HoverTextLocation::World, object)
.unwrap(),
permissions
.can_show_hover_text(HoverTextLocation::Hud, object)
.unwrap(),
]
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CamZoomMin_Default::test 662b332d66c72caecc1a179730bc2524b9da16aa85f7289bebd31842610ceccc translated
#[test]
fn camera_zoom_min_defaults_to_none() {
assert!(
harness()
.service
.permissions()
.get_camera_restrictions()
.unwrap()
.zoom_min()
.flatten()
.is_none()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextWorld_Default::test 380d1e30bd9ded04329bfd6d65ba447a8dd45a934cfa875628253719bb0e69ce translated
#[test]
fn can_show_hover_text_world_defaults_true() {
assert_eq!(hover_text_defaults(), [true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextHud_Default::test a0af1f72f417cfa451284b7a3dbbb26d378e7eb9896dde3b6df0d0a2e4773f38 translated
#[test]
fn can_show_hover_text_hud_defaults_true() {
assert_eq!(hover_text_defaults(), [true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverText_Default::test c4122dbf650f51bde55dfda412a884347a78d3cd09dd2bb0fcbe4a7e74a1fff6 translated
#[test]
fn can_show_hover_text_defaults_true() {
assert_eq!(hover_text_defaults(), [true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextAll_Default::test 0ed67c5566d038f770eb9f5df6aa0b5394d7d94cf7c397fa8089b419f872c681 translated
#[test]
fn can_show_all_hover_text_defaults_true() {
assert_eq!(hover_text_defaults(), [true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowNameTags_Default::test 0781be94eb099d9aed1be2ff313856770d1ec24047d04c81c69219c743b4c8cb translated
#[test]
fn can_show_name_tags_defaults_true() {
let permissions = harness().service.permissions();
assert!(permissions.can_show_name_tags(None).unwrap());
assert!(
permissions
.can_show_name_tags(Some(Some(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShare_Default::test e827d549d1d9329b63db159446937735ead13eed5d3eaa59440d3c686182f517 translated
#[test]
fn can_share_defaults_true() {
let permissions = harness().service.permissions();
assert!(permissions.can_share(None).unwrap());
assert!(
permissions
.can_share(Some(Some(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowNames_Default::test 56492cdd0802c5f8ed2a0f6d56abaf8186e37dd7b888904db52be97f9137279a translated
#[test]
fn can_show_names_defaults_true() {
let permissions = harness().service.permissions();
assert!(permissions.can_show_names(None).unwrap());
assert!(
permissions
.can_show_names(Some(Some(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanEdit_Default::test 417fb9f3eb3e70f3bd33710d11fb25eacd0db0a365b0ed2dec6778d09968f44b translated
#[test]
fn can_edit_defaults_true_for_all_locations_and_ids() {
let permissions = harness().service.permissions();
let object = Some(Some(guid("00000000-0000-4000-8000-000000000000")));
for location in [
ObjectLocation::Hud,
ObjectLocation::Attached,
ObjectLocation::RezzedInWorld,
] {
assert!(permissions.can_edit(location, None).unwrap());
assert!(permissions.can_edit(location, object).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanRecvChat_Default::test b1ec48da83249b1141c3af926cd494373c47214d6a145916a8833d49edd155e2 translated
#[test]
fn can_receive_chat_defaults_true() {
let permissions = harness().service.permissions();
assert!(
permissions
.can_receive_chat(
"Hello world".into(),
guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"),
)
.unwrap()
);
assert!(
permissions
.can_receive_chat(
"/me says Hello world".into(),
guid("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanAutoAcceptTpRequest_Default::test abbcccb4415afdb6558f40a6d4030704f64442f019d065fef8a7a56a407e8642 translated
#[test]
fn auto_accept_tp_request_defaults_false() {
let permissions = harness().service.permissions();
for user in [
Some(Some(guid("00000000-0000-4000-8000-000000000000"))),
Some(Some(guid("11111111-1111-4111-8111-111111111111"))),
None,
] {
assert!(!permissions.is_auto_accept_tp_request(user).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanTpRequest_Default::test aefc51023a5274d402dae0e8111a0776622dc431754c3d1f0ce240a50dfd405d translated
#[test]
fn can_tp_request_defaults_true() {
let permissions = harness().service.permissions();
assert!(permissions.can_tp_request(None).unwrap());
assert!(
permissions
.can_tp_request(Some(Some(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanAutoAcceptTp_Default::test 553245a5381689a7f1c6398cb0ca50510f9089b9bdc797672ae35fb5822fdf8e translated
#[test]
fn auto_accept_tp_defaults_false() {
let permissions = harness().service.permissions();
for user in [
Some(Some(guid("00000000-0000-4000-8000-000000000000"))),
Some(Some(guid("11111111-1111-4111-8111-111111111111"))),
None,
] {
assert!(!permissions.is_auto_accept_tp(user).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanChat_Default::test a9b0e4f8713991ce8b9b61d750c086d56da432dbddd533ec63dc0604238831a1 translated
#[test]
fn can_chat_defaults_true() {
let permissions = harness().service.permissions();
for (channel, message) in [(0, "Hello"), (0, "/me says Hello"), (5, "Hello")] {
assert!(permissions.can_chat(channel, message.into()).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanSendIM_Default::test 6cc5238ded59b80408c59c9e77ded1162e370c295b846903dbcc87f74175cd55 translated
#[test]
fn can_send_im_defaults_true() {
let permissions = harness().service.permissions();
let user = Some(Some(guid("00000000-0000-4000-8000-000000000000")));
assert!(permissions.can_send_im("Hello".into(), user, None).unwrap());
assert!(
permissions
.can_send_im("Hello".into(), user, Some("Group Name".into()))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanStartIM_Default::test c6d6db79b0939b33eb5fd29490474575e062f796160f4a69aab34ccefc1842cb translated
#[test]
fn can_start_im_defaults_true() {
assert!(
harness()
.service
.permissions()
.can_start_im(guid("00000000-0000-4000-8000-000000000000"))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanReceiveIM_Default::test 23c1c79ae9eba016a48f3e9097fc26283223c9e120308d93fe53ce591ee5691c translated
#[test]
fn can_receive_im_defaults_true() {
let permissions = harness().service.permissions();
let user = Some(Some(guid("00000000-0000-4000-8000-000000000000")));
assert!(
permissions
.can_receive_im("Hello".into(), user, None)
.unwrap()
);
assert!(
permissions
.can_receive_im("Hello".into(), user, Some("Group Name".into()))
.unwrap()
);
}

View File

@@ -0,0 +1,315 @@
// Exact Rust translations of the basic RLV query tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SENDER_ID, guid};
use libremetaverse_rlv::RlvService;
const OTHER_SENDER: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const SIT_ID: &str = "00000000-0000-4000-8000-000000000000";
const TP_EXCEPTION: &str = "3d6181b0-6a4b-97ef-18d8-722652995cf1";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn seed_blacklist(h: &RlvHarness, seed: &str) {
for behavior in seed.split(',').filter(|behavior| !behavior.is_empty()) {
h.service
.blacklist()
.blacklist_behavior(behavior.into())
.unwrap();
}
}
fn assert_reply(h: &RlvHarness, expected: &str) {
assert_eq!(
h.actions.lock().unwrap().replies,
vec![(1234, expected.into())]
);
}
fn get_blacklist_matches(command: &str, seed: &str, expected: &str) -> bool {
let h = harness();
seed_blacklist(&h, seed);
block_on(h.process(&format!("{command}=1234"))).unwrap();
h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:8e1b820c1f2bd3cd 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_all() {
assert!(get_blacklist_matches(
"@getblacklist",
"sendim,recvim",
"recvim,sendim"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:64136cd82156035a 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_im_filter() {
assert!(get_blacklist_matches(
"@getblacklist:im",
"sendim,recvim",
"recvim,sendim"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:2068bf7f0a131fe8 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_send_filter() {
assert!(get_blacklist_matches(
"@getblacklist:send",
"sendim,recvim",
"sendim"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:b86b0c5e67f981c2 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_unmatched_filter() {
assert!(get_blacklist_matches(
"@getblacklist:tpto",
"sendim,recvim",
""
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:123b930bb970a1f1 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_empty() {
assert!(get_blacklist_matches("@getblacklist", "", ""));
}
fn manual_blacklist_matches(seed: &str, expected: &str) -> bool {
let mut h = harness();
h.service.set_enable_instant_message_processing(true);
seed_blacklist(&h, seed);
block_on(
h.service
.process_instant_message("@getblacklist".into(), guid(SENDER_ID), None),
)
.unwrap();
h.actions.lock().unwrap().instant_messages == vec![(guid(SENDER_ID), expected.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:f14641dea0f1de93 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e translated
#[test]
fn manual_blacklist_all() {
assert!(manual_blacklist_matches("sendim,recvim", "recvim,sendim"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:d25c660357f6ccff 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e translated
#[test]
fn manual_blacklist_empty() {
assert!(manual_blacklist_matches("", ""));
}
fn debug_matches(setting_name: &str, setting_value: &str) -> bool {
let h = harness();
h.queries
.lock()
.unwrap()
.debug_settings
.insert(setting_name.to_lowercase(), setting_value.into());
block_on(h.process(&format!("@getdebug_{setting_name}=1234"))).unwrap()
&& h.actions.lock().unwrap().replies == vec![(1234, setting_value.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:fa77559e30768d15 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7 translated
#[test]
fn get_debug_known_setting() {
assert!(debug_matches(
"RenderResolutionDivisor",
"RenderResolutionDivisor Success"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:55694f25ed879d95 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7 translated
#[test]
fn get_debug_unknown_setting() {
assert!(debug_matches("Unknown Setting", "Unknown Setting Success"));
}
fn environment_matches(setting_name: &str, setting_value: &str) -> bool {
let h = harness();
h.queries
.lock()
.unwrap()
.environment_settings
.insert(setting_name.to_lowercase(), setting_value.into());
block_on(h.process(&format!("@getenv_{setting_name}=1234"))).unwrap()
&& h.actions.lock().unwrap().replies == vec![(1234, setting_value.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:f656b648d00a6d91 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881 translated
#[test]
fn get_environment_known_setting() {
assert!(environment_matches("Daytime", "Daytime Success"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:55694f25ed879d95 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881 translated
#[test]
fn get_environment_unknown_setting() {
assert!(environment_matches(
"Unknown Setting",
"Unknown Setting Success"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_Default::test da65b184d0ef1380274e8e4dfa199c125a1a192b9e76f8fec1d406df18186169 translated
#[test]
fn get_active_group() {
let h = harness();
h.queries.lock().unwrap().active_group = Some("Group Name".into());
assert!(block_on(h.process("@getgroup=1234")).unwrap());
assert_reply(&h, "Group Name");
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_NoGroup::test d1da37ae52bd94dac9cd6e031525b57f31ca7e9dc00a69a6e0c4e753741dc9e8 translated
#[test]
fn get_group_without_active_group() {
let h = harness();
assert!(block_on(h.process("@getgroup=1234")).unwrap());
assert_reply(&h, "none");
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID::test bfbf6d62c09c4878504aa529805a29fe9689d1e29e7ca3d44bf2346d6b3fbe6b translated
#[test]
fn get_sit_id_when_not_sitting() {
let h = harness();
block_on(h.process("@getsitid=1234")).unwrap();
assert_reply(&h, "NULL_KEY");
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID_Default::test 456f8f22b1d2917c3729ed600bdf0b693c0189bd100b9863f4b42b07259110b0 translated
#[test]
fn get_current_sit_id() {
let h = harness();
h.queries.lock().unwrap().sit_id = Some(guid(SIT_ID));
block_on(h.process("@getsitid=1234")).unwrap();
assert_reply(&h, SIT_ID);
}
fn seed_status(h: &RlvHarness) {
block_on(h.process("@fly=n")).unwrap();
block_on(h.process("@tplure=n")).unwrap();
block_on(h.process(&format!("@tplure:{TP_EXCEPTION}=add"))).unwrap();
block_on(h.process_from("@tplocal=n", OTHER_SENDER, "Sender 2")).unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusAllQueryTests.cs::GetStatusAllQueryTests.GetStatusAll::test ee8fac8485db2b5c01abf8664364ca1e13214243f1e661a04d93df680422d596 translated
#[test]
fn get_status_all_senders() {
let h = harness();
seed_status(&h);
block_on(h.process("@getstatusall=1234")).unwrap();
assert_reply(
&h,
"/fly/tplure/tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1/tplocal",
);
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus::test c538e68277e93b40374dfd86bde9be00e0b82dfad7f4573cc4b0660f15fa5fe4 translated
#[test]
fn get_status_for_sender() {
let h = harness();
seed_status(&h);
block_on(h.process("@getstatus=1234")).unwrap();
assert_reply(
&h,
"/fly/tplure/tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1",
);
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_filtered::test 574b7f7c37b4e09e4257e5b02d50b222054216e34b6d1dd3fe6b26127c89b562 translated
#[test]
fn get_status_filtered() {
let h = harness();
seed_status(&h);
block_on(h.process("@getstatus:tp=1234")).unwrap();
assert_reply(&h, "/tplure/tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1");
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_customSeparator::test 3bec2e53ea88857d4a1ae8cd6bc6f235f24e00d0773c24ca75a1892adb803527 translated
#[test]
fn get_status_custom_separator() {
let h = harness();
seed_status(&h);
block_on(h.process("@getstatus:; ! =1234")).unwrap();
assert_reply(
&h,
" ! fly ! tplure ! tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1",
);
}
fn version_num_blacklist_matches(seed: &str, expected: &str) -> bool {
let h = harness();
seed_blacklist(&h, seed);
block_on(h.process("@versionnumbl=1234")).unwrap();
h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:478968a5d14830de 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9 translated
#[test]
fn version_number_without_blacklist() {
assert!(version_num_blacklist_matches(
"",
RlvService::RLV_VERSION_NUM
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:8c124ee42e9ab944 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9 translated
#[test]
fn version_number_with_blacklist() {
assert!(version_num_blacklist_matches(
"sendim,recvim",
"2040213,recvim,sendim"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.ManualVersion::test 6f8493b201d69e1449d8311e434736f6f6b2bad04c9fe9c6adf94a94d9cbe597 translated
#[test]
fn manual_version() {
let mut h = harness();
h.service.set_enable_instant_message_processing(true);
block_on(
h.service
.process_instant_message("@version".into(), guid(SENDER_ID), None),
)
.unwrap();
assert_eq!(
h.actions.lock().unwrap().instant_messages,
vec![(guid(SENDER_ID), RlvService::RLV_VERSION.into())]
);
}
fn version_query_matches(command: &str, expected: &str) -> bool {
let h = harness();
block_on(h.process(&format!("{command}=1234"))).unwrap();
h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:442bdc765ad34e20 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30 translated
#[test]
fn version_query_standard() {
assert!(version_query_matches("@version", RlvService::RLV_VERSION));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:968af293ea2a53a1 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30 translated
#[test]
fn version_query_new() {
assert!(version_query_matches(
"@versionnew",
RlvService::RLV_VERSION
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:ae9a221915e6e1bb f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30 translated
#[test]
fn version_query_number() {
assert!(version_query_matches(
"@versionnum",
RlvService::RLV_VERSION_NUM
));
}

View File

@@ -0,0 +1,549 @@
// Exact Rust translations of recursive and folder-targeted attachment restrictions.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
use libremetaverse_types::compat::Guid;
const PRIM_1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
const PRIM_2: &str = "11111111-0002-4aaa-8aaa-ffffffffffff";
const PRIM_3: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
#[derive(Clone, Copy)]
enum Setup {
None,
PartySpine,
PartyChin,
BusinessPelvis,
BusinessChin,
BusinessChest,
RetroPants,
WatchTattoo,
PartyAndBusinessPelvis,
PartyAndBusinessPelvisDetach,
}
#[derive(Clone, Copy)]
enum FolderKey {
Clothing,
Hats,
SubHats,
Accessories,
}
#[derive(Clone, Copy)]
enum LockMode {
Attach,
Detach,
}
struct FolderIdentity {
clothing: (Guid, String),
hats: (Guid, String),
sub_hats: (Guid, String),
accessories: (Guid, String),
}
fn apply_setup(tree: &mut SampleInventoryTree, setup: Setup) {
match setup {
Setup::None => {}
Setup::PartySpine => {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Spine)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::PartyChin => {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::BusinessPelvis => {
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::BusinessChin => {
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::BusinessChest => {
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Chest)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::RetroPants => tree
.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants))),
Setup::WatchTattoo => tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo))),
Setup::PartyAndBusinessPelvis => {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_2))));
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_1))));
}
Setup::PartyAndBusinessPelvisDetach => {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_1))));
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
}
}
fn locked_folders_match(
h: &RlvHarness,
identities: &FolderIdentity,
expected: &[FolderKey],
mode: LockMode,
) -> bool {
let locked = h.service.restrictions().get_locked_folders().unwrap();
if locked.len() != expected.len() {
return false;
}
for key in expected {
let (id, name) = match key {
FolderKey::Clothing => &identities.clothing,
FolderKey::Hats => &identities.hats,
FolderKey::SubHats => &identities.sub_hats,
FolderKey::Accessories => &identities.accessories,
};
let Some(folder) = locked.get(id) else {
return false;
};
let common = folder.id() == *id
&& folder.name() == *name
&& folder.is_locked()
&& folder.attach_exceptions().is_empty()
&& folder.detach_exceptions().is_empty();
let mode_matches = match mode {
LockMode::Attach => {
!folder.can_attach()
&& folder.can_detach()
&& folder.attach_restrictions().len() == 1
&& folder.detach_restrictions().is_empty()
}
LockMode::Detach => {
folder.can_attach()
&& !folder.can_detach()
&& folder.attach_restrictions().is_empty()
&& folder.detach_restrictions().len() == 1
}
};
if !common || !mode_matches {
return false;
}
}
true
}
fn folder_case_matches(
command: &str,
sender: Option<(&str, &str)>,
setup: Setup,
mode: LockMode,
expected_items: [bool; 7],
expected_folders: &[FolderKey],
) -> bool {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().expect("sample inventory tree");
apply_setup(&mut tree, setup);
let identities = FolderIdentity {
clothing: (tree.clothing.id(), tree.clothing.name()),
hats: (tree.hats.id(), tree.hats.name()),
sub_hats: (tree.sub_hats.id(), tree.sub_hats.name()),
accessories: (tree.accessories.id(), tree.accessories.name()),
};
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
for command in command.split(',') {
let processed = sender.map_or_else(
|| block_on(h.process(command)),
|(id, name)| block_on(h.process_from(command, id, name)),
);
if !processed.unwrap() {
return false;
}
}
let permissions = h.service.permissions();
let actual = match mode {
LockMode::Attach => [
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.party_hat, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.business_pants, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.retro_pants, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.glasses, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.watch, true)
.unwrap(),
],
LockMode::Detach => [
permissions
.can_detach_with_rlv_inventory_item(tree.party_hat)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.business_pants)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.happy_shirt)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.retro_pants)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.glasses)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap(),
],
};
actual == expected_items && locked_folders_match(&h, &identities, expected_folders, mode)
}
const HATS_LOCKED: [bool; 7] = [false, false, true, true, true, true, true];
const CLOTHING_LOCKED: [bool; 7] = [true, true, false, false, false, true, true];
const CLOTHING_RECURSIVE_LOCKED: [bool; 7] = [false, false, false, false, false, true, true];
const ACCESSORIES_LOCKED: [bool; 7] = [true, true, true, true, true, false, false];
const ALL_ALLOWED: [bool; 7] = [true; 7];
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis::test 39bc0c4581f8277f4d5c90ec715c40f4715b5ae7007a28a04fe762f2f6adfbfd translated
#[test]
fn attach_all_this() {
assert!(folder_case_matches(
"@attachallthis=n",
Some((PRIM_3, "Party Hat (Spine)")),
Setup::PartyChin,
LockMode::Attach,
HATS_LOCKED,
&[FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive::test d051e7783e79bf91a8092cd2d29cf1aacec3b0af86ecf0c7ca590ce25bc8393c translated
#[test]
fn attach_all_this_recursive() {
assert!(folder_case_matches(
"@attachallthis=n",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessChin,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Path::test b4db2b29ad376777b382f8c6f4f7b62643bb2dd43858de4be69ac2252f18c963 translated
#[test]
fn attach_all_this_recursive_path() {
assert!(folder_case_matches(
"@attachallthis:Clothing=n",
None,
Setup::BusinessChin,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Worn::test 6ecfc6ffe71896979a37dac6dd8149a015b8d3e7e952247954333c053da4961e translated
#[test]
fn attach_all_this_recursive_worn() {
assert!(folder_case_matches(
"@attachallthis:pants=n",
None,
Setup::RetroPants,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Attached::test 8ac38c77c6bdb03e4cbaa96600bead9a760eb5eec098504b05cfb3a1bdfb8557 translated
#[test]
fn attach_all_this_recursive_attached() {
assert!(folder_case_matches(
"@attachallthis:chest=n",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessChest,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Attached_AddRem::test 495f288e0fa86059d13a027075700ba6308e9c9d585fa56e3d1adf4a71df912b translated
#[test]
fn attach_all_this_recursive_attached_removed() {
assert!(folder_case_matches(
"@attachallthis:chest=n,@attachallthis:chest=y",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessChest,
LockMode::Attach,
ALL_ALLOWED,
&[],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis::test 3a8a5acc4ad5cbec76737239ea23330a34f54146a4ff9d5d25082c220527a3e4 translated
#[test]
fn attach_this() {
assert!(folder_case_matches(
"@attachthis=n",
Some((PRIM_3, "Party Hat (Spine)")),
Setup::PartySpine,
LockMode::Attach,
HATS_LOCKED,
&[FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_NotRecursive::test a5818b4e30d04aba7d6427b2b94e025d34e82eb3bdcb7ac80a23e55f2382ec29 translated
#[test]
fn attach_this_not_recursive() {
assert!(folder_case_matches(
"@attachthis=n",
Some((PRIM_1, "Business Pants (Pelvis)")),
Setup::BusinessPelvis,
LockMode::Attach,
CLOTHING_LOCKED,
&[FolderKey::Clothing],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByPath::test 93e1721f171e24e540160e738f731b895ebd868d840bcdf7c16ba92f6eb4c49a translated
#[test]
fn attach_this_by_path() {
assert!(folder_case_matches(
"@attachthis:Clothing/Hats=n",
None,
Setup::None,
LockMode::Attach,
HATS_LOCKED,
&[FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByRlvAttachmentPoint::test 90a562b2c120daa0ea2612befe9e09649bc2ffac59c2cd360fe4a37dedf85ae3 translated
#[test]
fn attach_this_by_attachment_point() {
assert!(folder_case_matches(
"@attachthis:pelvis=n",
None,
Setup::PartyAndBusinessPelvis,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByWornLayer::test a444d51c2091fa36f1a010e98ad896042aa0262153ea8a833a14dfcbf02de85e translated
#[test]
fn attach_this_by_worn_layer() {
assert!(folder_case_matches(
"@attachthis:tattoo=n",
None,
Setup::WatchTattoo,
LockMode::Attach,
ACCESSORIES_LOCKED,
&[FolderKey::Accessories],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByWornLayer_AddRem::test dd3d9a0d9b56f08f6be7a6200e1f50e834ecc7613de0cdf44ee89262b3abdb30 translated
#[test]
fn attach_this_by_worn_layer_removed() {
assert!(folder_case_matches(
"@attachthis:tattoo=n,@attachthis:tattoo=y",
None,
Setup::WatchTattoo,
LockMode::Attach,
ALL_ALLOWED,
&[],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis::test ee74f952bd602bd23cfc7b203940a902e1b30e02cff60c1abc1f74da964c1f7d translated
#[test]
fn detach_all_this() {
assert!(folder_case_matches(
"@detachallthis=n",
Some((PRIM_3, "Party Hat (Spine)")),
Setup::PartySpine,
LockMode::Detach,
HATS_LOCKED,
&[FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive::test 2b6a646ee82484a6d1901ea4425b0e32fe553827f5bea37b506ffe29d1aec192 translated
#[test]
fn detach_all_this_recursive() {
assert!(folder_case_matches(
"@detachallthis=n",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessPelvis,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Path::test 731244b623f23a8870d011280a062add751607ce2c58be3261485bb61d488297 translated
#[test]
fn detach_all_this_recursive_path() {
assert!(folder_case_matches(
"@detachallthis:Clothing=n",
None,
Setup::None,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Worn::test d8424a48e64346edd683b7a68652dd5a0be615658f085b0390699ac7b4db5d2c translated
#[test]
fn detach_all_this_recursive_worn() {
assert!(folder_case_matches(
"@detachallthis:pants=n",
None,
Setup::RetroPants,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Attached::test f399592217e7a4638ea25d469681ab9cc58bf8a937af2bfff8895996f7bbc493 translated
#[test]
fn detach_all_this_recursive_attached() {
assert!(folder_case_matches(
"@detachallthis:chest=n",
None,
Setup::BusinessChest,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Attached_AddRem::test 507273250b932ff93fa34f87190ad1ab289edeed275be6d2259bab05c5b055d1 translated
#[test]
fn detach_all_this_recursive_attached_removed() {
assert!(folder_case_matches(
"@detachallthis:chest=n,@detachallthis:chest=y",
None,
Setup::BusinessChest,
LockMode::Detach,
ALL_ALLOWED,
&[],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis::test bf6cdb48a5271d5116db4d0cbf12dbf63fc3cc93862bf718cf849d4abf9eb7cc translated
#[test]
fn detach_this() {
assert!(folder_case_matches(
"@detachthis=n",
Some((PRIM_3, "Party Hat (Spine)")),
Setup::PartySpine,
LockMode::Detach,
HATS_LOCKED,
&[FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_NotRecursive::test a8452e2b0abcf82447394bae981a1d25677147fad17828d8f6d0705264efa429 translated
#[test]
fn detach_this_not_recursive() {
assert!(folder_case_matches(
"@detachthis=n",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessPelvis,
LockMode::Detach,
CLOTHING_LOCKED,
&[FolderKey::Clothing],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByPath::test e6378e0db310005b8426cabd25969818ed36252e1995de97c6b29d5ab155ee58 translated
#[test]
fn detach_this_by_path() {
assert!(folder_case_matches(
"@detachthis:Clothing=n",
None,
Setup::None,
LockMode::Detach,
CLOTHING_LOCKED,
&[FolderKey::Clothing],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByRlvAttachmentPoint::test 278e4cbf0f9999efec04fcabade19da97439cca732e0e7e3e3c004e232c27224 translated
#[test]
fn detach_this_by_attachment_point() {
assert!(folder_case_matches(
"@detachthis:pelvis=n",
None,
Setup::PartyAndBusinessPelvisDetach,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByWornLayer::test 66b7eba54e34ed58c59d594cdcb85d874c4db9bbbd871e5438c40fd3d47ad3f6 translated
#[test]
fn detach_this_by_worn_layer() {
assert!(folder_case_matches(
"@detachthis:tattoo=n",
None,
Setup::WatchTattoo,
LockMode::Detach,
ACCESSORIES_LOCKED,
&[FolderKey::Accessories],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByWornLayer_AddRem::test 7424bf38db1abd74132618ee3bcf95a79c32942da26086760dc82355a815d37e translated
#[test]
fn detach_this_by_worn_layer_removed() {
assert!(folder_case_matches(
"@detachthis:tattoo=n,@detachthis:tattoo=y",
None,
Setup::WatchTattoo,
LockMode::Detach,
ALL_ALLOWED,
&[],
));
}

View File

@@ -0,0 +1,424 @@
//! Exact Rust translations of every `detach`/`remattach` alias case.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvInventoryItem, RlvWearableType};
use libremetaverse_types::compat::Guid;
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const FANCY: &str = "d1111111-dddd-4ddd-8ddd-dddddddddddd";
const EXTERNAL: &str = "12312312-0002-4aaa-8aaa-aaaaaaaaaaaa";
const PRIM1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
const EXTERNAL_PRIM: &str = "12312312-0002-4aaa-8aaa-ffffffffffff";
#[derive(Clone, Copy)]
enum Setup {
Normal,
NoStrip,
NoStripLink,
External,
Folder,
FolderNoStrip,
FolderLink,
Point,
PointNoStrip,
PointLink,
PointNone,
Uuid,
UuidItemNoStrip,
UuidFolderNoStrip,
UuidFolderLink,
UuidRestricted,
UuidExternal,
}
fn attach(item: &mut RlvInventoryItem, point: RlvAttachmentPoint, prim: &str) {
item.set_attached_to(Some(Some(point)));
item.set_attached_prim_id(Some(Some(guid(prim))));
}
fn external(
id: &str,
name: &str,
point: Option<RlvAttachmentPoint>,
prim: Option<&str>,
worn: Option<RlvWearableType>,
) -> RlvInventoryItem {
RlvInventoryItem::new(
guid(id),
name.into(),
false,
Some(Some(guid("12312312-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))),
point.map(Some),
prim.map(|v| Some(guid(v))),
worn.map(Some),
None,
)
.unwrap()
}
fn base(tree: &mut SampleInventoryTree) {
attach(&mut tree.happy_shirt, RlvAttachmentPoint::Chest, PRIM1);
attach(
&mut tree.fancy_hat,
RlvAttachmentPoint::Chin,
"11111111-0003-4aaa-8aaa-ffffffffffff",
);
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
}
#[allow(clippy::too_many_lines)]
fn run(command: &str, setup: Setup) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
let mut external_items = vec![];
base(&mut tree);
match setup {
Setup::NoStrip | Setup::NoStripLink => {
tree.hats.set_name("nostrip Hats".into());
tree.happy_shirt.set_name("nostrip Happy Shirt".into());
attach(
&mut tree.retro_pants,
RlvAttachmentPoint::Groin,
"11111111-0005-4aaa-8aaa-ffffffffffff",
);
if matches!(setup, Setup::NoStripLink) {
tree.fancy_hat.set_is_link(true);
}
}
Setup::External => {
external_items.push(external(
"12312312-0001-4aaa-8aaa-aaaaaaaaaaaa",
"External Tattoo",
None,
None,
Some(RlvWearableType::Tattoo),
));
external_items.push(external(
EXTERNAL,
"External Jaw Thing",
Some(RlvAttachmentPoint::Jaw),
Some(EXTERNAL_PRIM),
None,
));
}
Setup::FolderNoStrip | Setup::FolderLink => {
tree.hats.set_name("nostrip Hats".into());
if matches!(setup, Setup::FolderLink) {
tree.fancy_hat.set_is_link(true);
}
}
Setup::Point => external_items.push(external(
EXTERNAL,
"External Chest Thing",
Some(RlvAttachmentPoint::Chest),
Some(EXTERNAL_PRIM),
None,
)),
Setup::PointNoStrip | Setup::PointLink => {
tree.hats.set_name("nostrip Hats".into());
tree.happy_shirt.set_name("nostrip Happy Shirt".into());
attach(
&mut tree.fancy_hat,
RlvAttachmentPoint::Chest,
"11111111-0003-4aaa-8aaa-ffffffffffff",
);
attach(
&mut tree.retro_pants,
RlvAttachmentPoint::Chest,
"11111111-0005-4aaa-8aaa-ffffffffffff",
);
if matches!(setup, Setup::PointLink) {
tree.fancy_hat.set_is_link(true);
}
external_items.push(external(
EXTERNAL,
"External Chest Thing",
Some(RlvAttachmentPoint::Chest),
Some(EXTERNAL_PRIM),
None,
));
external_items.push(external(
"12312312-0003-4aaa-8aaa-aaaaaaaaaaaa",
"nostrip External Chest Thing",
Some(RlvAttachmentPoint::Chest),
Some("12312312-0003-4aaa-8aaa-ffffffffffff"),
None,
));
}
Setup::UuidItemNoStrip => tree.happy_shirt.set_name("nostrip Happy Shirt".into()),
Setup::UuidFolderNoStrip | Setup::UuidFolderLink => {
tree.clothing.set_name("nostrip Clothing".into());
if matches!(setup, Setup::UuidFolderLink) {
tree.happy_shirt.set_is_link(true);
}
}
Setup::UuidExternal => external_items.push(external(
EXTERNAL,
"External Jaw Thing",
Some(RlvAttachmentPoint::Jaw),
Some(EXTERNAL_PRIM),
None,
)),
_ => {}
}
h.queries.lock().unwrap().inventory_map =
Some(InventoryMap::new(tree.root, external_items).unwrap());
if matches!(setup, Setup::UuidRestricted) {
block_on(h.process("@detachallthis:Clothing=n")).unwrap();
}
block_on(h.process(command)).unwrap();
let mut v = h.actions.lock().unwrap().detachments[0].clone();
v.sort_by_key(|id| id.0);
v
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut v: Vec<_> = values.iter().map(|s| guid(s)).collect();
v.sort_by_key(|id| id.0);
v
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach::case:bb1d34dc76ade75f 16420d56c60229e8d8b6a2a0d63b1f500112c23cef451d69bb0ed97fe9b63bae translated
#[test]
fn detach_all_attachments() {
assert_eq!(run("@detach=force", Setup::Normal), ids(&[HAPPY, FANCY]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach::case:c9faa5be8fef55e8 16420d56c60229e8d8b6a2a0d63b1f500112c23cef451d69bb0ed97fe9b63bae translated
#[test]
fn remattach_all_attachments() {
assert_eq!(run("@remattach=force", Setup::Normal), ids(&[HAPPY, FANCY]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip::case:bb1d34dc76ade75f 5b3f1cbe99833e16c6f10ef568618627445babbcdfc9be555b48257bfdffeea7 translated
#[test]
fn detach_honors_nostrip() {
assert_eq!(run("@detach=force", Setup::NoStrip), ids(&[RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip::case:c9faa5be8fef55e8 5b3f1cbe99833e16c6f10ef568618627445babbcdfc9be555b48257bfdffeea7 translated
#[test]
fn remattach_honors_nostrip() {
assert_eq!(run("@remattach=force", Setup::NoStrip), ids(&[RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip_LinkException::case:bb1d34dc76ade75f 96a4b53d9e55dcd656c25af6619a3d0d67f5bc2517a759d722559a4ffb225472 translated
#[test]
fn detach_honors_nostrip_link_exception() {
assert_eq!(
run("@detach=force", Setup::NoStripLink),
ids(&[RETRO, FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip_LinkException::case:c9faa5be8fef55e8 96a4b53d9e55dcd656c25af6619a3d0d67f5bc2517a759d722559a4ffb225472 translated
#[test]
fn remattach_honors_nostrip_link_exception() {
assert_eq!(
run("@remattach=force", Setup::NoStripLink),
ids(&[RETRO, FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ExternalItems::case:bb1d34dc76ade75f 7545f36532fcb7974a9e009e567b2342754a11da95eb3f17ee04089dcec42664 translated
#[test]
fn detach_external_items() {
assert_eq!(
run("@detach=force", Setup::External),
ids(&[HAPPY, FANCY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ExternalItems::case:c9faa5be8fef55e8 7545f36532fcb7974a9e009e567b2342754a11da95eb3f17ee04089dcec42664 translated
#[test]
fn remattach_external_items() {
assert_eq!(
run("@remattach=force", Setup::External),
ids(&[HAPPY, FANCY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder::case:97eb7af1f9c3c62c 583d3f596c80411d950038e3ec64032bee75150b8c819741fe89a4ca40eb2553 translated
#[test]
fn detach_by_folder() {
assert_eq!(
run("@detach:Clothing/Hats=force", Setup::Folder),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder::case:1a04fd408fddaac0 583d3f596c80411d950038e3ec64032bee75150b8c819741fe89a4ca40eb2553 translated
#[test]
fn remattach_by_folder() {
assert_eq!(
run("@remattach:Clothing/Hats=force", Setup::Folder),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip::case:2117c838922f5ba4 3a21b8ae807126d6f93ac95e16c47330b4146ace9781e9c9665ad493ee8c48b1 translated
#[test]
fn detach_by_folder_honors_nostrip() {
assert!(run("@detach:Clothing/nostrip Hats=force", Setup::FolderNoStrip).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip::case:11d4ca4fd3e35db1 3a21b8ae807126d6f93ac95e16c47330b4146ace9781e9c9665ad493ee8c48b1 translated
#[test]
fn remattach_by_folder_honors_nostrip() {
assert!(
run(
"@remattach:Clothing/nostrip Hats=force",
Setup::FolderNoStrip
)
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip_LinkException::case:2117c838922f5ba4 7c00e7dc70b3078d75009cf78a9fece889eee85f237c1a3c79c6249ae5e5327f translated
#[test]
fn detach_by_folder_honors_link_exception() {
assert_eq!(
run("@detach:Clothing/nostrip Hats=force", Setup::FolderLink),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip_LinkException::case:11d4ca4fd3e35db1 7c00e7dc70b3078d75009cf78a9fece889eee85f237c1a3c79c6249ae5e5327f translated
#[test]
fn remattach_by_folder_honors_link_exception() {
assert_eq!(
run("@remattach:Clothing/nostrip Hats=force", Setup::FolderLink),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint::case:644d3f75f3570ac3 e09627228c1cf8311e56ac6660389bc1b268db8fd4f883dc40aaf3d2ec00916b translated
#[test]
fn detach_by_attachment_point() {
assert_eq!(
run("@detach:chest=force", Setup::Point),
ids(&[HAPPY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint::case:53be219b37533fa6 e09627228c1cf8311e56ac6660389bc1b268db8fd4f883dc40aaf3d2ec00916b translated
#[test]
fn remattach_by_attachment_point() {
assert_eq!(
run("@remattach:chest=force", Setup::Point),
ids(&[HAPPY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip::case:644d3f75f3570ac3 ffaaad92700d5d606154abdddd05c24c7584c5c3e55290df61e2b2a71d8148d7 translated
#[test]
fn detach_by_attachment_point_honors_nostrip() {
assert_eq!(
run("@detach:chest=force", Setup::PointNoStrip),
ids(&[RETRO, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip::case:53be219b37533fa6 ffaaad92700d5d606154abdddd05c24c7584c5c3e55290df61e2b2a71d8148d7 translated
#[test]
fn remattach_by_attachment_point_honors_nostrip() {
assert_eq!(
run("@remattach:chest=force", Setup::PointNoStrip),
ids(&[RETRO, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip_LinkException::case:644d3f75f3570ac3 af1b1caf070a186bc2b02b598919b52d47c289d708fde3713e48ce1a40d7c025 translated
#[test]
fn detach_by_attachment_point_honors_link_exception() {
assert_eq!(
run("@detach:chest=force", Setup::PointLink),
ids(&[RETRO, FANCY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip_LinkException::case:53be219b37533fa6 af1b1caf070a186bc2b02b598919b52d47c289d708fde3713e48ce1a40d7c025 translated
#[test]
fn remattach_by_attachment_point_honors_link_exception() {
assert_eq!(
run("@remattach:chest=force", Setup::PointLink),
ids(&[RETRO, FANCY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_None::case:9a124e69f33b279f afed603254ad6048a46e157254f16253063e6c76c9ea16f46a69d8455bc0e6fb translated
#[test]
fn detach_by_missing_attachment_point() {
assert!(run("@detach:skull=force", Setup::PointNone).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_None::case:800d7d8ba57071b1 afed603254ad6048a46e157254f16253063e6c76c9ea16f46a69d8455bc0e6fb translated
#[test]
fn remattach_by_missing_attachment_point() {
assert!(run("@remattach:skull=force", Setup::PointNone).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID::case:e5bdbdba9613b46a 4b1a8acea7f1bb100bf11e9329672c64b53aba4974558f1c693460eef7f56c2d translated
#[test]
fn detach_by_uuid() {
assert_eq!(
run(&format!("@detach:{PRIM1}=force"), Setup::Uuid),
ids(&[HAPPY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID::case:7cb3f81460bd8e9f 4b1a8acea7f1bb100bf11e9329672c64b53aba4974558f1c693460eef7f56c2d translated
#[test]
fn remattach_by_uuid() {
assert_eq!(
run(&format!("@remattach:{PRIM1}=force"), Setup::Uuid),
ids(&[HAPPY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInItemName::case:e5bdbdba9613b46a 6857733912b45ef9153b0f58cd74ae6c9dc0034fa10933d153cae88a2c7d9423 translated
#[test]
fn detach_by_uuid_honors_item_nostrip() {
assert!(run(&format!("@detach:{PRIM1}=force"), Setup::UuidItemNoStrip).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInItemName::case:7cb3f81460bd8e9f 6857733912b45ef9153b0f58cd74ae6c9dc0034fa10933d153cae88a2c7d9423 translated
#[test]
fn remattach_by_uuid_honors_item_nostrip() {
assert!(run(&format!("@remattach:{PRIM1}=force"), Setup::UuidItemNoStrip).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName::case:e5bdbdba9613b46a 1a3189f931e086ab3d2d3e99c53dba2e9d39dce75a52fd02400c6892aef5d0c4 translated
#[test]
fn detach_by_uuid_honors_folder_nostrip() {
assert!(run(&format!("@detach:{PRIM1}=force"), Setup::UuidFolderNoStrip).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName::case:7cb3f81460bd8e9f 1a3189f931e086ab3d2d3e99c53dba2e9d39dce75a52fd02400c6892aef5d0c4 translated
#[test]
fn remattach_by_uuid_honors_folder_nostrip() {
assert!(
run(
&format!("@remattach:{PRIM1}=force"),
Setup::UuidFolderNoStrip
)
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName_LinkException::case:e5bdbdba9613b46a bd7bc72a107b4a21b00977e13b086da192bef2c2e6f0fdb73b8e332016c6ef23 translated
#[test]
fn detach_by_uuid_honors_folder_link_exception() {
assert_eq!(
run(&format!("@detach:{PRIM1}=force"), Setup::UuidFolderLink),
ids(&[HAPPY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName_LinkException::case:7cb3f81460bd8e9f bd7bc72a107b4a21b00977e13b086da192bef2c2e6f0fdb73b8e332016c6ef23 translated
#[test]
fn remattach_by_uuid_honors_folder_link_exception() {
assert_eq!(
run(&format!("@remattach:{PRIM1}=force"), Setup::UuidFolderLink),
ids(&[HAPPY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_WithRestrictions::case:e5bdbdba9613b46a 2ecf40d1d338117ddac4cfd6c7a030e96b7adf72cd90e0d8327787317e1f38d7 translated
#[test]
fn detach_by_uuid_honors_restrictions() {
assert!(run(&format!("@detach:{PRIM1}=force"), Setup::UuidRestricted).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_WithRestrictions::case:7cb3f81460bd8e9f 2ecf40d1d338117ddac4cfd6c7a030e96b7adf72cd90e0d8327787317e1f38d7 translated
#[test]
fn remattach_by_uuid_honors_restrictions() {
assert!(run(&format!("@remattach:{PRIM1}=force"), Setup::UuidRestricted).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_External::case:e5bdbdba9613b46a e0bdc682df3416bdc01855e6e63974e64c21951aac629807352220baf572dded translated
#[test]
fn detach_external_by_uuid() {
assert_eq!(
run(
&format!("@detach:{EXTERNAL_PRIM}=force"),
Setup::UuidExternal
),
ids(&[EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_External::case:7cb3f81460bd8e9f e0bdc682df3416bdc01855e6e63974e64c21951aac629807352220baf572dded translated
#[test]
fn remattach_external_by_uuid() {
assert_eq!(
run(
&format!("@remattach:{EXTERNAL_PRIM}=force"),
Setup::UuidExternal
),
ids(&[EXTERNAL])
);
}

View File

@@ -0,0 +1,257 @@
//! Exact Rust translations of `RemOutfitCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvInventoryItem, RlvWearableType};
use libremetaverse_types::compat::Guid;
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const WATCH: &str = "c0000000-cccc-4ccc-8ccc-cccccccccccc";
const PARTY: &str = "d0000000-dddd-4ddd-8ddd-dddddddddddd";
const FANCY: &str = "d1111111-dddd-4ddd-8ddd-dddddddddddd";
const EXTERNAL1: &str = "12312312-0001-4aaa-8aaa-aaaaaaaaaaaa";
const EXTERNAL2: &str = "12312312-0002-4aaa-8aaa-aaaaaaaaaaaa";
#[derive(Clone, Copy)]
enum Setup {
All,
PrivateClothing,
External,
ExternalNoStrip,
ExternalNoStripLink,
ExternalByType,
Folder,
PrivateFolder,
FolderNoStripItem,
FolderNoStripName,
FolderNoStripNameLink,
Specific,
SpecificPrivate,
SpecificNoStrip,
SpecificNoStripLink,
BodyPart,
}
fn external(id: &str, name: &str) -> RlvInventoryItem {
RlvInventoryItem::new(
guid(id),
name.into(),
false,
Some(Some(guid("12312312-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))),
None,
None,
Some(Some(RlvWearableType::Tattoo)),
None,
)
.unwrap()
}
fn base_worn(tree: &mut SampleInventoryTree) {
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Shirt)));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.party_hat
.set_worn_on(Some(Some(RlvWearableType::Skin)));
}
fn run(command: &str, setup: Setup) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
let mut external_items = vec![];
match setup {
Setup::All | Setup::Folder | Setup::Specific | Setup::BodyPart => base_worn(&mut tree),
Setup::PrivateClothing => {
base_worn(&mut tree);
tree.clothing.set_name(".Clothing".into());
}
Setup::External | Setup::ExternalByType => {
base_worn(&mut tree);
external_items.push(external(EXTERNAL1, "External Tattoo"));
}
Setup::ExternalNoStrip | Setup::ExternalNoStripLink => {
base_worn(&mut tree);
tree.hats.set_name("nostrip Hats".into());
tree.happy_shirt.set_name("nostrip Happy Shirt".into());
if matches!(setup, Setup::ExternalNoStripLink) {
tree.fancy_hat.set_is_link(true);
}
external_items.push(external(EXTERNAL1, "External Tattoo"));
external_items.push(external(EXTERNAL2, "nostrip External Tattoo"));
}
Setup::PrivateFolder | Setup::SpecificPrivate => {
base_worn(&mut tree);
tree.hats.set_name(".Hats".into());
}
Setup::FolderNoStripItem => {
base_worn(&mut tree);
tree.fancy_hat.set_name("nostrip Fancy Hat".into());
}
Setup::FolderNoStripName | Setup::FolderNoStripNameLink => {
base_worn(&mut tree);
tree.hats.set_name("nostrip Hats".into());
if matches!(setup, Setup::FolderNoStripNameLink) {
tree.fancy_hat.set_is_link(true);
}
}
Setup::SpecificNoStrip | Setup::SpecificNoStripLink => {
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.party_hat
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.glasses
.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.watch.set_name("nostrip Watch".into());
tree.clothing.set_name("nostrip clothing".into());
if matches!(setup, Setup::SpecificNoStripLink) {
tree.retro_pants.set_is_link(true);
}
}
}
h.queries.lock().unwrap().inventory_map =
Some(InventoryMap::new(tree.root, external_items).unwrap());
block_on(h.process(command)).unwrap();
let mut ids = h.actions.lock().unwrap().removed_outfits[0].clone();
ids.sort_by_key(|id| id.0);
ids
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut result: Vec<_> = values.iter().map(|value| guid(value)).collect();
result.sort_by_key(|id| id.0);
result
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit::test 60bd0e62bbd4613c4d2d1a65705644dc25fd7327408adfc0bb7e95c45d79cdcb translated
#[test]
fn remove_outfit() {
assert_eq!(
run("@remoutfit=force", Setup::All),
ids(&[RETRO, HAPPY, WATCH, FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_PrivateFolders::test d79ac3806f50915390edd0a24b756ef398c1334017f69d16f4cb887dcdd41fb1 translated
#[test]
fn remove_outfit_in_private_folders() {
assert_eq!(
run("@remoutfit=force", Setup::PrivateClothing),
ids(&[RETRO, HAPPY, WATCH, FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems::test 0265a9fee1070cbcc458bfcb05fe267991cbdb5480500c1b32aace1eb4935217 translated
#[test]
fn remove_outfit_external_items() {
assert_eq!(
run("@remoutfit=force", Setup::External),
ids(&[RETRO, HAPPY, WATCH, FANCY, EXTERNAL1])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_NoStrip::test b93d39d919fb70b02ccdb724969f7b983c726c707bca96e1b1ddc6ee248a734f translated
#[test]
fn remove_outfit_external_items_honors_nostrip() {
assert_eq!(
run("@remoutfit=force", Setup::ExternalNoStrip),
ids(&[RETRO, WATCH, EXTERNAL1])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_NoStrip_LinkException::test 5ecc44228573645e0a0c78d100dab54b793c6ce8dc50a02d79a919fe6d7c1678 translated
#[test]
fn remove_outfit_external_items_honors_link_exception() {
assert_eq!(
run("@remoutfit=force", Setup::ExternalNoStripLink),
ids(&[RETRO, WATCH, FANCY, EXTERNAL1])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_ByType::test 8ba106f071f8768af1d6213c04f67dd0aec846ae47552686eba86c489bdb0292 translated
#[test]
fn remove_outfit_external_items_by_type() {
assert_eq!(
run("@remoutfit:tattoo=force", Setup::ExternalByType),
ids(&[FANCY, WATCH, EXTERNAL1])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder::test 45f9e7a9d0ef99ec7d58b59f1c1db7b6065994939717842bb02486b470b357b5 translated
#[test]
fn remove_outfit_folder() {
assert_eq!(
run("@remoutfit:Clothing/Hats=force", Setup::Folder),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_PrivateFolder::test 68f3050a1b667304ff2b252690cc7d1994964dbd2c7633d54e5c6654714c0aed translated
#[test]
fn remove_outfit_private_folder() {
assert_eq!(
run("@remoutfit:Clothing/Hats=force", Setup::PrivateFolder),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStrip::test d56b83a72d6d3529af0390674550ce40733c14de6210cf71e277f0e195d1e330 translated
#[test]
fn remove_outfit_folder_honors_item_nostrip() {
assert!(run("@remoutfit:Clothing/Hats=force", Setup::FolderNoStripItem).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStripFolderName::test a28f5517a9d05085627d5acaf33441d598912301962f6e99aaff49ef5114af53 translated
#[test]
fn remove_outfit_folder_honors_folder_nostrip() {
assert!(
run(
"@remoutfit:Clothing/nostrip Hats=force",
Setup::FolderNoStripName
)
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStripFolderName_LinkException::test 80efc201f976365e68d32ae1b30db0f10a17cbc65aedc82895ffa679700008da translated
#[test]
fn remove_outfit_folder_honors_link_exception() {
assert_eq!(
run(
"@remoutfit:Clothing/nostrip Hats=force",
Setup::FolderNoStripNameLink
),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific::test 7235143679739442ec942d294a8a68f69b7fb5678ed4e3ca03be35c74e9c71a9 translated
#[test]
fn remove_outfit_specific() {
assert_eq!(
run("@remoutfit:tattoo=force", Setup::Specific),
ids(&[FANCY, WATCH])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_PrivateFolder::test 3feea26f000dc7eb86b1413f1a5bdd5f109c5f9f969918cd1ce2e7f926f26c12 translated
#[test]
fn remove_outfit_specific_private_folder() {
assert_eq!(
run("@remoutfit:tattoo=force", Setup::SpecificPrivate),
ids(&[FANCY, WATCH])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_NoStrip::test 6e4b8bc53933a889df1cf553ca7e0601e5061bb87013a4075c2ff357cc9d987f translated
#[test]
fn remove_outfit_specific_honors_nostrip() {
assert_eq!(
run("@remoutfit:pants=force", Setup::SpecificNoStrip),
ids(&[PARTY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_NoStrip_LinkException::test 72b1409f70531d859f15a012cb1fb03d795d2065c5d03b7a263d352ca4b80e98 translated
#[test]
fn remove_outfit_specific_honors_link_exception() {
assert_eq!(
run("@remoutfit:pants=force", Setup::SpecificNoStripLink),
ids(&[PARTY, RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_BodyPart_Specific::test 13804c96395db86821371dc8f2cacd2cb182338f8ea88034afcc5da19e3f0691 translated
#[test]
fn remove_outfit_does_not_remove_body_part() {
assert!(run("@remoutfit:skin=force", Setup::BodyPart).is_empty());
}

View File

@@ -0,0 +1,256 @@
// Exact Rust translations of RlvRestrictionManagerTests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::RlvRestrictionType;
use libremetaverse_types::compat::Guid;
use std::sync::{Arc, Mutex};
const PRIM_1: &str = "11111111-1111-1111-1111-111111111111";
const PRIM_2: &str = "22222222-2222-2222-2222-222222222222";
const PRIM_3: &str = "33333333-3333-3333-3333-333333333333";
const MISSING: &str = "99999999-9999-9999-9999-999999999999";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process_from(h: &RlvHarness, sender: &str, commands: &[&str]) {
for command in commands {
block_on(h.process_from(command, sender, "TestObject")).unwrap();
}
}
fn tracked(h: &RlvHarness) -> Vec<Guid> {
h.service
.restrictions()
.get_tracked_prim_ids()
.unwrap()
.collect()
}
async fn remove(h: &RlvHarness, ids: Vec<Guid>) {
h.service
.restrictions()
.remove_restrictions_for_objects(Box::new(ids.into_iter()), None)
.await
.unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_NoRestrictions_ReturnsEmptyCollection::test 327086a5aa514ddf8b2cc40891f7ae5e8039788f5cbfeda86f04bd9161f39ded translated
#[test]
fn tracked_prim_ids_empty() {
assert!(tracked(&harness()).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_SingleRestriction_ReturnsSingleId::test 85a822c9e2e8beb2e70748513a397b8ccbb2977c0581b0519bd8ad43e699ad57 translated
#[test]
fn tracked_prim_ids_single_restriction() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
assert_eq!(tracked(&h), vec![guid(PRIM_1)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MultipleRestrictionsFromSameObject_ReturnsSingleId::test 933070f933b0a5a39b3d0cd5fd9be9423a538609d0106b352a7d9c339665d6d1 translated
#[test]
fn tracked_prim_ids_deduplicates_one_object() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n", "@jump=n", "@sit=n"]);
assert_eq!(tracked(&h), vec![guid(PRIM_1)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MultipleObjects_ReturnsAllUniqueIds::test 8c2afe66145e4815e73d7849f83cfec50e4a7a49793cc757917cd608c9387419 translated
#[test]
fn tracked_prim_ids_multiple_objects() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
process_from(&h, PRIM_2, &["@jump=n"]);
process_from(&h, PRIM_3, &["@sit=n"]);
let ids = tracked(&h);
assert_eq!(ids.len(), 3);
assert!(ids.contains(&guid(PRIM_1)));
assert!(ids.contains(&guid(PRIM_2)));
assert!(ids.contains(&guid(PRIM_3)));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MixedRestrictionsAndExceptions_ReturnsAllUniqueIds::test 25ea3c36aba93d5183816962bf49bfdbc3e17e6b06d73a41dee5b51407a84746 translated
#[test]
fn tracked_prim_ids_include_restrictions_and_exceptions() {
let h = harness();
process_from(&h, PRIM_1, &["@detachthis=n"]);
process_from(&h, PRIM_2, &["@detachthis_except:folder=n"]);
let ids = tracked(&h);
assert_eq!(ids.len(), 2);
assert!(ids.contains(&guid(PRIM_1)));
assert!(ids.contains(&guid(PRIM_2)));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_AfterRemovingRestriction_DoesNotReturnRemovedObjectId::test af3d5328e5c829bd2de2b72c3f4ede6f083efa789ccef1d73d752612a177360f translated
#[test]
fn tracked_prim_ids_after_removing_restriction() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
process_from(&h, PRIM_2, &["@jump=n"]);
process_from(&h, PRIM_1, &["@fly=y"]);
let ids = tracked(&h);
assert_eq!(ids, vec![guid(PRIM_2)]);
assert!(!ids.contains(&guid(PRIM_1)));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_AfterClearingAllRestrictions_ReturnsEmptyCollection::test 191a8cc3dba7e68155083a6892f1b4a29ab589023e22cffbc8cd69c005884cca translated
#[test]
fn tracked_prim_ids_after_clear() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n", "@jump=n", "@clear"]);
assert!(tracked(&h).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_EmptyInput_NoEffect::test 8718e08bb2bf951a94803b4947943b5f7f9eb85e906b4ac6c639cb8cd065cf9d translated
#[test]
fn remove_restrictions_empty_input() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
block_on(remove(&h, vec![]));
assert!(!h.service.permissions().can_fly().unwrap());
assert_eq!(tracked(&h).len(), 1);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_NonExistentId_NoEffect::test 882d2315f40317cce9c9a026eda498325b6227886652795ed45e87cc4e5697ac translated
#[test]
fn remove_restrictions_missing_id() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
block_on(remove(&h, vec![guid(MISSING)]));
assert!(!h.service.permissions().can_fly().unwrap());
assert_eq!(tracked(&h), vec![guid(PRIM_1)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_SingleObject_RemovesAllRestrictionsFromObject::test 73ab6ee30a336372f6aef5bc4a99dbb58215b9445daea5d9708d0ea9cabe8bd1 translated
#[test]
fn remove_restrictions_single_object() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n", "@jump=n", "@sit=n"]);
assert!(!h.service.permissions().can_fly().unwrap());
assert!(!h.service.permissions().can_jump().unwrap());
block_on(remove(&h, vec![guid(PRIM_1)]));
assert!(h.service.permissions().can_fly().unwrap());
assert!(h.service.permissions().can_jump().unwrap());
assert!(tracked(&h).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_MultipleObjects_RemovesOnlySpecifiedObjects::test 03b6a6a3e02f6a6a5f296ff1d6cca31c9fc53982cbc9c27e73cfb698ed82acf5 translated
#[test]
fn remove_restrictions_multiple_objects() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
process_from(&h, PRIM_2, &["@jump=n"]);
process_from(&h, PRIM_3, &["@sit=n"]);
assert!(!h.service.permissions().can_fly().unwrap());
assert!(!h.service.permissions().can_jump().unwrap());
block_on(remove(&h, vec![guid(PRIM_1), guid(PRIM_3)]));
assert!(h.service.permissions().can_fly().unwrap());
assert!(!h.service.permissions().can_jump().unwrap());
assert_eq!(tracked(&h), vec![guid(PRIM_2)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_PartialMatch_RemovesOnlyMatchingObjects::test 00a26d807882b2bbb375c5ce7cf1074d3227acd891e859602e78abbdc6eefb6a translated
#[test]
fn remove_restrictions_partial_match() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
process_from(&h, PRIM_2, &["@jump=n"]);
block_on(remove(&h, vec![guid(PRIM_1), guid(MISSING)]));
assert!(h.service.permissions().can_fly().unwrap());
assert!(!h.service.permissions().can_jump().unwrap());
assert_eq!(tracked(&h), vec![guid(PRIM_2)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_WithNotificationRestrictions_SendsNotifications::test ba82b183dfdb01b36f9b45520e1808290c360f327d4afa833ba3b8c7a7cecffb translated
#[test]
fn remove_restrictions_sends_notification() {
let h = harness();
process_from(&h, PRIM_2, &["@notify:123=n"]);
process_from(&h, PRIM_1, &["@fly=n"]);
block_on(remove(&h, vec![guid(PRIM_1)]));
assert_eq!(
h.actions
.lock()
.unwrap()
.replies
.iter()
.filter(|reply| **reply == (123, "/fly=y".into()))
.count(),
1
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_WithComplexRestrictions_RemovesCorrectly::test 631de2d39fa56b29014fae4ce3b57c480f540ad41ce08a0037b7f8bbfcb3c502 translated
#[test]
fn remove_restrictions_complex_types() {
let h = harness();
process_from(
&h,
PRIM_1,
&[
"@detachthis=n",
"@detachthis_except:folder=n",
"@touchfar:1.5=n",
],
);
process_from(&h, PRIM_2, &["@fly=n"]);
assert_eq!(
h.service
.restrictions()
.find_restrictions(None, Some(Some(guid(PRIM_1))))
.unwrap()
.len(),
3
);
assert_eq!(
h.service
.restrictions()
.find_restrictions(None, Some(Some(guid(PRIM_2))))
.unwrap()
.len(),
1
);
block_on(remove(&h, vec![guid(PRIM_1)]));
assert!(
h.service
.restrictions()
.find_restrictions(None, Some(Some(guid(PRIM_1))))
.unwrap()
.is_empty()
);
assert_eq!(
h.service
.restrictions()
.find_restrictions(None, Some(Some(guid(PRIM_2))))
.unwrap()
.len(),
1
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_TriggersRestrictionUpdatedEvent::test 318f1f4207b04d01076d3498aceea781c4889b05cdbef199cdbea43dde355f4c translated
#[test]
fn remove_restrictions_triggers_update_event() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
let removed = Arc::new(Mutex::new(None));
let captured = Arc::clone(&removed);
let _subscription = h
.service
.restrictions()
.subscribe_restriction_updated(Some(Arc::new(move |args| {
if !args.is_new() && args.is_deleted() {
let restriction = args.restriction();
*captured.lock().unwrap() = Some((restriction.behavior(), restriction.sender()));
}
})));
block_on(remove(&h, vec![guid(PRIM_1)]));
assert_eq!(
*removed.lock().unwrap(),
Some((RlvRestrictionType::Fly, guid(PRIM_1)))
);
}

View File

@@ -0,0 +1,383 @@
//! Exact Rust translations of the non-inventory RLV command tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, TeleportCall, guid};
const OBJECT: &str = "00000000-0000-4000-8000-000000000000";
const OTHER_SENDER: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight::test fb3adb86988b10b2d3fe9223324f8a3c1ba7b8c2ea909ee6b57b38c590fed372 translated
#[test]
fn adjust_height() {
let h = harness();
block_on(h.process("@adjustheight:4.3;1.25=force")).unwrap();
assert_eq!(
h.actions.lock().unwrap().adjusted_heights,
vec![(4.3, 1.25, 0.0)]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight_WithDelta::test 1f37a125fd9df8585740d37c711888dfcd92460d86c19077f771d7f3fab54264 translated
#[test]
fn adjust_height_with_delta() {
let h = harness();
block_on(h.process("@adjustheight:4.3;1.25;12.34=force")).unwrap();
assert_eq!(
h.actions.lock().unwrap().adjusted_heights,
vec![(4.3, 1.25, 12.34)]
);
}
fn seed_clear(h: &RlvHarness) {
block_on(h.process("@tploc=n")).unwrap();
block_on(h.process("@tplm=n")).unwrap();
block_on(h.process("@unsit=n")).unwrap();
block_on(h.process("@fly=n")).unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear::test 865d022233930e9582fec5b0e99063f15506a339c430755aba83706b594182ad translated
#[test]
fn clear() {
let h = harness();
seed_clear(&h);
block_on(h.process("@clear")).unwrap();
assert!(
h.service
.restrictions()
.find_restrictions(None, None)
.unwrap()
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_CaseInSensitive::test b70296f9d2b6c9eb8c6dd6e560056ab8320d746a991fafec858812fc2ebb3141 translated
#[test]
fn clear_is_case_insensitive() {
let h = harness();
seed_clear(&h);
block_on(h.process("@cLEaR")).unwrap();
assert!(
h.service
.restrictions()
.find_restrictions(None, None)
.unwrap()
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_SenderBased::test 1ae70737411e18626227c0b15181572c1c623eefce0a8fa1a874b2229c44c38e translated
#[test]
fn clear_is_sender_based() {
let h = harness();
block_on(h.process("@tploc=n")).unwrap();
block_on(h.process("@tplm=n")).unwrap();
block_on(h.process_from("@unsit=n", OTHER_SENDER, "Sender 2")).unwrap();
block_on(h.process_from("@fly=n", OTHER_SENDER, "Sender 2")).unwrap();
block_on(h.process_from("@clear", OTHER_SENDER, "Sender 2")).unwrap();
let permissions = h.service.permissions();
assert_eq!(
[
permissions.can_tp_loc().unwrap(),
permissions.can_tp_lm().unwrap(),
permissions.can_unsit().unwrap(),
permissions.can_fly().unwrap()
],
[false, false, true, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_Filtered::test e0f0b5a42c3baf92fef6a8d4fc2c60dbd6963db6f844fed55b06968f0c9e543f translated
#[test]
fn clear_is_filtered() {
let h = harness();
seed_clear(&h);
block_on(h.process("@clear=tp")).unwrap();
let permissions = h.service.permissions();
assert_eq!(
[
permissions.can_tp_loc().unwrap(),
permissions.can_tp_lm().unwrap(),
permissions.can_unsit().unwrap(),
permissions.can_fly().unwrap()
],
[true, true, false, false]
);
}
fn set_debug(setting: &str, value: &str) -> Vec<(String, String)> {
let h = harness();
block_on(h.process(&format!("@setdebug_{setting}:{value}=force"))).unwrap();
h.actions.lock().unwrap().debug_settings.clone()
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:fa77559e30768d15 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d translated
#[test]
fn set_debug_known_setting() {
assert_eq!(
set_debug("RenderResolutionDivisor", "RenderResolutionDivisor Success"),
vec![(
"renderresolutiondivisor".into(),
"RenderResolutionDivisor Success".into()
)]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:55694f25ed879d95 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d translated
#[test]
fn set_debug_unknown_setting() {
assert_eq!(
set_debug("Unknown Setting", "Unknown Setting Success"),
vec![("unknown setting".into(), "Unknown Setting Success".into())]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Invalid::test 2e0595319ba8e2c9a8280c5b034363ad7998eb740cb6b7fff3d75bb0167c6464 translated
#[test]
fn set_debug_rejects_empty_name() {
let h = harness();
assert!(!block_on(h.process("@setdebug_:42=force")).unwrap());
assert!(h.actions.lock().unwrap().debug_settings.is_empty());
}
fn set_env(setting: &str, value: &str) -> Vec<(String, String)> {
let h = harness();
block_on(h.process(&format!("@setenv_{setting}:{value}=force"))).unwrap();
h.actions.lock().unwrap().environment_settings.clone()
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:f656b648d00a6d91 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1 translated
#[test]
fn set_environment_known_setting() {
assert_eq!(
set_env("Daytime", "Daytime Success"),
vec![("daytime".into(), "Daytime Success".into())]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:55694f25ed879d95 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1 translated
#[test]
fn set_environment_unknown_setting() {
assert_eq!(
set_env("Unknown Setting", "Unknown Setting Success"),
vec![("unknown setting".into(), "Unknown Setting Success".into())]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByName::test fae27e58cd981f5471f4c2b8356bb07aa5e76a57aaf0882d0dbfb86360e077e3 translated
#[test]
fn set_group_by_name() {
let h = harness();
block_on(h.process("@setgroup:Group Name=force")).unwrap();
assert_eq!(
h.actions.lock().unwrap().group_names,
vec![("Group Name".into(), None)]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByNameAndRole::test 408442b86bb8259eb9bbb4cf8a5d3b0830c7ba9357fa04cb6e851511a7a24df1 translated
#[test]
fn set_group_by_name_and_role() {
let h = harness();
block_on(h.process("@setgroup:Group Name;Admin Role=force")).unwrap();
assert_eq!(
h.actions.lock().unwrap().group_names,
vec![("Group Name".into(), Some("Admin Role".into()))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ById::test 27f13c52c8c5e2e4298fee3f4322f9906d5f82e900aa5f46c9a8ffac3a6dfae7 translated
#[test]
fn set_group_by_id() {
let h = harness();
block_on(h.process(&format!("@setgroup:{OBJECT}=force"))).unwrap();
assert_eq!(
h.actions.lock().unwrap().group_ids,
vec![(guid(OBJECT), None)]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByIdAndRole::test e18fd0c318ebd4f9a189418449568b3a34b8f7d3a0097f100a7253c4d5a31bde translated
#[test]
fn set_group_by_id_and_role() {
let h = harness();
block_on(h.process(&format!("@setgroup:{OBJECT};Admin Role=force"))).unwrap();
assert_eq!(
h.actions.lock().unwrap().group_ids,
vec![(guid(OBJECT), Some("Admin Role".into()))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetRotCommandTests.cs::SetRotCommandTests.SetRot::test c3302d63cdda9d72b85dad2749e2684cc26d51c72ddc6ace8275911f8ba67ef4 translated
#[test]
fn set_rotation() {
let h = harness();
block_on(h.process("@setrot:1.5=force")).unwrap();
assert_eq!(h.actions.lock().unwrap().rotations, vec![1.5]);
}
fn sit_harness(is_sitting: bool, exists: bool) -> RlvHarness {
let h = harness();
h.queries.lock().unwrap().is_sitting = is_sitting;
h.queries
.lock()
.unwrap()
.object_exists
.insert(guid(OBJECT), exists);
h
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_Default::test 24e45ba898cb8ed0919369d07a39d0b21982fa4fc4c41eb4835ba765c05e2469 translated
#[test]
fn force_sit() {
let h = sit_harness(false, true);
block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap();
assert_eq!(h.actions.lock().unwrap().sits, vec![guid(OBJECT)]);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileStanding::test 8d179277f6a7f98ead813de7bd02ab5146b46ce240d1d5e4a69037885e5f626a translated
#[test]
fn force_sit_with_unsit_restricted_while_standing() {
let h = sit_harness(false, true);
block_on(h.process("@unsit=n")).unwrap();
block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap();
assert_eq!(h.actions.lock().unwrap().sits, vec![guid(OBJECT)]);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileSeated::test 1f2debd6e644c86698577e1c04db96d6aac43267ceae8de9f28435b62ff92817 translated
#[test]
fn force_sit_rejects_unsit_restriction_while_seated() {
let h = sit_harness(true, true);
block_on(h.process("@unsit=n")).unwrap();
assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
assert!(h.actions.lock().unwrap().sits.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedSit::test 8ac0964fc07bb5e860123ce8de1102c2254ffde28f246896d81f7524c3c87021 translated
#[test]
fn force_sit_rejects_sit_restriction() {
let h = sit_harness(true, true);
block_on(h.process("@sit=n")).unwrap();
assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
assert!(h.actions.lock().unwrap().sits.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedStandTp::test bc0c259477ef5f1e5a76b1081f604ba421c82340f738e37fd52b91a421037cf6 translated
#[test]
fn force_sit_rejects_standtp_restriction() {
let h = sit_harness(true, true);
block_on(h.process("@standtp=n")).unwrap();
assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
assert!(h.actions.lock().unwrap().sits.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_InvalidObject::test 787bfe6fefe3895b4bcb5da027ffeac70bf67c3c7a295dbbf7e1526156290040 translated
#[test]
fn force_sit_rejects_invalid_object() {
let h = sit_harness(false, false);
assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
assert!(h.actions.lock().unwrap().sits.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround::test 2319cd49aaae5ac824bc5ffd4f33a5e4f3f684ebec1dc1f1732071eb44ee1cb8 translated
#[test]
fn force_sit_ground() {
let h = harness();
assert!(block_on(h.process("@sitground=force")).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround_RestrictedSit::test 5ac661e9f7fa93cf6ca76aa69f6d84ac61ebd22f26620203f084777010b6de4d translated
#[test]
fn force_sit_ground_rejects_sit_restriction() {
let h = harness();
block_on(h.process("@sit=n")).unwrap();
assert!(!block_on(h.process("@sitground=force")).unwrap());
}
fn teleport(command: &str) -> Vec<TeleportCall> {
let h = harness();
block_on(h.process(command)).unwrap();
h.actions.lock().unwrap().teleports.clone()
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_Default::test 1613e723da60f84dfb54a7345b96566a055a9b7a017e66b0929d6f37c04b62a3 translated
#[test]
fn teleport_default() {
assert_eq!(
teleport("@tpto:1.5/2.5/3.5=force"),
vec![TeleportCall {
x: 1.5,
y: 2.5,
z: 3.5,
region: None,
look_at: None
}]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegion::test 50c5f63c5cb0da221846fd7c0c7f2d471bef2aa2ab203a9b5bdb4eceeb3d97bf translated
#[test]
fn teleport_with_region() {
assert_eq!(
teleport("@tpto:Region Name/1.5/2.5/3.5=force"),
vec![TeleportCall {
x: 1.5,
y: 2.5,
z: 3.5,
region: Some("Region Name".into()),
look_at: None
}]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegionAndLookAt::test c9030189de7acdad0db5c8f83e49ee0433ec0588a35436ab39cdcf40a4fd4d36 translated
#[test]
#[allow(clippy::approx_constant)] // Exact C# fixture literal, not a PI approximation.
fn teleport_with_region_and_look_at() {
assert_eq!(
teleport("@tpto:Region Name/1.5/2.5/3.5;3.1415=force"),
vec![TeleportCall {
x: 1.5,
y: 2.5,
z: 3.5,
region: Some("Region Name".into()),
look_at: Some(Some(3.1415))
}]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedUnsit::test 4dc00a1048593f7468271a4262cf311a3516ea4a53e288eeca69d1297dafc9f2 translated
#[test]
fn teleport_rejects_unsit_restriction() {
let h = harness();
block_on(h.process("@unsit=n")).unwrap();
assert!(!block_on(h.process("@tpto:1.5/2.5/3.5=force")).unwrap());
assert!(h.actions.lock().unwrap().teleports.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedTpLoc::test 3e1ecc1d04973a496edf9d156e52ba76a93ff431181a3ece93c0e4f82884895a translated
#[test]
fn teleport_rejects_tploc_restriction() {
let h = harness();
block_on(h.process("@tploc=n")).unwrap();
assert!(!block_on(h.process("@tpto:1.5/2.5/3.5=force")).unwrap());
assert!(h.actions.lock().unwrap().teleports.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit::test 2f91e1112e1c4e97b79a4dc7bcd4d4a85f13125bd636f81147ce5b396366ebed translated
#[test]
fn force_unsit() {
let h = harness();
assert!(block_on(h.process("@unsit=force")).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit_RestrictedUnsit::test 2ecf210dc83b06018cdcf44cb44bdf43f1040133e7523542a2e1126d6d98004f translated
#[test]
fn force_unsit_rejects_unsit_restriction() {
let h = harness();
block_on(h.process("@unsit=n")).unwrap();
assert!(!block_on(h.process("@unsit=force")).unwrap());
}

View File

@@ -0,0 +1,329 @@
// Exact Rust translations of the simple RLV permission restrictions.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::{
RlvPermissionsService, RlvPermissionsServiceObjectLocation as ObjectLocation,
RlvPermissionsServiceTouchLocation as TouchLocation,
};
use libremetaverse_types::Error;
fn check_simple(
command: &str,
permission: fn(&RlvPermissionsService) -> Result<bool, Error>,
) -> [bool; 2] {
let h = RlvHarness::new().expect("RlvService constructor");
block_on(h.process(&format!("@{command}=n"))).unwrap();
let restricted = permission(&h.service.permissions()).unwrap();
block_on(h.process(&format!("@{command}=y"))).unwrap();
[restricted, permission(&h.service.permissions()).unwrap()]
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AllowIdleRestrictionTests.cs::AllowIdleRestrictionTests.CanAllowIdle::test 6278bb1a70f024f687080cb8e8a56bbc923f679fb4adb61c6c91c3397a3de7fc translated
#[test]
fn allow_idle_restriction() {
assert_eq!(
check_simple("allowIdle", RlvPermissionsService::can_allow_idle),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AlwaysRunRestrictionTests.cs::AlwaysRunRestrictionTests.CanAlwaysRun::test 9c0a34e0960e3e2a834ccfc1c129a1f5a8f8c6cfd30b322671b4e5c4cd25a24c translated
#[test]
fn always_run_restriction() {
assert_eq!(
check_simple("alwaysRun", RlvPermissionsService::can_always_run),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatNormalTests.cs::ChatNormalTests.CanChatNormal::test 9a23c49327636e769c7ff2688a0649d441f3531406e8f51e152ec7186a312287 translated
#[test]
fn chat_normal_restriction() {
assert_eq!(
check_simple("chatNormal", RlvPermissionsService::can_chat_normal),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatShoutRestrictionTests.cs::ChatShoutRestrictionTests.CanChatShout::test 493e1dd87afaaa7f8183e677df5c32d00f150ffcdd53f9afad8684672837aa28 translated
#[test]
fn chat_shout_restriction() {
assert_eq!(
check_simple("chatShout", RlvPermissionsService::can_chat_shout),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatWhisperRestrictionTests.cs::ChatWhisperRestrictionTests.CanChatWhisper::test 67c5d2cb8b3e9424fbcf08378c2a28368fe07aa83ec028df7cf88b91576d3e9f translated
#[test]
fn chat_whisper_restriction() {
assert_eq!(
check_simple("chatWhisper", RlvPermissionsService::can_chat_whisper),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DefaultWearRestrictionTests.cs::DefaultWearRestrictionTests.CanDefaultWear::test 64eef4c82d1c5a21bc923cfd44616ddc1a5e6403a9a1c5ad6bd2e5ee06e9704c translated
#[test]
fn default_wear_restriction() {
assert_eq!(
check_simple("defaultWear", RlvPermissionsService::can_default_wear),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FlyRestrictionTests.cs::FlyRestrictionTests.CanFly::test 5f60149edccece6b8a6827bbdc6f593ffd863961c13b506f1171aa0cf37fd5b7 translated
#[test]
fn fly_restriction() {
assert_eq!(
check_simple("fly", RlvPermissionsService::can_fly),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/InteractRestrictionTests.cs::InteractRestrictionTests.CanInteract::test 935d319e07b613ba39b06db30cfd18306670f7dc97186db38c0374c3aac6901e translated
#[test]
fn interact_restriction() {
assert_eq!(
check_simple("interact", RlvPermissionsService::can_interact),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/InteractRestrictionTests.cs::InteractRestrictionTests.CanInteract_default::test 53b9d7f7cfd63a10538060624f81b7a6b1754a7462c230671ed909698dd18923 translated
#[test]
fn interact_restriction_blocks_touch_edit_rez_and_sit() {
let h = RlvHarness::new().unwrap();
block_on(h.process("@interact=n")).unwrap();
let permissions = h.service.permissions();
let object = guid("00000000-0000-4000-8000-000000000000");
let user = Some(Some(guid("55555555-5555-4555-8555-555555555555")));
for (location, user, distance) in [
(TouchLocation::AttachedSelf, None, None),
(TouchLocation::AttachedOther, user, None),
(TouchLocation::RezzedInWorld, None, Some(Some(5.0))),
(TouchLocation::Hud, None, None),
] {
assert!(
!permissions
.can_touch(location, object, user, distance)
.unwrap()
);
}
for location in [
ObjectLocation::Attached,
ObjectLocation::RezzedInWorld,
ObjectLocation::Hud,
] {
assert!(!permissions.can_edit(location, Some(Some(object))).unwrap());
}
assert!(!permissions.can_rez().unwrap());
assert!(!permissions.can_sit().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/JumpRestrictionTests.cs::JumpRestrictionTests.CanJump::test 104374c66e6748d101b69ed5343d9972f29e937305cb17f90244ffa74fc7ed35 translated
#[test]
fn jump_restriction() {
assert_eq!(
check_simple("jump", RlvPermissionsService::can_jump),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RezRestrictionTests.cs::RezRestrictionTests.CanRez::test 5cae348cc241a884803692031c0af4f33fb3a2ce8331129a9866c5364599eccb translated
#[test]
fn rez_restriction() {
assert_eq!(
check_simple("rez", RlvPermissionsService::can_rez),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChatRestrictionTests.cs::SendChatRestrictionTests.CanSendChat::test 36cfbe5123b4b37ee43f0b4ba6453ebbe2754960825b1a8481e77e4f3a0e8015 translated
#[test]
fn send_chat_restriction() {
assert_eq!(
check_simple("sendChat", RlvPermissionsService::can_send_chat),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChatRestrictionTests.cs::SendChatRestrictionTests.CanChat_SendChatRestriction::test 793a31da070038e90c41e4bdb1161daaf51376617a7444867f19c7125ad34313 translated
#[test]
fn send_chat_restriction_preserves_slash_messages_and_private_channels() {
let h = RlvHarness::new().unwrap();
block_on(h.process("@sendchat=n")).unwrap();
let permissions = h.service.permissions();
assert!(!permissions.can_chat(0, "Hello".into()).unwrap());
assert!(permissions.can_chat(0, "/me says Hello".into()).unwrap());
assert!(permissions.can_chat(0, "/ something?".into()).unwrap());
assert!(
!permissions
.can_chat(0, "/me says Hello ^_^".into())
.unwrap()
);
assert!(permissions.can_chat(5, "Hello".into()).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendGestureRestrictionTests.cs::SendGestureRestrictionTests.CanSendGesture::test 91367110c04e3c6ad173f56f209a166d828560850d3d084893e899bcc756428a translated
#[test]
fn send_gesture_restriction() {
assert_eq!(
check_simple("sendGesture", RlvPermissionsService::can_send_gesture),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetDebugRestrictionTests.cs::SetDebugRestrictionTests.CanSetDebug::test d4fb9da4879ef8d1be115e00b7a8de959fd58e32722bc9e2985bca8e97dd2ce3 translated
#[test]
fn set_debug_restriction() {
assert_eq!(
check_simple("setDebug", RlvPermissionsService::can_set_debug),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetEnvRestrictionTests.cs::SetEnvRestrictionTests.CanSetEnv::test bb4c82afd643d267264467282cdfe09095c804079e73dd15179e1aa0b063c08f translated
#[test]
fn set_env_restriction() {
assert_eq!(
check_simple("setEnv", RlvPermissionsService::can_set_env),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetGroupRestrictionTests.cs::SetGroupRestrictionTests.CanSetGroup::test 9d89210cbc5c188985a535ae045e44d296c796f700d4a1e2b7b4d75345cc4a6d translated
#[test]
fn set_group_restriction() {
assert_eq!(
check_simple("setGroup", RlvPermissionsService::can_set_group),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowInvRestrictionTests.cs::ShowInvRestrictionTests.CanShowInv::test b7c8bb7ad9d2c02c1c0168531c8ac0636885817a40b13bc006f4f5b20d28591c translated
#[test]
fn show_inventory_restriction() {
assert_eq!(
check_simple("showInv", RlvPermissionsService::can_show_inv),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowLocRestrictionTests.cs::ShowLocRestrictionTests.CanShowLoc::test a8b154f2db967ab72781f31dcd7701d204f66ece1ef95a30cc67d788c78da617 translated
#[test]
fn show_location_restriction() {
assert_eq!(
check_simple("showLoc", RlvPermissionsService::can_show_loc),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowMiniMapRestrictionTests.cs::ShowMiniMapRestrictionTests.CanShowMiniMap::test da901135b533aee1b025cf5dd925e857b4734ea00770ced4518f501453ea9736 translated
#[test]
fn show_mini_map_restriction() {
assert_eq!(
check_simple("showMiniMap", RlvPermissionsService::can_show_mini_map),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNearbyRestrictionTests.cs::ShowNearbyRestrictionTests.CanShowNearby::test 4faa79795b1143934efbd8ebea7a926b270dd5d1e69f8a64f496063d570d868d translated
#[test]
fn show_nearby_restriction() {
assert_eq!(
check_simple("showNearby", RlvPermissionsService::can_show_nearby),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowWorldMapRestrictionTests.cs::ShowWorldMapRestrictionTests.CanShowWorldMap::test da16f247df929f83ed21377869790c00cb5922fa6086da3787e90570f5684f67 translated
#[test]
fn show_world_map_restriction() {
assert_eq!(
check_simple("showWorldMap", RlvPermissionsService::can_show_world_map),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitRestrictionTests.cs::SitRestrictionTests.CanSit::test 813906dbfd09bb02c129a794f40a2f5dcda6e73d232e167359a6360a350fa4b4 translated
#[test]
fn sit_restriction() {
assert_eq!(
check_simple("sit", RlvPermissionsService::can_sit),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/StandTpRestrictionTests.cs::StandTpRestrictionTests.CanStandTp::test 0f694e59d32c3c97fbee072d591b74c89561f4648bd3440002d8f54db0058a94 translated
#[test]
fn stand_tp_restriction() {
assert_eq!(
check_simple("standTp", RlvPermissionsService::can_stand_tp),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TempRunRestrictionTests.cs::TempRunRestrictionTests.CanTempRun::test 8893bb24bf10de7e914874c347ac5b73982d33925a1cf29ae8c361c3087be408 translated
#[test]
fn temp_run_restriction() {
assert_eq!(
check_simple("tempRun", RlvPermissionsService::can_temp_run),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLmRestrictionTests.cs::TpLmRestrictionTests.CanTpLm::test 847bd3264fd831837d8dab25b235450f19591fef3b3bd0315021727453ad64ee translated
#[test]
fn tp_landmark_restriction() {
assert_eq!(
check_simple("tpLm", RlvPermissionsService::can_tp_lm),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocRestrictionTests.cs::TpLocRestrictionTests.CanTpLoc::test 8e5e2ab1b55b710ecce509b141ccac9bcd9ebbad479868496645ac89574bd089 translated
#[test]
fn tp_location_restriction() {
assert_eq!(
check_simple("tpLoc", RlvPermissionsService::can_tp_loc),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/UnsitRestrictionTests.cs::UnsitRestrictionTests.CanUnsit::test 2341a0d230eace08d612a1ae3f9aac7b5a1d3d914f04b6ada4726523e9bd3a37 translated
#[test]
fn unsit_restriction() {
assert_eq!(
check_simple("unsit", RlvPermissionsService::can_unsit),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewNoteRestrictionTests.cs::ViewNoteRestrictionTests.CanViewNote::test 954472ccc5e060f987260c7d8f87f09dcb252e832c22810ed48dd316a173cf5e translated
#[test]
fn view_note_restriction() {
assert_eq!(
check_simple("viewNote", RlvPermissionsService::can_view_note),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewScriptRestrictionTests.cs::ViewScriptRestrictionTests.CanViewScript::test 5e9246991c14d80bc83aad4b5944bd9701dc32b354a701a378def8924f7b5315 translated
#[test]
fn view_script_restriction() {
assert_eq!(
check_simple("viewScript", RlvPermissionsService::can_view_script),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewTextureRestrictionTests.cs::ViewTextureRestrictionTests.CanViewTexture::test d1ee89e12ea9c2d971b4d11c82f3129412fd56fa28d2bd2fb923f082eda62571 translated
#[test]
fn view_texture_restriction() {
assert_eq!(
check_simple("viewTexture", RlvPermissionsService::can_view_texture),
[false, true]
);
}

View File

@@ -0,0 +1,605 @@
// Exact Rust translations of the message, sharing, and name restriction tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::RlvPermissionsServiceHoverTextLocation as HoverTextLocation;
const USER_1: &str = "00000000-0000-4000-8000-000000000000";
const USER_2: &str = "11111111-1111-4111-8111-111111111111";
const SENDER_2: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const SENDER_3: &str = "22222222-2222-4222-8222-222222222222";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process(h: &RlvHarness, commands: &[&str]) {
for command in commands {
block_on(h.process(command)).unwrap();
}
}
fn receive_im(h: &RlvHarness, user: &str, group: Option<&str>) -> bool {
h.service
.permissions()
.can_receive_im(
"Hello world".into(),
Some(Some(guid(user))),
group.map(Into::into),
)
.unwrap()
}
fn send_im(h: &RlvHarness, user: &str, group: Option<&str>) -> bool {
h.service
.permissions()
.can_send_im(
"Hello world".into(),
Some(Some(guid(user))),
group.map(Into::into),
)
.unwrap()
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatExceptionTests.cs::RecvChatExceptionTests.CanRecvChat::test 017906038e211352d7d2751fafbcab5028cd8b189e7aa29a6202ff578976a23c translated
#[test]
fn receive_chat_blocks_chat_but_not_emote() {
let h = harness();
process(&h, &["@recvchat=n"]);
let permissions = h.service.permissions();
assert!(
!permissions
.can_receive_chat("Hello world".into(), guid(SENDER_2))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(SENDER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatFromRestrictionTests.cs::RecvChatFromRestrictionTests.CanRecvChatFrom::test aaf24dc0b8533a7e93cc567fecbb866067b72da1837207869f879647840bfa21 translated
#[test]
fn receive_chat_from_one_user() {
let h = harness();
process(&h, &[&format!("@recvchatfrom:{USER_1}=add")]);
let permissions = h.service.permissions();
assert!(
!permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatSecExceptionTests.cs::RecvChatSecExceptionTests.CanRecvChat_Secure::test cba089ebe607088e37be285918a1d2c674f1acc4cad075733108afea3ad0279b translated
#[test]
fn secure_receive_chat_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@recvchat_sec=n"]);
block_on(h.process_from(&format!("@recvchat:{USER_1}=add"), SENDER_2, "Sender 2")).unwrap();
process(&h, &[&format!("@recvchat:{USER_2}=add")]);
let permissions = h.service.permissions();
assert!(
!permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteFromRestrictionTests.cs::RecvEmoteFromRestrictionTests.CanRecvChat_RecvEmoteFrom::test d07ded724315cf135603d4dc5a684e5a59a5cf8415963acc30d402ad81916ac1 translated
#[test]
fn receive_emote_from_one_user() {
let h = harness();
process(&h, &[&format!("@recvemotefrom:{USER_1}=n")]);
let permissions = h.service.permissions();
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
assert!(
!permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteRestrictionTests.cs::RecvEmoteRestrictionTests.CanRecvChat_RecvEmote::test 438b72e6c44570580bf41aa7b8ed00afb800eff8836ee971eab9fc6a00fecc19 translated
#[test]
fn receive_emote_restriction() {
let h = harness();
process(&h, &["@recvemote=n"]);
let permissions = h.service.permissions();
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(SENDER_2))
.unwrap()
);
assert!(
!permissions
.can_receive_chat("/me says Hello world".into(), guid(SENDER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteSecRestrictionTests.cs::RecvEmoteSecRestrictionTests.CanRecvChat_RecvEmote_Secure::test 9e1f72426762569b1c650fdf80c53e4a590b6476f8539fff6e110101e48459e8 translated
#[test]
fn secure_receive_emote_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@recvemote_sec=n"]);
block_on(h.process_from(&format!("@recvemote:{USER_1}=add"), SENDER_2, "Sender 2")).unwrap();
process(&h, &[&format!("@recvemote:{USER_2}=add")]);
let permissions = h.service.permissions();
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
assert!(
!permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMFrom::test ebe072c7e1c8ba440b560c2e4a0aa5151ba546f5b6cd5505012958e901c58201 translated
#[test]
fn receive_im_from_one_user() {
let h = harness();
process(&h, &[&format!("@recvimfrom:{USER_1}=n")]);
assert!(!receive_im(&h, USER_1, None));
assert!(receive_im(&h, USER_2, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMFrom_Group::test d3d155240723ca2d379f00111a3b27acb41786615a2f5b0ad2c968040d7f4447 translated
#[test]
fn receive_im_from_one_group() {
let h = harness();
process(&h, &["@recvimfrom:First Group=n"]);
assert!(!receive_im(&h, USER_1, Some("First Group")));
assert!(receive_im(&h, USER_2, Some("Second Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMTo_AllGroups::test dd1050e7ef3e9805b88964822485856d6b2e5e98ee647ee08251cbc5bd452208 translated
#[test]
fn receive_im_from_all_groups() {
let h = harness();
process(&h, &["@recvimfrom:allgroups=n"]);
assert!(!receive_im(&h, USER_1, Some("First Group")));
assert!(!receive_im(&h, USER_2, Some("Second Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImRestrictionTests.cs::RecvImRestrictionTests.CanReceiveIM::test 9c88e79ed2686e571e32ccecbc93c130423b966ff4e65e72f228f1713e5047cd translated
#[test]
fn receive_im_restriction() {
let h = harness();
process(&h, &["@recvim=n"]);
assert!(
!h.service
.permissions()
.can_receive_im("Hello".into(), Some(Some(guid(USER_1))), None)
.unwrap()
);
assert!(
!h.service
.permissions()
.can_receive_im(
"Hello".into(),
Some(Some(guid(USER_1))),
Some("Group Name".into())
)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure::test e549fe9719efd180f8ab8c80b989701cd23ebf07cd004d9a5a18a0cc7db12e64 translated
#[test]
fn secure_receive_im_user_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@recvim_sec=n", &format!("@recvim:{USER_1}=add")]);
block_on(h.process_from(&format!("@recvim:{USER_2}=add"), SENDER_2, "Sender 2")).unwrap();
assert!(receive_im(&h, USER_1, None));
assert!(!receive_im(&h, USER_2, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure_Group::test 13653ee7443d2eca88f2940d0c3804de3685dcf6c9277a4717a42dad4c01fca4 translated
#[test]
fn secure_receive_im_group_exception() {
let h = harness();
process(&h, &["@recvim_sec=n", "@recvim:Group Name=add"]);
block_on(h.process_from("@recvim:allgroups=add", SENDER_2, "Sender 2")).unwrap();
assert!(receive_im(&h, USER_1, Some("Group Name")));
assert!(!receive_im(&h, USER_1, Some("Another Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure_AllGroups::test d99435b52a3b774ab5d2bb6911824fa45803fe82cfe0b2c192a05473b72463c8 translated
#[test]
fn secure_receive_im_all_groups_exception() {
let h = harness();
process(&h, &["@recvim_sec=n", "@recvim:allgroups=add"]);
assert!(receive_im(&h, USER_1, Some("Group Name")));
assert!(receive_im(&h, USER_1, Some("Another Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelRestrictionTests.cs::SendChannelRestrictionTests.CanSendChannel::test 8496734391f57cf2f2d8156f3b5a9ad9147c959e3bf99f9e76a4072e971a5b42 translated
#[test]
fn send_channel_restriction() {
let h = harness();
process(&h, &["@sendchannel=n"]);
assert!(
!h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelSecRestrictionTests.cs::SendChannelSecRestrictionTests.CanSendChannel_Secure::test 5bd9096e9af488d5cdb08ed78120ef46f81f9be1eaf132c49a955eb07ae904eb translated
#[test]
fn secure_send_channel_restrictions_are_sender_scoped() {
let h = harness();
process(&h, &["@sendchannel_sec=n", "@sendchannel:123=n"]);
block_on(h.process_from("@sendchannel:456=n", SENDER_2, "Sender 2")).unwrap();
assert!(
h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
assert!(
!h.service
.permissions()
.can_chat(456, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelSecRestrictionTests.cs::SendChannelSecRestrictionTests.CanSendChannel_Secure_Exception::test e675121ba9f6ab8f6e4484e66d76d0dd14f8ef39122c8fff2878ba5e6b3a7409 translated
#[test]
fn secure_send_channel_exception() {
let h = harness();
process(&h, &["@sendchannel_sec=n", "@sendchannel_sec:123=n"]);
assert!(
h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
assert!(
!h.service
.permissions()
.can_chat(456, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImRestrictionTests.cs::SendImRestrictionTests.CanSendIM::test c63ab3a41b6b302e7c84c54374c7193335840bafc40f2d0f2b1c3a2787b26203 translated
#[test]
fn send_im_restriction() {
let h = harness();
process(&h, &["@sendim=n"]);
assert!(
!h.service
.permissions()
.can_send_im("Hello".into(), Some(Some(guid(USER_1))), None)
.unwrap()
);
assert!(
!h.service
.permissions()
.can_send_im(
"Hello".into(),
Some(Some(guid(USER_1))),
Some("Group Name".into())
)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure::test 65422234501bcbf151f27e0d45c74726e670665f39d90df23396f79450ba2b91 translated
#[test]
fn secure_send_im_user_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@sendim_sec=n", &format!("@sendim:{USER_1}=add")]);
block_on(h.process_from(&format!("@sendim:{USER_2}=add"), SENDER_2, "Sender 2")).unwrap();
assert!(send_im(&h, USER_1, None));
assert!(!send_im(&h, USER_2, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure_Group::test 4ed2e6416a86eb2406e20bbb7e60a380de25577ad034ba613530ed28f6001df9 translated
#[test]
fn secure_send_im_group_exception() {
let h = harness();
process(&h, &["@sendim_sec=n", "@sendim:Group Name=add"]);
block_on(h.process_from("@sendim:allgroups=add", SENDER_2, "Sender 2")).unwrap();
assert!(send_im(&h, USER_1, Some("Group Name")));
assert!(!send_im(&h, USER_1, Some("Another Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure_AllGroups::test a4b699c9ada01ca4ce4d535739178e5310affa938d02dfaede6d034488d24f5f translated
#[test]
fn secure_send_im_all_groups_exception() {
let h = harness();
process(&h, &["@sendim_sec=n", "@sendim:allgroups=add"]);
assert!(send_im(&h, USER_1, Some("Group Name")));
assert!(send_im(&h, USER_1, Some("Another Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo::test 38258cda1081160b6b34f8e909adbc683a0f08efce8c63066bcac09835e5cdcc translated
#[test]
fn send_im_to_one_user() {
let h = harness();
process(&h, &[&format!("@sendimto:{USER_1}=n")]);
assert!(!send_im(&h, USER_1, None));
assert!(send_im(&h, USER_2, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo_Group::test 1e12f7e3dbbee7d8dfb757fc8797644a353dfaa995e343e59124aa85126d70aa translated
#[test]
fn send_im_to_one_group() {
let h = harness();
process(&h, &["@sendimto:First Group=n"]);
assert!(!send_im(&h, USER_1, Some("First Group")));
assert!(send_im(&h, USER_2, Some("Second Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo_AllGroups::test bc9b87ab7b171c76987ddaf94f05c0ac2ad8dc0c1f24f5dfce2f4125e7b28df5 translated
#[test]
fn send_im_to_all_groups() {
let h = harness();
process(&h, &["@sendimto:allgroups=n"]);
assert!(!send_im(&h, USER_1, Some("First Group")));
assert!(!send_im(&h, USER_2, Some("Second Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareRestrictionTests.cs::ShareRestrictionTests.CanShare::test 23052e5792ff72624d45b54ccfd02fa5d8025d977010f1e8d34a90d27a4d0e29 translated
#[test]
fn share_restriction() {
let h = harness();
process(&h, &["@share=n"]);
assert!(!h.service.permissions().can_share(None).unwrap());
assert!(
!h.service
.permissions()
.can_share(Some(Some(guid(SENDER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareSecRestrictionTests.cs::ShareSecRestrictionTests.CanShare_Secure_Default::test 6d61bafb190791ceaccb6c46cde3adf5b5479e6b5e76bafeadd0942400389248 translated
#[test]
fn secure_share_default() {
let h = harness();
process(&h, &["@share_sec=n"]);
assert!(!h.service.permissions().can_share(None).unwrap());
assert!(
!h.service
.permissions()
.can_share(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_share(Some(Some(guid(USER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareSecRestrictionTests.cs::ShareSecRestrictionTests.CanShare_Secure::test e1aed5b3b8efccef47094788c3221e20240c671c1004d6d6bd899e5d9ddd51fa translated
#[test]
fn secure_share_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@share_sec=n", &format!("@share:{USER_1}=add")]);
block_on(h.process_from(&format!("@share:{USER_2}=add"), SENDER_2, "Sender 2")).unwrap();
assert!(!h.service.permissions().can_share(None).unwrap());
assert!(
h.service
.permissions()
.can_share(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_share(Some(Some(guid(USER_2))))
.unwrap()
);
}
fn hover(h: &RlvHarness, location: HoverTextLocation, object: &str) -> bool {
h.service
.permissions()
.can_show_hover_text(location, Some(Some(guid(object))))
.unwrap()
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextAllRestrictionTests.cs::ShowHoverTextAllRestrictionTests.CanShowHoverTextAll::test 6a855738e87477d31dc7867d0c75ba1bf563e2b1e180f54759657a58b7da9793 translated
#[test]
fn show_hover_text_all_restriction() {
let h = harness();
process(&h, &["@showhovertextall=n"]);
assert!(!hover(&h, HoverTextLocation::World, USER_1));
assert!(!hover(&h, HoverTextLocation::Hud, USER_1));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextHudRestrictionTests.cs::ShowHoverTextHudRestrictionTests.CanShowHoverTextHud::test 9d08e2a3eb303b14c4b222cae5d52537e81a7d9cfc9fcfe9625d513b6311a6ed translated
#[test]
fn show_hover_text_hud_restriction() {
let h = harness();
process(&h, &["@showhovertexthud=n"]);
for object in [USER_1, USER_2] {
assert!(hover(&h, HoverTextLocation::World, object));
assert!(!hover(&h, HoverTextLocation::Hud, object));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextRestrictionTests.cs::ShowHoverTextRestrictionTests.CanShowHoverText::test 5642102d6832b227c37c14d0fbfc30921022c5789b811021805db6f3a2120f36 translated
#[test]
fn show_hover_text_one_object_restriction() {
let h = harness();
process(&h, &[&format!("@showhovertext:{USER_1}=n")]);
assert!(!hover(&h, HoverTextLocation::World, USER_1));
assert!(!hover(&h, HoverTextLocation::Hud, USER_1));
assert!(hover(&h, HoverTextLocation::World, USER_2));
assert!(hover(&h, HoverTextLocation::Hud, USER_2));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextWorldRestrictionTests.cs::ShowHoverTextWorldRestrictionTests.CanShowHoverTextWorld::test 1be82408fbc87f1525dc7652e01fbbc17a993b70a2268f0b742d035b37cbf70c translated
#[test]
fn show_hover_text_world_restriction() {
let h = harness();
process(&h, &["@showhovertextworld=n"]);
for object in [USER_1, USER_2] {
assert!(!hover(&h, HoverTextLocation::World, object));
assert!(hover(&h, HoverTextLocation::Hud, object));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNameTagsRestrictionTests.cs::ShowNameTagsRestrictionTests.CanShowNameTags::test 74e8a6aefdefb9eb41509f6b4438e6854e5ad0ace38ab663f445aae484e94e22 translated
#[test]
fn show_name_tags_restriction() {
let h = harness();
process(&h, &["@shownametags=n"]);
assert!(!h.service.permissions().can_show_name_tags(None).unwrap());
assert!(
!h.service
.permissions()
.can_show_name_tags(Some(Some(guid(SENDER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesRestrictionTests.cs::ShowNamesRestrictionTests.CanShowNames::test c44fe98d881a89af5db856e98f7bd7480d9bfb4378730002e518a7d1da412812 translated
#[test]
fn show_names_restriction() {
let h = harness();
process(&h, &["@shownames=n"]);
assert!(!h.service.permissions().can_show_names(None).unwrap());
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(SENDER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure_Default::test 98d2c84d2f226fbb4b03c365f3ab007142d87b1980dda3666ce5ec36909fc599 translated
#[test]
fn secure_show_names_default() {
let h = harness();
process(&h, &["@shownames_sec=n"]);
assert!(!h.service.permissions().can_show_names(None).unwrap());
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(USER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure::test 90ae29916dc2b60cd3de336e4a37683de8967f448fef26af360e3d24278773d3 translated
#[test]
fn secure_show_names_exceptions_are_sender_scoped() {
let h = harness();
process(
&h,
&["@shownames_sec=n", &format!("@shownames:{USER_1}=add")],
);
block_on(h.process_from(&format!("@shownames:{USER_2}=add"), SENDER_3, "Sender 2")).unwrap();
assert!(!h.service.permissions().can_show_names(None).unwrap());
assert!(
h.service
.permissions()
.can_show_names(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(USER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure_Except::test 457772321f7fd1ea88a279e99a4b0a955e462652bac1fb7953b8455f3d67a155 translated
#[test]
fn secure_show_names_direct_exception() {
let h = harness();
process(
&h,
&["@shownames_sec=n", &format!("@shownames_sec:{USER_1}=n")],
);
assert!(!h.service.permissions().can_show_names(None).unwrap());
assert!(
h.service
.permissions()
.can_show_names(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(USER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/StartImRestrictionTests.cs::StartImRestrictionTests.CanStartIM::test cc8318d5233b947ca96939369de3a2fdc2c21468cc13a87c87908126c6e45500 translated
#[test]
fn start_im_restriction() {
let h = harness();
process(&h, &["@startim=n"]);
assert!(!h.service.permissions().can_start_im(guid(USER_1)).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/StartImToRestrictionTests.cs::StartImToRestrictionTests.CanStartIMTo::test 0c7e19de2ecf94a6db09ee409ff88ff503e02d8dd8f7f11f427cebc51a3ac09f translated
#[test]
fn start_im_to_one_user() {
let h = harness();
process(&h, &[&format!("@startimto:{USER_2}=n")]);
assert!(h.service.permissions().can_start_im(guid(USER_1)).unwrap());
assert!(!h.service.permissions().can_start_im(guid(USER_2)).unwrap());
}

View File

@@ -0,0 +1,441 @@
// Exact Rust translations of far-touch, touch, sit-teleport, and teleport restrictions.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::RlvPermissionsServiceTouchLocation as TouchLocation;
const OBJECT_1: &str = "00000000-0000-4000-8000-000000000000";
const OBJECT_2: &str = "11111111-1111-4111-8111-111111111111";
const USER_1: &str = "55555555-5555-4555-8555-555555555555";
const USER_2: &str = "66666666-6666-4666-8666-666666666666";
const SENDER_2: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const SENDER_3: &str = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process(h: &RlvHarness, commands: &[&str]) {
for command in commands {
block_on(h.process(command)).unwrap();
}
}
fn far_touch(command: &str) -> (bool, f32) {
let h = harness();
process(&h, &[command]);
let mut distance = 0.0;
let found = h
.service
.permissions()
.try_get_max_far_touch_distance(&mut distance);
(found, distance)
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch::case:ccd63fc5b9c064fb a5568e0040a3c0ac8875a11596b7d0799ac5169b919e4fc65587555b2d3edd52 translated
#[test]
fn far_touch_fartouch_value() {
assert_eq!(far_touch("@fartouch:0.9=n"), (true, 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch::case:ae3d093c6c7267ac a5568e0040a3c0ac8875a11596b7d0799ac5169b919e4fc65587555b2d3edd52 translated
#[test]
fn far_touch_touchfar_value() {
assert_eq!(far_touch("@touchfar:0.9=n"), (true, 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Synonym::case:ccd63fc5b9c064fb c7aff866d539ceb26cc028532a901f18b58bb020f34da56444f08c9f4df1eb52 translated
#[test]
fn far_touch_fartouch_synonym() {
assert_eq!(far_touch("@fartouch:0.9=n"), (true, 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Synonym::case:ae3d093c6c7267ac c7aff866d539ceb26cc028532a901f18b58bb020f34da56444f08c9f4df1eb52 translated
#[test]
fn far_touch_touchfar_synonym() {
assert_eq!(far_touch("@touchfar:0.9=n"), (true, 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Default::case:ccd63fc5b9c064fb e894c744ea780a0a46cd2387157077c1a62c3c6b982303f3b7bff0b5d950816a translated
#[test]
fn far_touch_fartouch_default() {
assert_eq!(far_touch("@fartouch=n"), (true, 1.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Default::case:ae3d093c6c7267ac e894c744ea780a0a46cd2387157077c1a62c3c6b982303f3b7bff0b5d950816a translated
#[test]
fn far_touch_touchfar_default() {
assert_eq!(far_touch("@touchfar=n"), (true, 1.5));
}
fn far_touch_multiple_matches(first: &str, second: &str) -> bool {
let h = harness();
process(
&h,
&[&format!("@{first}:12.34=n"), &format!("@{second}:6.78=n")],
);
let mut before_removal = 0.0;
let found_before = h
.service
.permissions()
.try_get_max_far_touch_distance(&mut before_removal);
process(&h, &[&format!("@{first}:6.78=y")]);
let mut after_removal = 0.0;
let found_after = h
.service
.permissions()
.try_get_max_far_touch_distance(&mut after_removal);
found_before
&& found_after
&& (after_removal - 12.34).abs() < 0.0001
&& (before_removal - 6.78).abs() < 0.0001
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:5788809ef8877342 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905 translated
#[test]
fn far_touch_multiple_fartouch_fartouch() {
assert!(far_touch_multiple_matches("fartouch", "fartouch"));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:b3ebeae1885ed5db 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905 translated
#[test]
fn far_touch_multiple_fartouch_touchfar() {
assert!(far_touch_multiple_matches("fartouch", "touchfar"));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:07cf5c5cabecfebf 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905 translated
#[test]
fn far_touch_multiple_touchfar_touchfar() {
assert!(far_touch_multiple_matches("touchfar", "touchfar"));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:8008f95bc76b47e9 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905 translated
#[test]
fn far_touch_multiple_touchfar_fartouch() {
assert!(far_touch_multiple_matches("touchfar", "fartouch"));
}
fn sit_tp(h: &RlvHarness) -> (bool, f32) {
let mut distance = 0.0;
let active = h.service.permissions().can_sit_tp(&mut distance).unwrap();
(active, distance)
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Default::test ddcdba94af060ede43f0d585688966ccd923238a2365164b32a301b04d83cdfc translated
#[test]
fn sit_tp_default() {
assert_eq!(sit_tp(&harness()), (false, 1.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Single::test 041c57829ab1032eed79e6f47c8b9026124b681fb6ffa4b3c5ac16b16d0b354b translated
#[test]
fn sit_tp_single() {
let h = harness();
process(&h, &["@SitTp:2.5=n"]);
assert_eq!(sit_tp(&h), (true, 2.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_SingleSender::test feed9f3cca3395e1eb5a8d831304a4171e79f6e1d93f03a4aca0e27edba5ed6d translated
#[test]
fn sit_tp_multiple_single_sender() {
let h = harness();
process(&h, &["@SitTp:3.5=n", "@SitTp:4.5=n", "@SitTp:2.5=n"]);
assert_eq!(sit_tp(&h), (true, 2.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_SingleSender_WithRemoval::test 4b26c525e0a13fbc79b280f0a6c3b0f9e3e0e664241e9f55a88eda3dd80b203a translated
#[test]
fn sit_tp_multiple_single_sender_with_removal() {
let h = harness();
process(
&h,
&[
"@SitTp:3.5=n",
"@SitTp:4.5=n",
"@SitTp:2.5=n",
"@SitTp:8.5=n",
"@SitTp:8.5=y",
],
);
assert_eq!(sit_tp(&h), (true, 2.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_MultipleSenders::test cd9e3508d44e2e008609ac0cc12d3e207ec454a3f5c6e36aa325d33be9b6718f translated
#[test]
fn sit_tp_multiple_senders() {
let h = harness();
process(&h, &["@SitTp:3.5=n"]);
block_on(h.process_from("@SitTp:4.5=n", SENDER_2, "Sender 2")).unwrap();
block_on(h.process_from("@SitTp:2.5=n", SENDER_3, "Sender 3")).unwrap();
assert_eq!(sit_tp(&h), (true, 2.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Off::test e871d15d797e0f8f0b02613c2a421b47b87068c8757bbd0104cd15d406137854 translated
#[test]
fn sit_tp_off() {
let h = harness();
process(&h, &["@SitTp:2.5=n", "@SitTp:2.5=y"]);
assert_eq!(sit_tp(&h), (false, 1.5));
}
fn touch(
h: &RlvHarness,
location: TouchLocation,
object: &str,
user: Option<&str>,
distance: Option<f32>,
) -> bool {
h.service
.permissions()
.can_touch(
location,
guid(object),
user.map(|value| Some(guid(value))),
distance.map(Some),
)
.unwrap()
}
fn touch_matrix(h: &RlvHarness) -> [bool; 4] {
[
touch(h, TouchLocation::AttachedSelf, OBJECT_1, None, None),
touch(
h,
TouchLocation::AttachedOther,
OBJECT_1,
Some(USER_1),
None,
),
touch(h, TouchLocation::RezzedInWorld, OBJECT_1, None, Some(5.0)),
touch(h, TouchLocation::Hud, OBJECT_1, None, None),
]
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAllRestrictionTests.cs::TouchAllRestrictionTests.TouchAll::test 06da3251125bf4d3b2d542cfba7fa0a7b0c18dc0f97024a57c0e0ddf6cfc8dd6 translated
#[test]
fn touch_all_default_permissions() {
assert_eq!(touch_matrix(&harness()), [true, true, true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAllRestrictionTests.cs::TouchAllRestrictionTests.TouchAll_default::test 9526d7bed6473afd41f97fb11ec950caae157865cec8eee719030ca109ab2681 translated
#[test]
fn touch_all_restricted() {
let h = harness();
process(&h, &["@touchall=n"]);
assert_eq!(touch_matrix(&h), [false, false, false, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachOtherRestrictionTests.cs::TouchAttachOtherRestrictionTests.TouchAttachOther_default::test 1f8157f5fd5db8b5a4596d5be6a5d780704cac85370204c77eca08da286adb86 translated
#[test]
fn touch_attach_other_default() {
let h = harness();
process(&h, &["@touchattachother=n"]);
assert_eq!(touch_matrix(&h), [true, false, true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachOtherRestrictionTests.cs::TouchAttachOtherRestrictionTests.TouchAttachOther_Specific::test add9d393d4aaf03768239611a8a64b2ef73fc4c8561dbbc51950a10c006198e6 translated
#[test]
fn touch_attach_other_specific_user() {
let h = harness();
process(&h, &[&format!("@touchattachother:{USER_2}=n")]);
assert!(touch(&h, TouchLocation::AttachedSelf, OBJECT_1, None, None));
assert!(touch(
&h,
TouchLocation::AttachedOther,
OBJECT_1,
Some(USER_1),
None
));
assert!(!touch(
&h,
TouchLocation::AttachedOther,
OBJECT_1,
Some(USER_2),
None
));
assert!(touch(
&h,
TouchLocation::RezzedInWorld,
OBJECT_1,
None,
Some(5.0)
));
assert!(touch(&h, TouchLocation::Hud, OBJECT_1, None, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachRestrictionTests.cs::TouchAttachRestrictionTests.TouchAttach_default::test 4c4c65f8ed4b29367c353a02e52c91e9402788ffd35c75e5a6a40a827710e20a translated
#[test]
fn touch_attach_default() {
let h = harness();
process(&h, &["@touchattach=n"]);
assert_eq!(touch_matrix(&h), [false, false, true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachSelfRestrictionTests.cs::TouchAttachSelfRestrictionTests.TouchAttachSelf_default::test 09f7d7a45a9899746c1c63608f95db89ef2ae4a875437a2b594bb120da8139ff translated
#[test]
fn touch_attach_self_default() {
let h = harness();
process(&h, &["@touchattachself=n"]);
assert_eq!(touch_matrix(&h), [false, true, true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchHudRestrictionTests.cs::TouchHudRestrictionTests.TouchHud_default::test b15afadb1f45b51eb47651a9d890ed2a6b1de8066d986d9b1ccc33da734c0194 translated
#[test]
fn touch_hud_default() {
let h = harness();
process(&h, &["@touchhud=n"]);
assert_eq!(touch_matrix(&h), [true, true, true, false]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchHudRestrictionTests.cs::TouchHudRestrictionTests.TouchHud_specific::test 4c4e1a9493e5cf34f220ebec54c5373e1b30c81044803deece263dced5f7155d translated
#[test]
fn touch_hud_specific_object() {
let h = harness();
process(&h, &[&format!("@touchhud:{OBJECT_2}=n")]);
assert_eq!(touch_matrix(&h), [true, true, true, true]);
assert!(!touch(&h, TouchLocation::Hud, OBJECT_2, None, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchWorldRestrictionTests.cs::TouchWorldRestrictionTests.TouchWorld_default::test 5995288721c44beaa329b266e15d619f2314c9ca74386145294183c7c509b42a translated
#[test]
fn touch_world_default() {
let h = harness();
process(&h, &["@touchworld=n"]);
assert_eq!(touch_matrix(&h), [true, true, false, true]);
}
fn tp_local_matches(command: &str, expected_distance: f32) -> bool {
let h = harness();
process(&h, &[command]);
let mut distance = -1.0;
h.service.permissions().can_tp_local(&mut distance).unwrap()
&& (distance - expected_distance).abs() < 0.0001
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocalRestrictionTests.cs::TpLocalRestrictionTests.CanTpLocal_Default::test 4b251429c6561c1d29f19f8fbc33dd0fb11344fe0d10962e789823ffedb3777b translated
#[test]
fn tp_local_default_distance() {
assert!(tp_local_matches("@TpLocal=n", 0.0));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocalRestrictionTests.cs::TpLocalRestrictionTests.CanTpLocal::test f9dd3daf337533beab1f4c2dce488f44dea5d17880e8f61b33e3c17c1a4c776f translated
#[test]
fn tp_local_explicit_distance() {
assert!(tp_local_matches("@TpLocal:0.9=n", 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureRestrictionTests.cs::TpLureRestrictionTests.CanTpLure_Default::test 595e468736aab4136404842adf36a79f37b9900c3ee3993079621a5a6c96dec1 translated
#[test]
fn tp_lure_default() {
let permissions = harness().service.permissions();
assert!(permissions.can_tp_lure(None).unwrap());
assert!(permissions.can_tp_lure(Some(Some(guid(SENDER_2)))).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureRestrictionTests.cs::TpLureRestrictionTests.CanTpLure::test a57f7803128d75a0f1ba35a1c7489f78ca99d7e5e540f06b84725da8a5cd10da translated
#[test]
fn tp_lure_restricted() {
let h = harness();
process(&h, &["@tplure=n"]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_lure(None).unwrap());
assert!(!permissions.can_tp_lure(Some(Some(guid(SENDER_2)))).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureSecRestrictionTests.cs::TpLureSecRestrictionTests.CanTpLure_Secure_Default::test 577c2c8d22ba1aa8d4426832807ea4ed8cd243836b0d38b0ebc9f32a851c34f4 translated
#[test]
fn secure_tp_lure_default() {
let h = harness();
process(&h, &["@tplure_sec=n"]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_lure(None).unwrap());
assert!(!permissions.can_tp_lure(Some(Some(guid(OBJECT_1)))).unwrap());
assert!(!permissions.can_tp_lure(Some(Some(guid(OBJECT_2)))).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureSecRestrictionTests.cs::TpLureSecRestrictionTests.CanTpLure_Secure::test 38f2894e39bdd7c3c8e1520fa6ed02573be3dfdef0bc5bd1073d9d2240917804 translated
#[test]
fn secure_tp_lure_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@tplure_sec=n", &format!("@tplure:{OBJECT_1}=add")]);
block_on(h.process_from(&format!("@tplure:{OBJECT_2}=add"), SENDER_2, "Sender 2")).unwrap();
let permissions = h.service.permissions();
assert!(!permissions.can_tp_lure(None).unwrap());
assert!(permissions.can_tp_lure(Some(Some(guid(OBJECT_1)))).unwrap());
assert!(!permissions.can_tp_lure(Some(Some(guid(OBJECT_2)))).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestRestrictionTests.cs::TpRequestRestrictionTests.CanTpRequest::test 08ddf0e6dd1faf1f249bc7f7a9545d9e33efb5a438eacc3606b1495a83cf57db translated
#[test]
fn tp_request_restricted() {
let h = harness();
process(&h, &["@tprequest=n"]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_request(None).unwrap());
assert!(
!permissions
.can_tp_request(Some(Some(guid(SENDER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestRestrictionTests.cs::TpRequestRestrictionTests.CanTpRequest_Except::test 89ccb1dd172928c41079555cb6d7ff3fcbd34594dcff0399670cdebc739ac109 translated
#[test]
fn tp_request_exception() {
let h = harness();
process(&h, &["@tprequest=n", &format!("@tprequest:{OBJECT_1}=add")]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_request(None).unwrap());
assert!(
permissions
.can_tp_request(Some(Some(guid(OBJECT_1))))
.unwrap()
);
assert!(
!permissions
.can_tp_request(Some(Some(guid(OBJECT_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestSecRestrictionTests.cs::TpRequestSecRestrictionTests.CanTpRequest_Secure_Default::test 87cb0ffa95d408d55045ade0966979360c28762e05729893b068801ed3b877ed translated
#[test]
fn secure_tp_request_default() {
let h = harness();
process(&h, &["@tprequest_sec=n"]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_request(None).unwrap());
assert!(
!permissions
.can_tp_request(Some(Some(guid(OBJECT_1))))
.unwrap()
);
assert!(
!permissions
.can_tp_request(Some(Some(guid(OBJECT_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestSecRestrictionTests.cs::TpRequestSecRestrictionTests.CanTpRequest_Secure::test 623310f5c9150f6d6527b0db0446e2c33bf873a849a8dc68b78a4173d130da93 translated
#[test]
fn secure_tp_request_exceptions_are_sender_scoped() {
let h = harness();
process(
&h,
&["@tprequest_sec=n", &format!("@tprequest:{OBJECT_1}=add")],
);
block_on(h.process_from(&format!("@tprequest:{OBJECT_2}=add"), SENDER_2, "Sender 2")).unwrap();
let permissions = h.service.permissions();
assert!(!permissions.can_tp_request(None).unwrap());
assert!(
permissions
.can_tp_request(Some(Some(guid(OBJECT_1))))
.unwrap()
);
assert!(
!permissions
.can_tp_request(Some(Some(guid(OBJECT_2))))
.unwrap()
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -576,7 +576,6 @@ def generate_tests(upstream: Path, output: Path, review_root: Path | None = None
"// @generated by tools/generate_surface.py; do not edit by hand.", "// @generated by tools/generate_surface.py; do not edit by hand.",
f"// Source: LibreMetaverse {UPSTREAM_COMMIT}", f"// Source: LibreMetaverse {UPSTREAM_COMMIT}",
"// Pending cases are catalog entries, not fake executable Rust tests.", "// Pending cases are catalog entries, not fake executable Rust tests.",
"",
] ]
for test in tests: for test in tests:
review = reviews.get(str(test["id"])) review = reviews.get(str(test["id"]))
@@ -584,6 +583,8 @@ def generate_tests(upstream: Path, output: Path, review_root: Path | None = None
test.update(review) test.update(review)
test["semantic_review"] = "reviewed" test["semantic_review"] = "reviewed"
continue continue
if len(rust_lines) == 3:
rust_lines.append("")
test.update( test.update(
{ {
"rust_file": "tests/compat/tests/generated_parity.rs", "rust_file": "tests/compat/tests/generated_parity.rs",