diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/enum-map/tests | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/enum-map/tests')
-rw-r--r-- | third_party/rust/enum-map/tests/serde.rs | 115 | ||||
-rw-r--r-- | third_party/rust/enum-map/tests/test.rs | 696 |
2 files changed, 811 insertions, 0 deletions
diff --git a/third_party/rust/enum-map/tests/serde.rs b/third_party/rust/enum-map/tests/serde.rs new file mode 100644 index 0000000000..062ffe246a --- /dev/null +++ b/third_party/rust/enum-map/tests/serde.rs @@ -0,0 +1,115 @@ +#![cfg(feature = "serde")] + +// SPDX-FileCopyrightText: 2017 - 2022 Kamila Borowska <kamila@borowska.pw> +// SPDX-FileCopyrightText: 2022 Cass Fridkin <cass@cloudflare.com> +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use enum_map::{enum_map, Enum, EnumMap}; +use serde::{Deserialize, Serialize}; +use serde_test::{assert_de_tokens_error, assert_tokens, Compact, Configure, Token}; + +#[derive(Debug, Enum, Deserialize, Serialize)] +enum Example { + A, + B, +} + +#[test] +fn serialization() { + let map = enum_map! { Example::A => 5, Example::B => 10 }; + assert_tokens( + &map.readable(), + &[ + Token::Map { len: Some(2) }, + Token::UnitVariant { + name: "Example", + variant: "A", + }, + Token::I32(5), + Token::UnitVariant { + name: "Example", + variant: "B", + }, + Token::I32(10), + Token::MapEnd, + ], + ); +} + +#[test] +fn compact_serialization() { + let map = enum_map! { Example::A => 5, Example::B => 10 }; + assert_tokens( + &map.compact(), + &[ + Token::Tuple { len: 2 }, + Token::I32(5), + Token::I32(10), + Token::TupleEnd, + ], + ); +} + +#[test] +fn invalid_compact_deserialization() { + assert_de_tokens_error::<Compact<EnumMap<bool, bool>>>( + &[Token::I32(4)], + "invalid type: integer `4`, expected a sequence", + ); +} + +#[test] +fn too_short_compact_deserialization() { + assert_de_tokens_error::<Compact<EnumMap<bool, bool>>>( + &[Token::Seq { len: None }, Token::Bool(true), Token::SeqEnd], + "invalid length 1, expected a sequence with as many elements as there are variants", + ); +} + +const JSON: &str = r#"{"A":5,"B":10}"#; + +#[test] +fn json_serialization() { + let map = enum_map! { Example::A => 5, Example::B => 10 }; + assert_eq!(serde_json::to_string(&map).unwrap(), String::from(JSON)); +} + +#[test] +fn json_deserialization() { + let example: EnumMap<Example, i32> = serde_json::from_str(JSON).unwrap(); + assert_eq!(example, enum_map! { Example::A => 5, Example::B => 10 }); +} + +#[test] +fn json_invalid_deserialization() { + let example: Result<EnumMap<Example, i32>, _> = serde_json::from_str(r"{}"); + assert!(example.is_err()); +} + +#[test] +fn json_invalid_type() { + let example: Result<EnumMap<Example, i32>, _> = serde_json::from_str("4"); + assert!(example.is_err()); +} + +#[test] +fn json_invalid_key() { + let example: Result<EnumMap<Example, i32>, _> = + serde_json::from_str(r#"{"a": 5, "b": 10, "c": 6}"#); + assert!(example.is_err()); +} + +#[test] +fn bincode_serialization() { + let example = enum_map! { false => 3u8, true => 4u8 }; + let serialized = bincode::serialize(&example).unwrap(); + assert_eq!(example, bincode::deserialize(&serialized).unwrap()); +} + +#[test] +fn bincode_too_short_deserialization() { + assert!( + bincode::deserialize::<EnumMap<bool, bool>>(&bincode::serialize(&()).unwrap()).is_err() + ); +} diff --git a/third_party/rust/enum-map/tests/test.rs b/third_party/rust/enum-map/tests/test.rs new file mode 100644 index 0000000000..66cea1fd1b --- /dev/null +++ b/third_party/rust/enum-map/tests/test.rs @@ -0,0 +1,696 @@ +// SPDX-FileCopyrightText: 2018 - 2022 Kamila Borowska <kamila@borowska.pw> +// SPDX-FileCopyrightText: 2019 Riey <creeper844@gmail.com> +// SPDX-FileCopyrightText: 2020 Amanieu d'Antras <amanieu@gmail.com> +// SPDX-FileCopyrightText: 2021 Bruno CorrĂȘa Zimmermann <brunoczim@gmail.com> +// SPDX-FileCopyrightText: 2021 micycle +// SPDX-FileCopyrightText: 2022 Cass Fridkin <cass@cloudflare.com> +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +#[macro_use] +extern crate enum_map; + +use enum_map::{Enum, EnumArray, EnumMap, IntoIter}; + +use std::cell::{Cell, RefCell}; +use std::collections::HashSet; +use std::convert::Infallible; +use std::marker::PhantomData; +use std::num::ParseIntError; +use std::panic::{catch_unwind, UnwindSafe}; + +trait From<T>: Sized { + fn from(_: T) -> Self { + unreachable!(); + } +} + +impl<T, U> From<T> for U {} + +#[derive(Copy, Clone, Debug, Enum, PartialEq)] +enum Example { + A, + B, + C, +} + +#[test] +fn test_bool() { + let mut map = enum_map! { false => 24, true => 42 }; + assert_eq!(map[false], 24); + assert_eq!(map[true], 42); + map[false] += 1; + assert_eq!(map[false], 25); + for (key, item) in &mut map { + if !key { + *item += 1; + } + } + assert_eq!(map[false], 26); + assert_eq!(map[true], 42); +} + +#[test] +fn test_clone() { + let map = enum_map! { false => 3, true => 5 }; + assert_eq!(map.clone(), map); +} + +#[test] +fn test_debug() { + let map = enum_map! { false => 3, true => 5 }; + assert_eq!(format!("{:?}", map), "{false: 3, true: 5}"); +} + +#[test] +fn test_hash() { + let map = enum_map! { false => 3, true => 5 }; + let mut set = HashSet::new(); + set.insert(map); + assert!(set.contains(&map)); +} + +#[test] +fn test_clear() { + let mut map = enum_map! { false => 1, true => 2 }; + map.clear(); + assert_eq!(map[true], 0); + assert_eq!(map[false], 0); +} + +#[test] +fn struct_of_enum() { + #[derive(Copy, Clone, Debug, Enum, PartialEq)] + struct Product { + example: Example, + is_done: bool, + } + + let mut map = enum_map! { + Product { example: Example::A, is_done: false } => "foo", + Product { example: Example::B, is_done: false } => "bar", + Product { example: Example::C, is_done: false } => "baz", + Product { example: Example::A, is_done: true } => "done foo", + Product { example: Example::B, is_done: true } => "bar done", + Product { example: Example::C, is_done: true } => "doooozne", + }; + + assert_eq!( + map[Product { + example: Example::B, + is_done: false + }], + "bar" + ); + assert_eq!( + map[Product { + example: Example::C, + is_done: false + }], + "baz" + ); + assert_eq!( + map[Product { + example: Example::B, + is_done: true + }], + "bar done" + ); + + map[Product { + example: Example::B, + is_done: true, + }] = "not really done"; + assert_eq!( + map[Product { + example: Example::B, + is_done: false + }], + "bar" + ); + assert_eq!( + map[Product { + example: Example::C, + is_done: false + }], + "baz" + ); + assert_eq!( + map[Product { + example: Example::B, + is_done: true + }], + "not really done" + ); +} + +#[test] +fn tuple_struct_of_enum() { + #[derive(Copy, Clone, Debug, Enum, PartialEq)] + struct Product(Example, bool); + + let mut map = enum_map! { + Product(Example::A, false) => "foo", + Product(Example::B, false) => "bar", + Product(Example::C, false) => "baz", + Product(Example::A, true) => "done foo", + Product(Example::B, true) => "bar done", + Product(Example::C, true) => "doooozne", + }; + + assert_eq!(map[Product(Example::B, false)], "bar"); + assert_eq!(map[Product(Example::C, false)], "baz"); + assert_eq!(map[Product(Example::B, true)], "bar done"); + + map[Product(Example::B, true)] = "not really done"; + assert_eq!(map[Product(Example::B, false)], "bar"); + assert_eq!(map[Product(Example::C, false)], "baz"); + assert_eq!(map[Product(Example::B, true)], "not really done"); +} + +#[test] +fn discriminants() { + #[derive(Debug, Enum, PartialEq)] + enum Discriminants { + A = 2000, + B = 3000, + C = 1000, + } + let mut map = EnumMap::default(); + map[Discriminants::A] = 3; + map[Discriminants::B] = 2; + map[Discriminants::C] = 1; + let mut pairs = map.iter(); + assert_eq!(pairs.next(), Some((Discriminants::A, &3))); + assert_eq!(pairs.next(), Some((Discriminants::B, &2))); + assert_eq!(pairs.next(), Some((Discriminants::C, &1))); + assert_eq!(pairs.next(), None); +} + +#[test] +fn extend() { + let mut map = enum_map! { _ => 0 }; + map.extend(vec![(Example::A, 3)]); + map.extend(vec![(&Example::B, &4)]); + assert_eq!( + map, + enum_map! { Example::A => 3, Example::B => 4, Example::C => 0 } + ); +} + +#[test] +fn collect() { + let iter = vec![(Example::A, 5), (Example::B, 7)] + .into_iter() + .map(|(k, v)| (k, v + 1)); + assert_eq!( + iter.collect::<EnumMap<_, _>>(), + enum_map! { Example::A => 6, Example::B => 8, Example::C => 0 } + ); +} + +#[test] +fn huge_enum() { + #[derive(Enum)] + enum Example { + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T, + U, + V, + W, + X, + Y, + Z, + Aa, + Bb, + Cc, + Dd, + Ee, + Ff, + Gg, + Hh, + Ii, + Jj, + Kk, + Ll, + Mm, + Nn, + Oo, + Pp, + Qq, + Rr, + Ss, + Tt, + Uu, + Vv, + Ww, + Xx, + Yy, + Zz, + } + + let map = enum_map! { _ => 2 }; + assert_eq!(map[Example::Xx], 2); +} + +#[test] +fn iterator_len() { + assert_eq!( + enum_map! { Example::A | Example::B | Example::C => 0 } + .iter() + .len(), + 3 + ); +} + +#[test] +fn iter_mut_len() { + assert_eq!( + enum_map! { Example::A | Example::B | Example::C => 0 } + .iter_mut() + .len(), + 3 + ); +} + +#[test] +fn into_iter_len() { + assert_eq!(enum_map! { Example::A | _ => 0 }.into_iter().len(), 3); +} + +#[test] +fn iterator_next_back() { + assert_eq!( + enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 } + .iter() + .next_back(), + Some((Example::C, &3)) + ); +} + +#[test] +fn iter_mut_next_back() { + assert_eq!( + enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 } + .iter_mut() + .next_back(), + Some((Example::C, &mut 3)) + ); +} + +#[test] +fn into_iter() { + let mut iter = enum_map! { true => 5, false => 7 }.into_iter(); + assert_eq!(iter.next(), Some((false, 7))); + assert_eq!(iter.next(), Some((true, 5))); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); +} + +#[test] +fn into_iter_u8() { + assert_eq!( + enum_map! { i => i }.into_iter().collect::<Vec<_>>(), + (0..256).map(|x| (x as u8, x as u8)).collect::<Vec<_>>() + ); +} + +struct DropReporter<'a> { + into: &'a RefCell<Vec<usize>>, + value: usize, +} + +impl<'a> Drop for DropReporter<'a> { + fn drop(&mut self) { + self.into.borrow_mut().push(self.value); + } +} + +#[test] +fn into_iter_drop() { + let dropped = RefCell::new(Vec::default()); + let mut a: IntoIter<Example, _> = enum_map! { + k => DropReporter { + into: &dropped, + value: k as usize, + }, + } + .into_iter(); + assert_eq!(a.next().unwrap().0, Example::A); + assert_eq!(*dropped.borrow(), &[0]); + drop(a); + assert_eq!(*dropped.borrow(), &[0, 1, 2]); +} + +#[test] +fn into_iter_double_ended_iterator() { + let mut iter = enum_map! { 0 => 5, 255 => 7, _ => 0 }.into_iter(); + assert_eq!(iter.next(), Some((0, 5))); + assert_eq!(iter.next_back(), Some((255, 7))); + assert_eq!(iter.next(), Some((1, 0))); + assert_eq!(iter.next_back(), Some((254, 0))); + assert!(iter.rev().eq((2..254).rev().map(|i| (i, 0)))); +} + +#[test] +fn values_rev_collect() { + assert_eq!( + vec![3, 2, 1], + enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 } + .values() + .rev() + .cloned() + .collect::<Vec<_>>() + ); +} + +#[test] +fn values_len() { + assert_eq!(enum_map! { false => 0, true => 1 }.values().len(), 2); +} + +#[test] +fn into_values_rev_collect() { + assert_eq!( + vec![3, 2, 1], + enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 } + .into_values() + .rev() + .collect::<Vec<_>>() + ); +} + +#[test] +fn into_values_len() { + assert_eq!(enum_map! { false => 0, true => 1 }.into_values().len(), 2); +} + +#[test] +fn values_mut_next_back() { + let mut map = enum_map! { false => 0, true => 1 }; + assert_eq!(map.values_mut().next_back(), Some(&mut 1)); +} +#[test] +fn test_u8() { + let mut map = enum_map! { b'a' => 4, _ => 0 }; + map[b'c'] = 3; + assert_eq!(map[b'a'], 4); + assert_eq!(map[b'b'], 0); + assert_eq!(map[b'c'], 3); + assert_eq!(map.iter().next(), Some((0, &0))); +} + +#[derive(Enum)] +enum Void {} + +#[test] +fn empty_map() { + let void: EnumMap<Void, Void> = enum_map! {}; + assert_eq!(void.len(), 0); +} + +#[test] +#[should_panic] +fn empty_value() { + let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() }; +} + +#[test] +fn empty_infallible_map() { + let void: EnumMap<Infallible, Infallible> = enum_map! {}; + assert_eq!(void.len(), 0); +} + +#[derive(Clone, Copy)] +enum X { + A(PhantomData<*const ()>), +} + +impl Enum for X { + const LENGTH: usize = 1; + + fn from_usize(arg: usize) -> X { + assert_eq!(arg, 0); + X::A(PhantomData) + } + + fn into_usize(self) -> usize { + 0 + } +} + +impl<V> EnumArray<V> for X { + type Array = [V; Self::LENGTH]; +} + +fn assert_sync_send<T: Sync + Send>(_: T) {} + +#[test] +fn assert_enum_map_does_not_copy_sync_send_dependency_of_keys() { + let mut map = enum_map! { X::A(PhantomData) => true }; + assert_sync_send(map); + assert_sync_send(&map); + assert_sync_send(&mut map); + assert_sync_send(map.iter()); + assert_sync_send(map.iter_mut()); + assert_sync_send(map.into_iter()); + assert!(map[X::A(PhantomData)]); +} + +#[test] +fn test_sum() { + assert_eq!( + enum_map! { i => u8::into(i) } + .iter() + .map(|(_, v)| v) + .sum::<u32>(), + 32_640 + ); +} + +#[test] +fn test_sum_mut() { + assert_eq!( + enum_map! { i => u8::into(i) } + .iter_mut() + .map(|(_, &mut v)| -> u32 { v }) + .sum::<u32>(), + 32_640 + ); +} + +#[test] +fn test_iter_clone() { + struct S(u8); + let map = enum_map! { + Example::A => S(3), + Example::B => S(4), + Example::C => S(1), + }; + let iter = map.iter(); + assert_eq!(iter.clone().map(|(_, S(v))| v).sum::<u8>(), 8); + assert_eq!(iter.map(|(_, S(v))| v).sum::<u8>(), 8); + let values = map.values(); + assert_eq!(values.clone().map(|S(v)| v).sum::<u8>(), 8); + assert_eq!(values.map(|S(v)| v).sum::<u8>(), 8); +} + +#[test] +fn question_mark() -> Result<(), ParseIntError> { + let map = enum_map! { false => "2".parse()?, true => "5".parse()? }; + assert_eq!(map, enum_map! { false => 2, true => 5 }); + Ok(()) +} + +#[test] +fn question_mark_failure() { + struct IncOnDrop<'a>(&'a Cell<i32>); + + impl Drop for IncOnDrop<'_> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + fn failible() -> Result<IncOnDrop<'static>, &'static str> { + Err("ERROR!") + } + + fn try_block(inc: &Cell<i32>) -> Result<(), &'static str> { + enum_map! { + 32 => failible()?, + _ => { + IncOnDrop(inc) + } + }; + Ok(()) + } + let value = Cell::new(0); + assert_eq!(try_block(&value), Err("ERROR!")); + assert_eq!(value.get(), 32); +} + +#[test] +#[should_panic = "Intentional panic"] +fn map_panic() { + let map: EnumMap<u8, String> = enum_map! { i => i.to_string() }; + map.map(|k, v| { + if k == 2 { + panic!("Intentional panic"); + } + v + " modified" + }); +} + +macro_rules! make_enum_map_macro_safety_test { + ($a:tt $b:tt) => { + // This is misuse of an API, however we need to test that to ensure safety + // as we use unsafe code. + enum E { + A, + B, + C, + } + + impl Enum for E { + const LENGTH: usize = $a; + + fn from_usize(value: usize) -> E { + match value { + 0 => E::A, + 1 => E::B, + 2 => E::C, + _ => unimplemented!(), + } + } + + fn into_usize(self) -> usize { + self as usize + } + } + + impl<V> EnumArray<V> for E { + type Array = [V; $b]; + } + + let map: EnumMap<E, String> = enum_map! { _ => "Hello, world!".into() }; + map.into_iter(); + }; +} + +#[test] +fn enum_map_macro_safety_under() { + make_enum_map_macro_safety_test!(2 3); +} + +#[test] +fn enum_map_macro_safety_over() { + make_enum_map_macro_safety_test!(3 2); +} + +#[test] +fn drop_panic_into_iter() { + struct DropHandler<'a>(&'a Cell<usize>); + impl Drop for DropHandler<'_> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + impl UnwindSafe for DropHandler<'_> {} + struct Storage<'a> { + should_panic: bool, + _drop_handler: DropHandler<'a>, + } + impl Drop for Storage<'_> { + fn drop(&mut self) { + if self.should_panic { + panic!(); + } + } + } + let cell = Cell::new(0); + let map: EnumMap<Example, _> = enum_map! { + v => Storage { should_panic: v == Example::B, _drop_handler: DropHandler(&cell) }, + }; + assert!(catch_unwind(|| { + map.into_iter(); + }) + .is_err()); + assert_eq!(cell.get(), 3); +} + +#[test] +fn test_const_enum_map_from_array() { + const CONST_ENUM_MAP_FROM_ARRAY: EnumMap<bool, u32> = EnumMap::from_array([4, 8]); + assert_eq!( + CONST_ENUM_MAP_FROM_ARRAY, + enum_map! { false => 4, true => 8 }, + ); +} + +#[test] +fn usize_override() { + #[allow(non_camel_case_types, dead_code)] + type usize = (); + #[derive(Enum)] + enum X { + A, + B, + } +} + +// Regression test for https://codeberg.org/xfix/enum-map/issues/112 +#[test] +fn test_issue_112() { + #[derive(Enum, PartialEq, Debug)] + enum Inner { + Inner1, + Inner2, + } + + #[derive(Enum, PartialEq, Debug)] + enum Outer { + A, + B(Inner), + C, + D(Inner, Inner), + E, + } + + assert_eq!(Outer::A.into_usize(), 0); + assert_eq!(Outer::A, Outer::from_usize(0)); + assert_eq!(Outer::B(Inner::Inner1).into_usize(), 1); + assert_eq!(Outer::B(Inner::Inner1), Outer::from_usize(1)); + assert_eq!(Outer::B(Inner::Inner2).into_usize(), 2); + assert_eq!(Outer::B(Inner::Inner2), Outer::from_usize(2)); + assert_eq!(Outer::C.into_usize(), 3); + assert_eq!(Outer::C, Outer::from_usize(3)); + assert_eq!(Outer::D(Inner::Inner1, Inner::Inner1).into_usize(), 4); + assert_eq!(Outer::D(Inner::Inner1, Inner::Inner1), Outer::from_usize(4)); + assert_eq!(Outer::D(Inner::Inner2, Inner::Inner1).into_usize(), 5); + assert_eq!(Outer::D(Inner::Inner2, Inner::Inner1), Outer::from_usize(5)); + assert_eq!(Outer::D(Inner::Inner1, Inner::Inner2).into_usize(), 6); + assert_eq!(Outer::D(Inner::Inner1, Inner::Inner2), Outer::from_usize(6)); + assert_eq!(Outer::D(Inner::Inner2, Inner::Inner2).into_usize(), 7); + assert_eq!(Outer::D(Inner::Inner2, Inner::Inner2), Outer::from_usize(7)); + assert_eq!(Outer::E.into_usize(), 8); + assert_eq!(Outer::E, Outer::from_usize(8)); +} |