Translate Types and Utilities parity tests
Some checks failed
Rust API gates / api-gates (push) Has been cancelled

This commit is contained in:
2026-08-08 13:58:25 +02:00
parent 39ee61525a
commit 1c0dfdc35c
19 changed files with 3482 additions and 3318 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,11 @@
//! Shared deterministic fixtures used by translated compatibility tests.
use std::collections::BTreeMap;
use std::future::Future;
use std::io;
use std::path::{Component, Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll, Wake, Waker};
use std::time::Duration;
/// Fails a not-yet-translated upstream test while retaining parity metadata.
@@ -25,6 +27,27 @@ pub fn pending(
)
}
/// Runs one test future without choosing an async runtime for the library.
pub fn block_on<F: Future>(future: F) -> F::Output {
struct ThreadWake(std::thread::Thread);
impl Wake for ThreadWake {
fn wake(self: Arc<Self>) {
self.0.unpark();
}
}
let waker = Waker::from(Arc::new(ThreadWake(std::thread::current())));
let mut context = Context::from_waker(&waker);
let mut future = std::pin::pin!(future);
loop {
match future.as_mut().poll(&mut context) {
Poll::Ready(output) => return output,
Poll::Pending => std::thread::park(),
}
}
}
/// Asserts equality within the exact absolute tolerance carried by an upstream test.
///
/// # Panics
@@ -250,6 +273,7 @@ mod tests {
#[test]
fn deterministic_harness_covers_clock_network_and_bytes() {
assert_eq!(block_on(std::future::ready(7)), 7);
assert_close(1.001, 1.0, 0.01);
assert_bytes_eq(&decode_hex("00 ff 2A").unwrap(), &[0, 255, 42]);
assert!(decode_hex("é").is_err());

View File

@@ -5,8 +5,11 @@ use libremetaverse::{
ChatEventArgs, ChatType, InventoryException, InventoryItem, InventoryManager,
TeleportEventArgs,
};
use libremetaverse_types::compat::{CancellationToken, EventHandler, Subscription};
use libremetaverse_types::compat::{CancellationToken, Subscription};
use libremetaverse_types::{AssetType, AttachmentPoint, UUID};
use std::sync::Arc;
type EventHandler<T> = Arc<dyn Fn(T) + Send + Sync>;
fn member_id<T>(result: Result<T, libremetaverse::Error>) -> &'static str {
result

View File

@@ -5,7 +5,10 @@ use libremetaverse::{
NetworkManagerDisconnectType, Settings, TexturePipeline, TexturePipelineSettings,
UDPPacketBuffer,
};
use libremetaverse_types::compat::{CancellationToken, EventHandler, IProgress, Subscription, Uri};
use libremetaverse_types::compat::{CancellationToken, IProgress, Subscription, Uri};
use std::sync::Arc;
type EventHandler<T> = Arc<dyn Fn(T) + Send + Sync>;
fn member_id<T>(result: Result<T, libremetaverse::Error>) -> &'static str {
result

View File

@@ -2719,19 +2719,6 @@ fn estate_tools_tests_request_convenant_a027d2de58bc() {
);
}
// parity-case: LibreMetaverse.Tests/EstateToolsTests.cs::EstateToolsTests.EstateInfo::test 68e1b204b4dfb56645bc6ad3a54146b2cc6ad865c298b70a2a55fc6cf148313f pending
#[test]
fn estate_tools_tests_estate_info_3bc323748179() {
pending(
"LibreMetaverse.Tests/EstateToolsTests.cs::EstateToolsTests.EstateInfo::test",
"LibreMetaverse.Tests/EstateToolsTests.cs",
176,
"EstateToolsTests.EstateInfo",
"[Test]",
"68e1b204b4dfb56645bc6ad3a54146b2cc6ad865c298b70a2a55fc6cf148313f",
);
}
// parity-case: LibreMetaverse.Tests/ExperienceListAndRegionMessageTests.cs::ExperienceListAndRegionMessageTests.ExperienceListMessage_Deserialize_ReadsExperienceIdsKey::test aa1f7d09f6c79118ea2e60621d57bd63632085ce81bc979e42294aca53d4f0d9 pending
#[test]
fn experience_list_and_region_message_tests_experience_list_message_6df527312dbb() {
@@ -5462,32 +5449,6 @@ fn network_tests_detect_objects_4781c499b3ef() {
);
}
// parity-case: LibreMetaverse.Tests/NetworkTests.cs::NetworkTests.U64Receive::test 2d740467370db0bf967800a078aed0e810bc1a71eec76d62cb66ba8240601dac pending
#[test]
fn network_tests_u64_receive_8da31179adac() {
pending(
"LibreMetaverse.Tests/NetworkTests.cs::NetworkTests.U64Receive::test",
"LibreMetaverse.Tests/NetworkTests.cs",
139,
"NetworkTests.U64Receive",
"[Test]",
"2d740467370db0bf967800a078aed0e810bc1a71eec76d62cb66ba8240601dac",
);
}
// parity-case: LibreMetaverse.Tests/NetworkTests.cs::NetworkTests.Teleport::test 2ccb0fbc0939177b28b2a3ae95651ac6c30bd5292abacfc5108ba927b0f6bccd pending
#[test]
fn network_tests_teleport_65828f9c5340() {
pending(
"LibreMetaverse.Tests/NetworkTests.cs::NetworkTests.Teleport::test",
"LibreMetaverse.Tests/NetworkTests.cs",
155,
"NetworkTests.Teleport",
"[Test]",
"2ccb0fbc0939177b28b2a3ae95651ac6c30bd5292abacfc5108ba927b0f6bccd",
);
}
// parity-case: LibreMetaverse.Tests/NetworkTests.cs::NetworkTests.CapsQueue::test cd5af4e7d69df3e938540711877d167fe28efb9af8af7518a62b8f406e46cc18 pending
#[test]
fn network_tests_caps_queue_bbde71137aba() {
@@ -5917,32 +5878,6 @@ fn packet_tests_to_bytes_multiple_db2623f4072b() {
);
}
// parity-case: LibreMetaverse.Tests/PositionHelperTests.cs::PositionHelperTests.ToGlobalAndLocalPosition_RoundTrip::test 695c6a640e5353e02def9a1b4a1c1eabb37a8543c13466dff570f58d847e7772 pending
#[test]
fn position_helper_tests_to_global_and_local_position_round_trip_499dfd6841a4() {
pending(
"LibreMetaverse.Tests/PositionHelperTests.cs::PositionHelperTests.ToGlobalAndLocalPosition_RoundTrip::test",
"LibreMetaverse.Tests/PositionHelperTests.cs",
9,
"PositionHelperTests.ToGlobalAndLocalPosition_RoundTrip",
"[Test]",
"695c6a640e5353e02def9a1b4a1c1eabb37a8543c13466dff570f58d847e7772",
);
}
// parity-case: LibreMetaverse.Tests/PositionHelperTests.cs::PositionHelperTests.FormatCoordinates_FormatsCorrectly::test fe4256d00dab5cc2de602b7b27442cac627a5956c4ce79c05d92de830f6fc5d2 pending
#[test]
fn position_helper_tests_format_coordinates_formats_correctly_252219c4f893() {
pending(
"LibreMetaverse.Tests/PositionHelperTests.cs::PositionHelperTests.FormatCoordinates_FormatsCorrectly::test",
"LibreMetaverse.Tests/PositionHelperTests.cs",
29,
"PositionHelperTests.FormatCoordinates_FormatsCorrectly",
"[Test]",
"fe4256d00dab5cc2de602b7b27442cac627a5956c4ce79c05d92de830f6fc5d2",
);
}
// parity-case: LibreMetaverse.Tests/PrimObjectTests.cs::PrimObjectTests.PathBegin::test 5c8e14e1d08a91a4e7c3e252c932b8fe15cf6b5231cc9fe5bb7ef2ae6e2c8299 pending
#[test]
fn prim_object_tests_path_begin_612754fad0a1() {
@@ -5995,19 +5930,6 @@ fn prim_object_tests_path_scale_e37a04cd76fb() {
);
}
// parity-case: LibreMetaverse.Tests/PrimObjectTests.cs::PrimObjectTests.PathShear::test d49147475e55b06e219db0bdad056486c511b9582a6ae2601105a7b3c49844ad pending
#[test]
fn prim_object_tests_path_shear_80b89b3046e8() {
pending(
"LibreMetaverse.Tests/PrimObjectTests.cs::PrimObjectTests.PathShear::test",
"LibreMetaverse.Tests/PrimObjectTests.cs",
88,
"PrimObjectTests.PathShear",
"[Test]",
"d49147475e55b06e219db0bdad056486c511b9582a6ae2601105a7b3c49844ad",
);
}
// parity-case: LibreMetaverse.Tests/PrimObjectTests.cs::PrimObjectTests.PathTaper::test 93a0adbc0630de3c9fbea6f8080d74ef6e3180e3813f00460bce5d52ef2f12b7 pending
#[test]
fn prim_object_tests_path_taper_3c824190973b() {
@@ -14406,19 +14328,6 @@ fn rlv_restriction_manager_tests_remove_restrictions_for_objects_tr_8600b8deef21
);
}
// parity-case: LibreMetaverse.Tests/ReaderWriterLockTests.cs::ReaderWriterLockTests.MultipleReadersOneWriter_ReaderConcurrencyAndWriterExclusion::test bf63804480951667455038244228f77c30454a365b496f062051f7b34e7b2618 pending
#[test]
fn reader_writer_lock_tests_multiple_readers_one_writer_reader_conc_ade8a15ef29f() {
pending(
"LibreMetaverse.Tests/ReaderWriterLockTests.cs::ReaderWriterLockTests.MultipleReadersOneWriter_ReaderConcurrencyAndWriterExclusion::test",
"LibreMetaverse.Tests/ReaderWriterLockTests.cs",
12,
"ReaderWriterLockTests.MultipleReadersOneWriter_ReaderConcurrencyAndWriterExclusion",
"[Test]",
"bf63804480951667455038244228f77c30454a365b496f062051f7b34e7b2618",
);
}
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.GetRegionRestartScheduleAsync_WeeklySchedule_ParsesDaysAndTime::test 0f64aab66c6a6d807b3d2bbc46b636a85900e4f76e35d5e3dd8cd0d8b295618b pending
#[test]
fn region_schedule_tests_get_region_restart_schedule_async_weekly_s_6053e03675af() {
@@ -15212,19 +15121,6 @@ fn terrain_material_override_tests_set_terrain_material_overrides_a_8c4f3c7893c2
);
}
// parity-case: LibreMetaverse.Tests/TextureEntryTests.cs::TextureEntryTests.RoundTrip_HighFace_TextureID_IsPreserved::test 5f215cd1c50fa8871967653b4667f848c14ff24a3b71906e51aac13c56de1f55 pending
#[test]
fn texture_entry_tests_round_trip_high_face_texture_id_is_preserved_5238ccc2188c() {
pending(
"LibreMetaverse.Tests/TextureEntryTests.cs::TextureEntryTests.RoundTrip_HighFace_TextureID_IsPreserved::test",
"LibreMetaverse.Tests/TextureEntryTests.cs",
45,
"TextureEntryTests.RoundTrip_HighFace_TextureID_IsPreserved",
"[Test]",
"5f215cd1c50fa8871967653b4667f848c14ff24a3b71906e51aac13c56de1f55",
);
}
// parity-case: LibreMetaverse.Tests/TextureEntryTests.cs::TextureEntryTests.RoundTrip_HighFace_TextureID_IsPreserved::case:d3ad6116f2458248 5f215cd1c50fa8871967653b4667f848c14ff24a3b71906e51aac13c56de1f55 pending
#[test]
fn texture_entry_tests_round_trip_high_face_texture_id_is_preserved_c347d30187c6() {
@@ -15355,97 +15251,6 @@ fn texture_entry_tests_round_trip_all_faces_texture_i_ds_all_preser_953d0ed895bf
);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.UUIDs::test 4f95d48c474bbd824254196dd605051773c711614bf661b5aa996054b6c98967 pending
#[test]
fn type_tests_uui_ds_9bf21ba61003() {
pending(
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.UUIDs::test",
"LibreMetaverse.Tests/TypeTests.cs",
38,
"TypeTests.UUIDs",
"[Test]",
"4f95d48c474bbd824254196dd605051773c711614bf661b5aa996054b6c98967",
);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.Vector3ApproxEquals::test 1438175bb0c0bd8b17dd878e8fb95fb0dba82abbab71882f2ceb39ec554189d9 pending
#[test]
fn type_tests_vector3_approx_equals_1bab6a7c6f2c() {
pending(
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.Vector3ApproxEquals::test",
"LibreMetaverse.Tests/TypeTests.cs",
72,
"TypeTests.Vector3ApproxEquals",
"[Test]",
"1438175bb0c0bd8b17dd878e8fb95fb0dba82abbab71882f2ceb39ec554189d9",
);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.VectorCasting::test 27c0a4b8402ef66f11dca075d8c1a0f0b647ccef9c2803125dde6ca292951cd4 pending
#[test]
fn type_tests_vector_casting_2cc55b2c8d51() {
pending(
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.VectorCasting::test",
"LibreMetaverse.Tests/TypeTests.cs",
100,
"TypeTests.VectorCasting",
"[Test]",
"27c0a4b8402ef66f11dca075d8c1a0f0b647ccef9c2803125dde6ca292951cd4",
);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.Quaternions::test 071cf3ef6932e093c0fd09fe461a738e75af905707fce9a321b8f08dd89c09dd pending
#[test]
fn type_tests_quaternions_ee55bd386727() {
pending(
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.Quaternions::test",
"LibreMetaverse.Tests/TypeTests.cs",
154,
"TypeTests.Quaternions",
"[Test]",
"071cf3ef6932e093c0fd09fe461a738e75af905707fce9a321b8f08dd89c09dd",
);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.TestMatrix::test 5d5ccc8b9ea1741b013fd945e42ba7e6511322fdce51998e358d42c1736457e3 pending
#[test]
fn type_tests_test_matrix_726846ec4ddb() {
pending(
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.TestMatrix::test",
"LibreMetaverse.Tests/TypeTests.cs",
185,
"TypeTests.TestMatrix",
"[Test]",
"5d5ccc8b9ea1741b013fd945e42ba7e6511322fdce51998e358d42c1736457e3",
);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.VectorQuaternionMath::test 3c3cccd3bbec216e2be0e772b0912bec9faed5288da4f6bb4dff3c6f9952e113 pending
#[test]
fn type_tests_vector_quaternion_math_239214af3bde() {
pending(
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.VectorQuaternionMath::test",
"LibreMetaverse.Tests/TypeTests.cs",
211,
"TypeTests.VectorQuaternionMath",
"[Test]",
"3c3cccd3bbec216e2be0e772b0912bec9faed5288da4f6bb4dff3c6f9952e113",
);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.FloatsToTerseStrings::test ce34cdfe106d5dadfa82056e7aa7690d2da748c7e753b9d2a2ad682d86327def pending
#[test]
fn type_tests_floats_to_terse_strings_004651cda9df() {
pending(
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.FloatsToTerseStrings::test",
"LibreMetaverse.Tests/TypeTests.cs",
223,
"TypeTests.FloatsToTerseStrings",
"[Test]",
"ce34cdfe106d5dadfa82056e7aa7690d2da748c7e753b9d2a2ad682d86327def",
);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.BitUnpacking::test 741470d770a0a71853d84e26abaf927fc7dc385dedf0d7de87f63e7a22cb4dd7 pending
#[test]
fn type_tests_bit_unpacking_9f7b6fc4c72c() {
@@ -15563,110 +15368,6 @@ fn upload_thumbnail_tests_upload_thumbnail_async_upload_does_not_co_912d32ae591d
);
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.FileHelper_SanitizeAndSafeNames::test 770d1cb751c4b8290c9443bcb4a91d17703628a157cc428c607a7d36ae0af985 pending
#[test]
fn util_unit_tests_file_helper_sanitize_and_safe_names_ebdc5251a383() {
pending(
"LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.FileHelper_SanitizeAndSafeNames::test",
"LibreMetaverse.Tests/UtilUnitTests.cs",
12,
"UtilUnitTests.FileHelper_SanitizeAndSafeNames",
"[Test]",
"770d1cb751c4b8290c9443bcb4a91d17703628a157cc428c607a7d36ae0af985",
);
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.ObservableDictionary_Events_FireOnAddRemoveAndClear::test 579412c3c839e1fe5b44cf956f8d329a15d4e05c05778b4e6e3ff9b7d2fb7607 pending
#[test]
fn util_unit_tests_observable_dictionary_events_fire_on_add_remove_dec21e72d9d7() {
pending(
"LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.ObservableDictionary_Events_FireOnAddRemoveAndClear::test",
"LibreMetaverse.Tests/UtilUnitTests.cs",
33,
"UtilUnitTests.ObservableDictionary_Events_FireOnAddRemoveAndClear",
"[Test]",
"579412c3c839e1fe5b44cf956f8d329a15d4e05c05778b4e6e3ff9b7d2fb7607",
);
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.EventSubscriptionHelper_WaitForEventAndAsync::test bab59e0caf1630edda9a2a6daecca95cd1a28f189fdde01b1b6afee4cd96d8cb pending
#[test]
fn util_unit_tests_event_subscription_helper_wait_for_event_and_asy_dd72b61bced8() {
pending(
"LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.EventSubscriptionHelper_WaitForEventAndAsync::test",
"LibreMetaverse.Tests/UtilUnitTests.cs",
62,
"UtilUnitTests.EventSubscriptionHelper_WaitForEventAndAsync",
"[Test]",
"bab59e0caf1630edda9a2a6daecca95cd1a28f189fdde01b1b6afee4cd96d8cb",
);
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.Repeat_Interval_ExecutesAndCancels::test 43250eb6d7799ca3c00e51810b3e04d9a874bfdeafd77af6f7b78f8f6c73ff77 pending
#[test]
fn util_unit_tests_repeat_interval_executes_and_cancels_ebf1b45b8eb9() {
pending(
"LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.Repeat_Interval_ExecutesAndCancels::test",
"LibreMetaverse.Tests/UtilUnitTests.cs",
118,
"UtilUnitTests.Repeat_Interval_ExecutesAndCancels",
"[Test]",
"43250eb6d7799ca3c00e51810b3e04d9a874bfdeafd77af6f7b78f8f6c73ff77",
);
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.NameValue_ParseAndToString::test f779a81d286c0028ea202bab00f8db0d1bbaea611003458918a9ec9a24207557 pending
#[test]
fn util_unit_tests_name_value_parse_and_to_string_d86a82c100bf() {
pending(
"LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.NameValue_ParseAndToString::test",
"LibreMetaverse.Tests/UtilUnitTests.cs",
141,
"UtilUnitTests.NameValue_ParseAndToString",
"[Test]",
"f779a81d286c0028ea202bab00f8db0d1bbaea611003458918a9ec9a24207557",
);
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.Helpers_SplitAndFloatToTerseString::test aa2c378f56cfd04d6d4cfa50cd3efafd2b2d479d681336d72fbb9d5ec5c363e6 pending
#[test]
fn util_unit_tests_helpers_split_and_float_to_terse_string_7b31c6f6d09a() {
pending(
"LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.Helpers_SplitAndFloatToTerseString::test",
"LibreMetaverse.Tests/UtilUnitTests.cs",
153,
"UtilUnitTests.Helpers_SplitAndFloatToTerseString",
"[Test]",
"aa2c378f56cfd04d6d4cfa50cd3efafd2b2d479d681336d72fbb9d5ec5c363e6",
);
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.DisposalHelper_SafeDisposeAndUsing::test 433ebbfeb69eeb7ceaac86c4b3637468152a1f5a9f4c12ea8d7a74e1cb0c4fec pending
#[test]
fn util_unit_tests_disposal_helper_safe_dispose_and_using_d9ec7904c289() {
pending(
"LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.DisposalHelper_SafeDisposeAndUsing::test",
"LibreMetaverse.Tests/UtilUnitTests.cs",
163,
"UtilUnitTests.DisposalHelper_SafeDisposeAndUsing",
"[Test]",
"433ebbfeb69eeb7ceaac86c4b3637468152a1f5a9f4c12ea8d7a74e1cb0c4fec",
);
}
// parity-case: LibreMetaverse.Tests/UtilsConversionsTests.cs::UtilsConversionsTests.StringToBytes::test 0bef42801dc2a50e132b05440424c44da54b53c853708ee2c0ec9799dbe0e8b2 pending
#[test]
fn utils_conversions_tests_string_to_bytes_fdacb435c54d() {
pending(
"LibreMetaverse.Tests/UtilsConversionsTests.cs::UtilsConversionsTests.StringToBytes::test",
"LibreMetaverse.Tests/UtilsConversionsTests.cs",
35,
"UtilsConversionsTests.StringToBytes",
"[Test]",
"0bef42801dc2a50e132b05440424c44da54b53c853708ee2c0ec9799dbe0e8b2",
);
}
// parity-case: LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeLLSDSample::test 2495e7d5c414b59962f03282c51fe1c0d5de350b51c1bdfcee9ced7c32acbe4d pending
#[test]
fn xml_sd_tests_deserialize_llsd_sample_665062bb9667() {

View File

@@ -0,0 +1,584 @@
#![allow(clippy::cast_possible_truncation, clippy::float_cmp)]
use libremetaverse::{
DictionaryEventAction, DisposalHelper, EventSubscription, EventSubscriptionHelper, FileHelper,
Helpers, NameValue, NameValueClassType, NameValueSendtoType, NameValueValueType,
ObservableDictionary, PositionHelper, Repeat, Simulator, threading::OptimisticReaderWriterLock,
};
use libremetaverse_compat_tests::{assert_close, block_on};
use libremetaverse_types::compat::{CancellationToken, Close, ExternalError, Guid, Utf16CodeUnit};
use libremetaverse_types::{Matrix4, Quaternion, UUID, Utils, Vector3, Vector3d};
use std::cell::Cell;
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
use std::sync::{Arc, Barrier, Mutex, mpsc};
use std::time::Duration;
fn vector3(x: f32, y: f32, z: f32) -> Vector3 {
Vector3::new_with_single_single_single(x, y, z).expect("Vector3 constructor")
}
fn vector3d(x: f64, y: f64, z: f64) -> Vector3d {
Vector3d::new_with_double_double_double(x, y, z).expect("Vector3d constructor")
}
fn quaternion(x: f32, y: f32, z: f32, w: f32) -> Quaternion {
Quaternion::new_with_single_single_single_single(x, y, z, w).expect("Quaternion constructor")
}
fn matrix(values: [f32; 16]) -> Matrix4 {
Matrix4::new_with_single_single_single_single_single_single_single_single_single_single_single_single_single_single_single_single(
values[0], values[1], values[2], values[3], values[4], values[5], values[6],
values[7], values[8], values[9], values[10], values[11], values[12], values[13],
values[14], values[15],
)
.expect("Matrix4 constructor")
}
fn assert_vector3(actual: &Vector3, expected: [f32; 3]) {
assert_eq!([actual.x, actual.y, actual.z], expected);
}
fn assert_vector3d(actual: &Vector3d, expected: [f64; 3]) {
assert_eq!([actual.x, actual.y, actual.z], expected);
}
fn assert_quaternion(actual: &Quaternion, expected: [f32; 4]) {
assert_eq!([actual.x, actual.y, actual.z, actual.w], expected);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.UUIDs::test 4f95d48c474bbd824254196dd605051773c711614bf661b5aa996054b6c98967 translated
#[test]
fn uuids() {
let zero = UUID::zero();
assert_eq!(zero.get_bytes().expect("UUID bytes"), [0; 16]);
let with_trailing_bytes = vec![
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0xff, 0xff,
];
let exact_bytes = with_trailing_bytes[..16].to_vec();
let a = UUID::new_with_bytes_int32(with_trailing_bytes, 0).expect("UUID byte constructor");
let b = UUID::new_with_bytes_int32(exact_bytes.clone(), 0).expect("UUID byte constructor");
assert!(a.equals_with_uuid(b));
let text = "00010203-0405-0607-0809-0a0b0c0d0e0f";
let a = UUID::new_with_bytes_int32(exact_bytes, 0).expect("UUID byte constructor");
let b = UUID::new_with_string(text.into()).expect("UUID string constructor");
assert!(a.equals_with_uuid(b));
let a = UUID::new_with_string(text.into()).expect("UUID string constructor");
assert_eq!(a.to_string(), text);
let parsed = UUID::parse(text.into()).expect("UUID parse");
let expected = UUID::new_with_string(text.into()).expect("UUID string constructor");
assert!(parsed.equals_with_uuid(expected));
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.Vector3ApproxEquals::test 1438175bb0c0bd8b17dd878e8fb95fb0dba82abbab71882f2ceb39ec554189d9 translated
#[test]
fn vector3_approx_equals() {
let cases = [
([1.0, 0.0, 0.0], [0.0, 0.0, 0.0], 0.9, false),
([1.0, 0.0, 0.0], [0.0, 0.0, 0.0], 1.0, true),
([-1.0, 0.0, 0.0], [1.0, 0.0, 0.0], 1.9, false),
([-1.0, 0.0, 0.0], [1.0, 0.0, 0.0], 2.0, true),
([0.0, -1.0, 0.0], [0.0, -1.1, 0.0], 0.09, false),
([0.0, -1.0, 0.0], [0.0, -1.1, 0.0], 0.11, true),
(
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.00001],
f32::from_bits(1),
false,
),
([0.0, 0.0, 0.0], [0.0, 0.0, 0.00001], 0.0001, true),
];
for (left, right, tolerance, expected) in cases {
let mut left = vector3(left[0], left[1], left[2]);
let right = vector3(right[0], right[1], right[2]);
assert_eq!(
left.approx_equals(right, tolerance)
.expect("Vector3 ApproxEquals"),
expected
);
}
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.VectorCasting::test 27c0a4b8402ef66f11dca075d8c1a0f0b647ccef9c2803125dde6ca292951cd4 translated
#[test]
fn vector_casting() {
for value in [
1.0,
1.1,
1.01,
1.001,
1.0001,
1.00001,
1.000_001,
1.000_000_1,
1.000_000_01,
] {
let narrowed = value as f32;
let no_precision_loss = value == f64::from(narrowed);
let c = Vector3::new_with_vector3d(vector3d(value, value, value))
.expect("Vector3d to Vector3 cast");
assert_vector3(&c, [narrowed; 3]);
let d = Vector3d::new_with_vector3(vector3(narrowed, narrowed, narrowed))
.expect("Vector3 to Vector3d cast");
if !no_precision_loss {
assert_ne!([d.x, d.y, d.z], [value; 3]);
}
assert_vector3d(&d, [f64::from(narrowed); 3]);
let left = Vector3d::new_with_vector3(vector3(narrowed, narrowed, narrowed))
.expect("implicit Vector3 to Vector3d cast");
let right = vector3d(
f64::from(narrowed),
f64::from(narrowed),
f64::from(narrowed),
);
assert!(Vector3d::eq(left, right));
}
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.Quaternions::test 071cf3ef6932e093c0fd09fe461a738e75af905707fce9a321b8f08dd89c09dd translated
#[test]
fn quaternions() {
let a = quaternion(1.0, 0.0, 0.0, 0.0);
let b = quaternion(1.0, 0.0, 0.0, 0.0);
assert!(Quaternion::eq(a, b));
let result = Quaternion::multiply_with_quaternion_quaternion(
quaternion(1.0, 0.0, 0.0, 0.0),
quaternion(1.0, 0.0, 0.0, 0.0),
)
.expect("Quaternion multiply");
assert_quaternion(&result, [0.0, 0.0, 0.0, -1.0]);
let result = Quaternion::multiply_with_quaternion_quaternion(
quaternion(1.0, 0.0, 0.0, 0.0),
quaternion(0.0, 1.0, 0.0, 0.0),
)
.expect("Quaternion multiply");
assert_quaternion(&result, [0.0, 0.0, 1.0, 0.0]);
let result = Quaternion::multiply_with_quaternion_quaternion(
quaternion(0.0, 0.0, 1.0, 0.0),
quaternion(0.0, 1.0, 0.0, 0.0),
)
.expect("Quaternion multiply");
assert_quaternion(&result, [-1.0, 0.0, 0.0, 0.0]);
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.TestMatrix::test 5d5ccc8b9ea1741b013fd945e42ba7e6511322fdce51998e358d42c1736457e3 translated
#[test]
fn test_matrix() {
let mut singular = matrix([
0.0, 0.0, 74.0, 1.0, 0.0, 435.0, 0.0, 1.0, 345.0, 0.0, 34.0, 1.0, 0.0, 0.0, 0.0, 0.0,
]);
assert_close(
f64::from(singular.determinant().expect("Matrix4 determinant")),
0.0,
0.001,
);
let inverse_identity = Matrix4::inverse(Matrix4::identity()).expect("Matrix4 inverse");
assert!(Matrix4::eq(Matrix4::identity(), inverse_identity));
let input = matrix([
1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
]);
let expected = matrix([
0.0, 1.0, -1.0, 0.0, 1.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
]);
assert!(Matrix4::eq(
Matrix4::inverse(input).expect("Matrix4 inverse"),
expected
));
}
// parity-case: LibreMetaverse.Tests/TypeTests.cs::TypeTests.FloatsToTerseStrings::test ce34cdfe106d5dadfa82056e7aa7690d2da748c7e753b9d2a2ad682d86327def translated
#[test]
fn floats_to_terse_strings() {
for (value, expected) in [(1.20, "1.2"), (24.00, "24"), (-0.59, "-.59"), (0.59, ".59")] {
assert_eq!(
Helpers::float_to_terse_string(value).expect("FloatToTerseString"),
expected
);
}
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.FileHelper_SanitizeAndSafeNames::test 770d1cb751c4b8290c9443bcb4a91d17703628a157cc428c607a7d36ae0af985 translated
#[test]
fn file_helper_sanitize_and_safe_names() {
let safe = FileHelper::safe_file_name("inva:lid/fi*le?.txt".into()).expect("safe file name");
assert!(!safe.is_empty());
assert!(!safe.contains(':'));
assert!(
!FileHelper::safe_dir_name("path|with?bad".into())
.expect("safe directory name")
.contains('|')
);
assert_eq!(
FileHelper::sanitize(
"abcxyz".into(),
vec![Utf16CodeUnit('a' as u16), Utf16CodeUnit('b' as u16)],
Some(Utf16CodeUnit('-' as u16)),
)
.expect("sanitize"),
"--cxyz"
);
let mut first = None;
let mut last = None;
assert!(FileHelper::try_parse_two_names(
"First Last".into(),
&mut first,
&mut last
));
assert_eq!(first.as_deref(), Some("First"));
assert_eq!(last.as_deref(), Some("Last"));
assert!(!FileHelper::try_parse_two_names(
" Too Many Parts Extra".into(),
&mut first,
&mut last
));
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.ObservableDictionary_Events_FireOnAddRemoveAndClear::test 579412c3c839e1fe5b44cf956f8d329a15d4e05c05778b4e6e3ff9b7d2fb7607 translated
#[test]
fn observable_dictionary_events_fire_on_add_remove_and_clear() {
let mut dictionary = ObservableDictionary::<String, i32>::new_with_constructor()
.expect("ObservableDictionary constructor");
let adds = Arc::new(AtomicI32::new(0));
let removes = Arc::new(AtomicI32::new(0));
let changes = Arc::new(AtomicI32::new(0));
let add_count = Arc::clone(&adds);
dictionary
.add_delegate(
DictionaryEventAction::Add,
Arc::new(move |action, _entry| {
if action == DictionaryEventAction::Add {
add_count.fetch_add(1, Ordering::SeqCst);
}
}),
)
.expect("add callback");
let remove_count = Arc::clone(&removes);
dictionary
.add_delegate(
DictionaryEventAction::Remove,
Arc::new(move |action, _entry| {
if action == DictionaryEventAction::Remove {
remove_count.fetch_add(1, Ordering::SeqCst);
}
}),
)
.expect("remove callback");
let change_count = Arc::clone(&changes);
dictionary
.add_delegate(
DictionaryEventAction::Change,
Arc::new(move |action, _entry| {
if action == DictionaryEventAction::Change {
change_count.fetch_add(1, Ordering::SeqCst);
}
}),
)
.expect("change callback");
dictionary
.add("one".into(), Some(1))
.expect("dictionary add");
assert_eq!(adds.load(Ordering::SeqCst), 1);
dictionary.set_item(Some("one".into()), Some(2));
assert!(adds.load(Ordering::SeqCst) >= 1);
assert!(dictionary.remove("one".into()).expect("dictionary remove"));
assert_eq!(removes.load(Ordering::SeqCst), 1);
dictionary.add("a".into(), Some(1)).expect("dictionary add");
dictionary.add("b".into(), Some(2)).expect("dictionary add");
dictionary.clear().expect("dictionary clear");
assert!(removes.load(Ordering::SeqCst) >= 3);
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.EventSubscriptionHelper_WaitForEventAndAsync::test bab59e0caf1630edda9a2a6daecca95cd1a28f189fdde01b1b6afee4cd96d8cb translated
#[test]
fn event_subscription_helper_wait_for_event_and_async() {
type UnitHandler = Arc<dyn Fn(Option<()>) + Send + Sync>;
let handler: Arc<Mutex<Option<UnitHandler>>> = Arc::new(Mutex::new(None));
let subscribed_handler = Arc::clone(&handler);
let unsubscribed_handler = Arc::clone(&handler);
let fired_handler = Arc::clone(&handler);
let (subscribed_tx, subscribed_rx) = mpsc::sync_channel(0);
let fire = std::thread::spawn(move || {
if subscribed_rx.recv_timeout(Duration::from_secs(5)).is_ok()
&& let Some(handler) = fired_handler.lock().expect("event handler").as_ref()
{
handler(Some(()));
}
});
let result =
EventSubscriptionHelper::wait_for_event_with_action_action_func_func_int32_t_result::<
(),
i32,
>(
Box::new(move |handler| {
*subscribed_handler.lock().expect("event handler") = Some(handler);
subscribed_tx.send(()).expect("subscription signal");
}),
Box::new(move |_handler| {
*unsubscribed_handler.lock().expect("event handler") = None;
}),
Box::new(|_event| true),
Box::new(|_event| Some(123)),
5_000,
Some(-1),
)
.expect("WaitForEvent");
assert_eq!(result, Some(123));
fire.join().expect("event fire task");
let handler: Arc<Mutex<Option<UnitHandler>>> = Arc::new(Mutex::new(None));
let subscribed_handler = Arc::clone(&handler);
let unsubscribed_handler = Arc::clone(&handler);
let fired_handler = Arc::clone(&handler);
let (subscribed_tx, subscribed_rx) = mpsc::sync_channel(0);
let fire = std::thread::spawn(move || {
if subscribed_rx.recv_timeout(Duration::from_secs(5)).is_ok()
&& let Some(handler) = fired_handler.lock().expect("event handler").as_ref()
{
handler(Some(()));
}
});
let async_result = block_on(
EventSubscriptionHelper::wait_for_event_with_action_action_func_func_int32_cancellation_token_t_result::<(), Guid>(
Box::new(move |handler| {
*subscribed_handler.lock().expect("event handler") = Some(handler);
subscribed_tx.send(()).expect("subscription signal");
}),
Box::new(move |_handler| {
*unsubscribed_handler.lock().expect("event handler") = None;
}),
Box::new(|_event| true),
Box::new(|_event| Some(Guid([0; 16]))),
5_000,
Some(CancellationToken),
Some(Guid([1; 16])),
),
)
.expect("WaitForEventAsync");
assert_eq!(async_result, Some(Guid([0; 16])));
fire.join().expect("async event fire task");
let subscription = EventSubscription::<()>::new(
Box::new(|_handler| {}),
Box::new(|_handler| {}),
Arc::new(|_event| {}),
)
.expect("EventSubscription constructor");
subscription.dispose().expect("EventSubscription dispose");
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.Repeat_Interval_ExecutesAndCancels::test 43250eb6d7799ca3c00e51810b3e04d9a874bfdeafd77af6f7b78f8f6c73ff77 translated
#[test]
fn repeat_interval_executes_and_cancels() {
let count = Arc::new(AtomicI32::new(0));
let action_count = Arc::clone(&count);
block_on(
Repeat::interval_with_time_span_action_cancellation_token_boolean(
Duration::from_millis(50),
Box::new(move || {
action_count.fetch_add(1, Ordering::SeqCst);
}),
CancellationToken,
Some(true),
),
)
.expect("Repeat interval");
assert!(count.load(Ordering::SeqCst) >= 1);
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.NameValue_ParseAndToString::test f779a81d286c0028ea202bab00f8db0d1bbaea611003458918a9ec9a24207557 translated
#[test]
fn name_value_parse_and_to_string() {
let parsed =
NameValue::new_with_string("greeting STRING R S Hello".into()).expect("NameValue parse");
assert_eq!(parsed.name, "greeting");
assert_eq!(parsed.type_, NameValueValueType::String);
assert_eq!(parsed.class_, NameValueClassType::ReadOnly);
assert_eq!(parsed.sendto, NameValueSendtoType::Sim);
let rendered = NameValue::name_values_to_string(vec![parsed]).expect("NameValue render");
assert!(rendered.contains("Hello"));
let value = NameValue::new_with_string("n1 STRING R S v1".into()).expect("NameValue parse");
let rendered = NameValue::name_values_to_string(vec![value]).expect("NameValue render");
assert!(rendered.contains("n1") && rendered.contains("v1"));
}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.Helpers_SplitAndFloatToTerseString::test aa2c378f56cfd04d6d4cfa50cd3efafd2b2d479d681336d72fbb9d5ec5c363e6 translated
#[test]
fn helpers_split_and_float_to_terse_string() {
let chunks: Vec<_> = Helpers::split_by("abcdef".into(), 2)
.expect("SplitBy")
.collect();
assert_eq!(chunks, ["ab", "cd", "ef"]);
assert_eq!(
Helpers::float_to_terse_string(0.0).expect("FloatToTerseString"),
".00"
);
assert!(
Helpers::float_to_terse_string(1.2300)
.expect("FloatToTerseString")
.contains("1.23")
);
}
struct ThrowOnDrop(Arc<AtomicBool>);
impl Close for ThrowOnDrop {}
impl Drop for ThrowOnDrop {
fn drop(&mut self) {
self.0.store(true, Ordering::SeqCst);
}
}
struct DisposableFlag(Cell<i32>);
impl Close for DisposableFlag {}
// parity-case: LibreMetaverse.Tests/UtilUnitTests.cs::UtilUnitTests.DisposalHelper_SafeDisposeAndUsing::test 433ebbfeb69eeb7ceaac86c4b3637468152a1f5a9f4c12ea8d7a74e1cb0c4fec translated
#[test]
fn disposal_helper_safe_dispose_and_using() {
let disposed = Arc::new(AtomicBool::new(false));
let logged = Arc::new(Mutex::new(None));
let logger_result = Arc::clone(&logged);
DisposalHelper::safe_dispose(
Box::new(ThrowOnDrop(Arc::clone(&disposed))),
Some("test".into()),
Some(Box::new(
move |message: String, _error: Option<ExternalError>| {
*logger_result.lock().expect("logger state") = Some(message);
},
)),
)
.expect("SafeDispose");
assert!(disposed.load(Ordering::SeqCst));
assert!(logged.lock().expect("logger state").is_some());
let result = DisposalHelper::using_with_func_func_3fbb9598(
Box::new(|| DisposableFlag(Cell::new(0))),
Box::new(|value| {
value.0.set(5);
Some(value.0.get())
}),
)
.expect("Using");
assert_eq!(result, Some(5));
}
// parity-case: LibreMetaverse.Tests/PositionHelperTests.cs::PositionHelperTests.ToGlobalAndLocalPosition_RoundTrip::test 695c6a640e5353e02def9a1b4a1c1eabb37a8543c13466dff570f58d847e7772 translated
#[test]
fn to_global_and_local_position_round_trip() {
let global_x = 512 * Simulator::DEFAULT_REGION_SIZE_X;
let global_y = 1024 * Simulator::DEFAULT_REGION_SIZE_Y;
let handle = Utils::u_ints_to_long(global_x, global_y).expect("region handle");
let local = vector3(10.5, 20.25, 5.0);
let global = PositionHelper::to_global_position(handle, local).expect("global position");
assert_close(global.x, f64::from(global_x) + 10.5, 0.0001);
assert_close(global.y, f64::from(global_y) + 20.25, 0.0001);
assert_close(global.z, 5.0, 0.0001);
let local = PositionHelper::to_local_position(handle, global).expect("local position");
assert_close(f64::from(local.x), 10.5, 0.0001);
assert_close(f64::from(local.y), 20.25, 0.0001);
assert_close(f64::from(local.z), 5.0, 0.0001);
}
// parity-case: LibreMetaverse.Tests/PositionHelperTests.cs::PositionHelperTests.FormatCoordinates_FormatsCorrectly::test fe4256d00dab5cc2de602b7b27442cac627a5956c4ce79c05d92de830f6fc5d2 translated
#[test]
fn format_coordinates_formats_correctly() {
for (coordinates, expected) in [
((None, None, None), ""),
((Some(Some(10)), None, None), " (10)"),
((Some(Some(10)), Some(Some(20)), None), " (10,20)"),
(
(Some(Some(10)), Some(Some(20)), Some(Some(30))),
" (10,20,30)",
),
] {
assert_eq!(
PositionHelper::format_coordinates(coordinates.0, coordinates.1, coordinates.2)
.expect("FormatCoordinates"),
expected
);
}
}
// parity-case: LibreMetaverse.Tests/ReaderWriterLockTests.cs::ReaderWriterLockTests.MultipleReadersOneWriter_ReaderConcurrencyAndWriterExclusion::test bf63804480951667455038244228f77c30454a365b496f062051f7b34e7b2618 translated
#[test]
fn multiple_readers_one_writer_reader_concurrency_and_writer_exclusion() {
const READERS: usize = 5;
let lock = Arc::new(OptimisticReaderWriterLock::new().expect("reader/writer lock constructor"));
let start = Arc::new(Barrier::new(READERS + 1));
let release = Arc::new(Barrier::new(READERS + 1));
let current = Arc::new(AtomicI32::new(0));
let maximum = Arc::new(AtomicI32::new(0));
let (entered_tx, entered_rx) = mpsc::channel();
let mut readers = Vec::new();
for _ in 0..READERS {
let lock = Arc::clone(&lock);
let start = Arc::clone(&start);
let release = Arc::clone(&release);
let current = Arc::clone(&current);
let maximum = Arc::clone(&maximum);
let entered = entered_tx.clone();
readers.push(std::thread::spawn(move || {
start.wait();
let _guard = lock.read_lock().expect("read lock");
let active = current.fetch_add(1, Ordering::SeqCst) + 1;
maximum.fetch_max(active, Ordering::SeqCst);
entered.send(()).expect("reader entered signal");
release.wait();
std::thread::sleep(Duration::from_millis(20));
current.fetch_sub(1, Ordering::SeqCst);
}));
}
start.wait();
for _ in 0..READERS {
entered_rx
.recv_timeout(Duration::from_secs(30))
.expect("all readers should enter within 30 seconds");
}
let (writer_tx, writer_rx) = mpsc::channel();
let writer_lock = Arc::clone(&lock);
let writer = std::thread::spawn(move || {
let _guard = writer_lock.write_lock().expect("write lock");
writer_tx.send(()).expect("writer acquired signal");
});
assert!(writer_rx.recv_timeout(Duration::from_millis(100)).is_err());
release.wait();
writer_rx
.recv_timeout(Duration::from_secs(30))
.expect("writer should acquire after readers exit");
assert!(maximum.load(Ordering::SeqCst) >= 2);
for reader in readers {
reader.join().expect("reader task");
}
writer.join().expect("writer task");
}
// parity-case: LibreMetaverse.Tests/UtilsConversionsTests.cs::UtilsConversionsTests.StringToBytes::test 0bef42801dc2a50e132b05440424c44da54b53c853708ee2c0ec9799dbe0e8b2 translated
#[test]
fn string_to_bytes() {
let text = "Your squirrel, your imagination";
let bytes = Utils::string_to_bytes(text.into()).expect("StringToBytes");
assert_eq!(
Utils::bytes_to_string_with_bytes(bytes).expect("BytesToString"),
text
);
}

View File

@@ -5,9 +5,10 @@ use libremetaverse::{
TerrainManager, TerrainPatch,
};
use libremetaverse_types::UUID;
use libremetaverse_types::compat::{
CancellationToken, EventHandler, IAsyncEnumerable, Subscription,
};
use libremetaverse_types::compat::{CancellationToken, IAsyncEnumerable, Subscription};
use std::sync::Arc;
type EventHandler<T> = Arc<dyn Fn(T) + Send + Sync>;
fn member_id<T>(result: Result<T, libremetaverse::Error>) -> &'static str {
result

File diff suppressed because it is too large Load Diff