| // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| // Exceptions. See /LICENSE for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| use googletest::prelude::*; |
| use static_assertions::assert_impl_all; |
| use std::cell::RefCell; |
| use std::cmp::Ordering; |
| use std::ffi::c_void; |
| use std::hash::BuildHasher; |
| use std::rc::Rc; |
| |
| #[gtest] |
| fn test_vector_new() { |
| let v = cc_std::std::vector::<i64>::new(); |
| expect_eq!(v.len(), 0); |
| expect_eq!(v.capacity(), 0); |
| expect_eq!(v.is_empty(), true); |
| } |
| |
| #[gtest] |
| fn test_set_len() { |
| let mut v = cc_std::std::vector::<isize>::with_capacity(10); |
| unsafe { |
| let p = v.as_mut_ptr(); |
| v.prepare_to_write_into_tail(); |
| for i in 0..3 { |
| std::ptr::write(p.offset(i), i); |
| } |
| v.set_len(3); |
| } |
| expect_eq!(v, [0, 1, 2]); |
| expect_that!(v.capacity(), ge(10)); |
| |
| unsafe { |
| v.set_len(0); |
| } |
| expect_eq!(v, []); |
| expect_that!(v.capacity(), ge(10)); |
| } |
| |
| #[gtest] |
| fn test_vector_push() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| expect_eq!(v.len(), 1); |
| expect_that!(v.capacity(), ge(1)); |
| expect_eq!(v.get(0), Some(&1)); |
| v.push(5); |
| expect_eq!(v.len(), 2); |
| expect_that!(v.capacity(), ge(2)); |
| expect_eq!(v.get(0), Some(&1)); |
| expect_eq!(v.get(1), Some(&5)); |
| } |
| |
| #[gtest] |
| fn test_vector_deref() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| v.push(5); |
| expect_eq!((*v)[0], 1); |
| expect_eq!((*v)[1], 5); |
| } |
| |
| #[gtest] |
| fn test_vector_get_range() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| v.push(-2); |
| expect_eq!(v.get_mut(0), Some(&mut 1)); |
| expect_eq!(v.get(0..2), Some(&[1, -2][..])); |
| } |
| |
| #[gtest] |
| fn test_vector_deref_mut() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| v.push(5); |
| (*v)[0] = 2; |
| expect_eq!((*v)[0], 2); |
| (*v)[1] = 6; |
| expect_eq!((*v)[1], 6); |
| } |
| |
| #[gtest] |
| fn test_vector_debug() { |
| let v = cc_std::std::vector::from([1, 2, 3]); |
| expect_eq!(format!("{:?}", v), "[1, 2, 3]"); |
| } |
| |
| struct InstanceCounted { |
| counter: Rc<RefCell<i32>>, |
| } |
| |
| impl Drop for InstanceCounted { |
| fn drop(&mut self) { |
| *self.counter.borrow_mut() -= 1; |
| } |
| } |
| |
| impl InstanceCounted { |
| fn new(counter: Rc<RefCell<i32>>) -> InstanceCounted { |
| *counter.borrow_mut() += 1; |
| InstanceCounted { counter } |
| } |
| } |
| |
| #[gtest] |
| fn test_vector_as_mut() { |
| let mut v = cc_std::std::vector::from(vec![2, 5]); |
| { |
| let mut_v: &mut [i32] = <cc_std::std::vector<i32> as AsMut<[i32]>>::as_mut(&mut v); |
| expect_eq!(mut_v, &[2, 5]); |
| mut_v[0] = 0; |
| } |
| expect_eq!(v, [0, 5]); |
| } |
| |
| #[gtest] |
| fn test_vector_as_ref() { |
| let v = cc_std::std::vector::from(vec![2, 5]); |
| expect_eq!(<cc_std::std::vector<i32> as AsRef<[i32]>>::as_ref(&v), &[2, 5]); |
| } |
| |
| #[gtest] |
| fn test_vector_borrow() { |
| let v = cc_std::std::vector::from(vec![2, 5]); |
| expect_eq!(<cc_std::std::vector<i32> as std::borrow::Borrow<[i32]>>::borrow(&v), &[2, 5]); |
| } |
| |
| #[gtest] |
| fn test_vector_borrow_mut() { |
| let mut v = cc_std::std::vector::from(vec![1, 3]); |
| { |
| let borrowed: &mut [i32] = |
| <cc_std::std::vector<i32> as std::borrow::BorrowMut<[i32]>>::borrow_mut(&mut v); |
| expect_eq!(borrowed, &[1, 3]); |
| borrowed[0] = 2; |
| } |
| expect_eq!(v, [2, 3]); |
| } |
| |
| #[gtest] |
| fn test_vector_drop() { |
| let mut v = cc_std::std::vector::new(); |
| let counter = Rc::new(RefCell::new(0i32)); |
| v.push(InstanceCounted::new(counter.clone())); |
| v.push(InstanceCounted::new(counter.clone())); |
| v.push(InstanceCounted::new(counter.clone())); |
| expect_eq!(*counter.borrow(), 3); |
| drop(v); |
| expect_eq!(*counter.borrow(), 0); |
| } |
| |
| #[gtest] |
| fn test_vector_index() { |
| let v = cc_std::std::vector::from(vec![1, 2, 3, 4]); |
| expect_eq!(v[0], 1); |
| expect_eq!(v[1], 2); |
| expect_eq!(v[..], [1, 2, 3, 4]); |
| expect_eq!(v[1..], [2, 3, 4]); |
| expect_eq!(v[1..2], [2]); |
| } |
| |
| #[gtest] |
| #[should_panic] |
| fn test_vector_index_out_of_bounds() { |
| let v = cc_std::std::vector::<i64>::new(); |
| use_variable(v[0]); |
| } |
| |
| #[gtest] |
| fn test_vector_mut_index() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3, 4]); |
| v[0] = 5; |
| expect_eq!(v, vec![5, 2, 3, 4]); |
| v[1..3][0] = 6; |
| expect_eq!(v, vec![5, 6, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_vector_to_vec() { |
| let v = cc_std::std::vector::from(vec![4, 5, 6]); |
| let v2 = v.to_vec(); |
| expect_eq!(v2, vec![4, 5, 6]); |
| } |
| |
| #[gtest] |
| fn test_clone() { |
| let v = cc_std::std::vector::from(vec![4, 5, 6]); |
| let v2 = v.clone(); |
| expect_eq!(v2, vec![4, 5, 6]); |
| } |
| |
| struct CloneCounter { |
| counter: Rc<RefCell<i32>>, |
| } |
| |
| impl Clone for CloneCounter { |
| fn clone(&self) -> Self { |
| *self.counter.borrow_mut() += 1; |
| CloneCounter { counter: self.counter.clone() } |
| } |
| } |
| |
| #[gtest] |
| fn test_clone_once_clone() { |
| let counter = Rc::new(RefCell::new(0i32)); |
| let v = cc_std::std::vector::from(vec![CloneCounter { counter: counter.clone() }]); |
| expect_eq!(*counter.borrow(), 0); |
| let _ = v.clone(); |
| expect_eq!(*counter.borrow(), 1); // the element was cloned once. |
| } |
| |
| #[gtest] |
| #[should_panic] |
| fn test_vector_mut_index_out_of_bounds() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| v[1] = 10; |
| } |
| |
| #[gtest] |
| fn test_vector_from_iter() { |
| let v = cc_std::std::vector::from_iter(std::iter::repeat(1).take(3)); |
| expect_eq!(v, [1, 1, 1]); |
| } |
| |
| #[gtest] |
| fn test_emtpy_vector_into_iter() { |
| let v = cc_std::std::vector::<i64>::new(); |
| let mut sum = 0; |
| for x in v { |
| sum += x; |
| } |
| expect_eq!(sum, 0); |
| } |
| |
| #[gtest] |
| fn test_vector_into_iter() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| v.push(2); |
| v.push(5); |
| let mut sum = 0; |
| for x in v { |
| sum += x; |
| } |
| expect_eq!(sum, 8); |
| } |
| |
| #[gtest] |
| fn test_vector_into_iter_size() { |
| let mut v = cc_std::std::vector::new(); |
| for i in 0..15 { |
| v.push(i); |
| } |
| let mut iter = v.into_iter(); |
| expect_eq!(iter.size_hint(), (15, Option::Some(15))); |
| iter.next(); |
| expect_eq!(iter.size_hint(), (14, Option::Some(14))); |
| expect_eq!(iter.count(), 14); |
| } |
| |
| #[gtest] |
| fn test_vector_into_iter_as_slice() { |
| let mut v = cc_std::std::vector::new(); |
| for i in 0..5 { |
| v.push(i); |
| } |
| let mut iter = v.into_iter(); |
| expect_eq!(iter.as_slice(), &[0, 1, 2, 3, 4]); |
| iter.next(); |
| expect_eq!(iter.as_slice(), &[1, 2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_vector_into_iter_as_mut_slice() { |
| let mut v = cc_std::std::vector::new(); |
| for i in 0..5 { |
| v.push(i); |
| } |
| let mut iter = v.into_iter(); |
| expect_eq!(iter.as_mut_slice(), &mut [0, 1, 2, 3, 4]); |
| iter.next(); |
| expect_eq!(iter.as_mut_slice(), &mut [1, 2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_vector_ref_iter() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| v.push(5); |
| v.push(10); |
| let mut sum = 0; |
| for x in &v { |
| sum += x; |
| } |
| // Sum the elements in the vector 2nd time to ensure that the vector is still |
| // valid. |
| for x in &v { |
| sum += x; |
| } |
| expect_eq!(sum, 32); |
| } |
| |
| #[gtest] |
| fn test_vector_mut_ref_iter() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| v.push(2); |
| // Increment the elements in the vector (mut access). |
| for x in &mut v { |
| *x += 1; |
| } |
| // Check that the elements were incremented. |
| let mut sum = 0; |
| for x in &v { |
| sum += x; |
| } |
| expect_eq!(sum, 5); |
| } |
| |
| #[gtest] |
| fn test_iterator_as_ref() { |
| let mut v = cc_std::std::vector::new(); |
| for i in 0..5 { |
| v.push(i); |
| } |
| let mut iter = v.into_iter(); |
| expect_eq!(iter.as_ref(), &[0, 1, 2, 3, 4]); |
| iter.next(); |
| expect_eq!(iter.as_ref(), &[1, 2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_iterator_debug() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| v.push(2); |
| v.push(3); |
| expect_eq!(format!("{:?}", v.into_iter()), "IntoIter([1, 2, 3])"); |
| } |
| |
| #[gtest] |
| fn test_iterator_default() { |
| expect_eq!( |
| format!("{:?}", <cc_std::std::vector<i32> as IntoIterator>::IntoIter::default()), |
| "IntoIter([])" |
| ); |
| } |
| |
| #[gtest] |
| fn test_iterator_next_back() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(1); |
| v.push(2); |
| let mut iter = v.into_iter(); |
| expect_eq!(iter.next_back(), Some(2)); |
| expect_eq!(iter.next_back(), Some(1)); |
| expect_eq!(iter.next_back(), None); |
| } |
| |
| #[gtest] |
| fn test_iterator_drop() { |
| let mut v = cc_std::std::vector::new(); |
| v.push(10); |
| let it = v.into_iter(); |
| drop(it) |
| } |
| |
| /// Use a variable in a way that can't be optimized out. |
| fn use_variable<T>(v: T) { |
| std::hint::black_box(v); |
| } |
| |
| #[gtest] |
| fn test_vector_reserve() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| v.reserve(10); |
| expect_that!(v.capacity(), ge(10)); |
| let current_capacity = v.capacity(); |
| v.reserve(5); // 5 < 10, so it should do nothing. |
| expect_eq!(v.capacity(), current_capacity); |
| } |
| |
| #[gtest] |
| fn test_vector_reserve_exact() { |
| let mut v = cc_std::std::vector::<usize>::new(); |
| v.reserve_exact(10); |
| expect_that!(v.capacity(), ge(10)); |
| let current_capacity = v.capacity(); |
| // Add elements to the current capacity. |
| for i in v.len()..current_capacity { |
| v.push(i); |
| } |
| v.reserve_exact(5); // it ensures that the capacity for additional 5 elements. |
| expect_that!(v.capacity(), ge(current_capacity + 5)); |
| } |
| |
| #[gtest] |
| fn test_vector_try_reserve() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| v.try_reserve(100).unwrap(); |
| expect_that!(v.capacity(), ge(100)); |
| } |
| |
| #[gtest] |
| fn test_vector_try_reserve_exact() { |
| let mut v = cc_std::std::vector::<usize>::new(); |
| v.try_reserve_exact(10).unwrap(); |
| expect_that!(v.capacity(), ge(10)); |
| let current_capacity = v.capacity(); |
| // Add elements to the current capacity. |
| for i in v.len()..current_capacity { |
| v.push(i); |
| } |
| v.try_reserve_exact(5).unwrap(); // it ensures that the capacity for additional 5 elements. |
| expect_that!(v.capacity(), ge(current_capacity + 5)); |
| } |
| |
| #[gtest] |
| fn test_shrink_to_fit() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| for i in 0..100 { |
| v.push(i); |
| } |
| v.clear(); // doesn't shrink the capacity. |
| v.shrink_to_fit(); |
| expect_eq!(v.capacity(), 0); |
| } |
| |
| #[gtest] |
| fn test_shrink_to() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| for i in 0..100 { |
| v.push(i); |
| } |
| v.clear(); // doesn't shrink the capacity. |
| v.shrink_to(10); |
| expect_that!(v.capacity(), le(99)); |
| expect_that!(v.capacity(), ge(10)); |
| } |
| |
| #[gtest] |
| fn test_vector_with_capacity() { |
| let v = cc_std::std::vector::<i32>::with_capacity(100); |
| expect_that!(v.capacity(), ge(100)); |
| } |
| |
| #[gtest] |
| fn test_vector_insert() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| v.insert(0, 1); |
| v.insert(0, 2); |
| expect_eq!(v, [2, 1]); |
| v.insert(1, 3); |
| expect_eq!(v, [2, 3, 1]); |
| } |
| |
| #[gtest] |
| fn test_vector_append() { |
| let mut v = cc_std::std::vector::from(vec![1, 2]); |
| let mut v2 = cc_std::std::vector::from(vec![3, 4]); |
| v.append(&mut v2); |
| expect_eq!(v, [1, 2, 3, 4]); |
| expect_eq!(v2, []); |
| expect_eq!(v2.is_empty(), true); |
| } |
| |
| #[gtest] |
| fn test_swap_remove() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3, 4]); |
| expect_eq!(v.swap_remove(1), 2); |
| expect_eq!(v, [1, 4, 3]); |
| expect_eq!(v.swap_remove(0), 1); |
| expect_eq!(v, [3, 4]); |
| expect_eq!(v.swap_remove(0), 3); |
| expect_eq!(v, [4]); |
| expect_eq!(v.swap_remove(0), 4); |
| expect_eq!(v.is_empty(), true); |
| } |
| |
| #[gtest] |
| #[should_panic] |
| fn test_swap_remove_out_of_bounds() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3, 4]); |
| v.swap_remove(4); |
| } |
| |
| #[gtest] |
| fn test_remove() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3, 4]); |
| expect_eq!(v.remove(1), 2); |
| expect_eq!(v, [1, 3, 4]); |
| expect_eq!(v.remove(0), 1); |
| expect_eq!(v, [3, 4]); |
| expect_eq!(v.remove(1), 4); |
| expect_eq!(v, [3]); |
| expect_eq!(v.remove(0), 3); |
| expect_eq!(v.is_empty(), true); |
| } |
| |
| #[gtest] |
| #[should_panic] |
| fn test_remove_out_of_bounds() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3]); |
| v.remove(3); |
| } |
| |
| #[gtest] |
| fn test_pop() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3, 4]); |
| expect_eq!(v.pop(), Some(4)); |
| expect_eq!(v, [1, 2, 3]); |
| expect_eq!(v.pop(), Some(3)); |
| expect_eq!(v, [1, 2]); |
| expect_eq!(v.pop(), Some(2)); |
| expect_eq!(v, [1]); |
| expect_eq!(v.pop(), Some(1)); |
| expect_eq!(v.is_empty(), true); |
| expect_eq!(v.pop(), None); |
| } |
| |
| #[gtest] |
| fn test_vector_clear() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3, 4]); |
| v.clear(); |
| expect_eq!(v.is_empty(), true); |
| expect_eq!(v.capacity(), 4); |
| } |
| |
| #[gtest] |
| fn test_truncate() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3, 4, 5]); |
| let capacity = v.capacity(); |
| v.truncate(2); |
| expect_eq!(v, [1, 2]); |
| expect_eq!(v.capacity(), capacity); |
| v.truncate(3); // no effect |
| expect_eq!(v, [1, 2]); |
| |
| v.truncate(0); |
| expect_eq!(v, []); |
| expect_eq!(v.capacity(), capacity); |
| } |
| |
| #[gtest] |
| fn test_vector_resize() { |
| let mut v = cc_std::std::vector::from(vec![1, 2]); |
| v.resize(6, 5); |
| expect_eq!(v, [1, 2, 5, 5, 5, 5]); |
| v.resize(0, 5); |
| expect_eq!(v, []); |
| v.resize(1, 5); |
| expect_eq!(v, [5]); |
| } |
| |
| #[gtest] |
| fn test_vector_resize_with() { |
| let mut v = cc_std::std::vector::from(vec![1, 2]); |
| v.resize_with(6, Default::default); |
| expect_eq!(v, [1, 2, 0, 0, 0, 0]); |
| v.resize_with(0, Default::default); |
| expect_eq!(v, []); |
| } |
| |
| #[gtest] |
| fn test_vector_dedup() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 2, 3, 3, 3, 4, 4, 4, 4]); |
| v.dedup(); |
| expect_eq!(v, [1, 2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_vector_dedup_by() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 2, 3, 3, 3, 4, 4, 4, 4]); |
| v.dedup_by(|a, b| a == b); |
| expect_eq!(v, [1, 2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_vector_dedup_by_key() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 2, 6, 3, 3, 5, 4, 4, 4, 4]); |
| v.dedup_by_key(|a| *a % 2); |
| expect_eq!(v, [1, 2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_retain() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); |
| v.retain(|&x| x % 2 == 0); |
| expect_eq!(v, [2, 4, 6, 8, 10]); |
| } |
| |
| #[gtest] |
| fn test_retain_mut() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3, 4]); |
| v.retain_mut(|x| { |
| if *x <= 3 { |
| *x += 1; |
| true |
| } else { |
| false |
| } |
| }); |
| expect_eq!(v, [2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_split_off() { |
| let mut vec = cc_std::std::vector::from(vec![1, 2, 3]); |
| let vec2 = vec.split_off(1); |
| expect_eq!(vec, [1]); |
| expect_eq!(vec2, [2, 3]); |
| } |
| |
| #[gtest] |
| fn test_vector_into_vec() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| v.push(1); |
| v.push(2); |
| v.push(3); |
| let v2 = v.into_vec(); |
| expect_eq!(v2, vec![1, 2, 3]); |
| } |
| |
| #[gtest] |
| fn test_extend_from_slice() { |
| let mut v = cc_std::std::vector::from(vec![1, 2, 3]); |
| v.extend_from_slice(&[4, 5, 6]); |
| expect_eq!(v, [1, 2, 3, 4, 5, 6]); |
| } |
| |
| #[gtest] |
| fn test_vector_extend_from_within() { |
| let mut v = cc_std::std::vector::from(vec![0, 1, 2, 3, 4]); |
| |
| v.extend_from_within(2..); |
| expect_eq!(v, [0, 1, 2, 3, 4, 2, 3, 4]); |
| |
| v.extend_from_within(..2); |
| expect_eq!(v, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1]); |
| |
| v.extend_from_within(4..8); |
| expect_eq!(v, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_vector_into_dropped_counter() { |
| let mut v = cc_std::std::vector::new(); |
| let counter = Rc::new(RefCell::new(0i32)); |
| v.push(InstanceCounted::new(counter.clone())); |
| v.push(InstanceCounted::new(counter.clone())); |
| v.push(InstanceCounted::new(counter.clone())); |
| expect_eq!(*counter.borrow(), 3); |
| let v2 = v.into_vec(); |
| drop(v2); |
| expect_eq!(*counter.borrow(), 0); |
| } |
| |
| #[gtest] |
| fn test_vector_from_vec() { |
| let v = cc_std::std::vector::from(vec![0, 1, 2, 3, 4]); |
| expect_eq!(v.len(), 5); |
| for i in 0..5 { |
| expect_eq!(v[i], i); |
| } |
| } |
| |
| #[gtest] |
| fn test_vector_extend() { |
| let mut v = cc_std::std::vector::new(); |
| v.extend(vec![1, 2, 3]); |
| expect_eq!(v, [1, 2, 3]); |
| v.extend(vec![4, 5, 6]); |
| expect_eq!(v, [1, 2, 3, 4, 5, 6]); |
| } |
| |
| #[gtest] |
| fn test_hash() { |
| let b = std::hash::RandomState::new(); |
| let v: cc_std::std::vector<i64> = cc_std::std::vector::from(vec![10, 12, -4]); |
| let s: &[i64] = &[10, 12, -4]; |
| expect_eq!(b.hash_one(v), b.hash_one(s)); |
| } |
| |
| #[gtest] |
| fn test_partial_ord() { |
| let u = cc_std::std::vector::from(vec![0.5, 1.0]); |
| let v = cc_std::std::vector::from(vec![0.5, 2.5, 3.0]); |
| expect_eq!(u.partial_cmp(&v).unwrap(), Ordering::Less); |
| expect_eq!(u.partial_cmp(&u).unwrap(), Ordering::Equal); |
| expect_eq!(v.partial_cmp(&u).unwrap(), Ordering::Greater); |
| } |
| |
| #[gtest] |
| fn test_partial_ord_non_comparable() { |
| let u = cc_std::std::vector::from(vec![1.0, f64::NAN]); |
| let v = cc_std::std::vector::from(vec![1.0, 2.0]); |
| // NAN is not comparable to any other number, so the comparison result is |
| // undefined. |
| expect_eq!(u.partial_cmp(&u), None); |
| expect_eq!(u.partial_cmp(&v), None); |
| } |
| |
| #[gtest] |
| fn test_ord() { |
| let u = cc_std::std::vector::from(vec![0, 1]); |
| let v = cc_std::std::vector::from(vec![0, 2]); |
| expect_eq!(u.cmp(&v), Ordering::Less); |
| expect_eq!(u.cmp(&u), Ordering::Equal); |
| expect_eq!(v.cmp(&u), Ordering::Greater); |
| } |
| |
| #[gtest] |
| fn test_comparison_operators() { |
| let u = cc_std::std::vector::from(vec![0, 1]); |
| let v = cc_std::std::vector::from(vec![0, 2, 3]); |
| expect_eq!(u < v, true); |
| expect_eq!(u <= v, true); |
| expect_eq!(u > v, false); |
| expect_eq!(u >= v, false); |
| } |
| #[gtest] |
| fn test_eq() { |
| assert_impl_all!(cc_std::std::vector<i64>: Eq); |
| } |
| |
| #[gtest] |
| fn test_vector_from_vec_with_capacity() { |
| let vector = cc_std::std::vector::from(vec![0, 1, 2, 3, 4]); |
| let vec = Vec::from(vector); |
| expect_eq!(vec, [0, 1, 2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_as_ptr() { |
| let v = cc_std::std::vector::from(vec!['a', 'b']); |
| let ptr: *const char = v.as_ptr(); |
| unsafe { |
| expect_eq!(*ptr, 'a'); |
| } |
| } |
| |
| #[gtest] |
| fn test_as_mut_ptr() { |
| let mut v = cc_std::std::vector::from(vec!['a', 'b']); |
| let ptr: *mut char = v.as_mut_ptr(); |
| unsafe { |
| expect_eq!(*ptr, 'a'); |
| *ptr = 'c'; |
| } |
| expect_eq!(v[0], 'c'); |
| } |
| |
| #[gtest] |
| fn test_as_slice() { |
| let v = cc_std::std::vector::from(vec![5, 6, 7]); |
| let slice: &[i32] = v.as_slice(); |
| expect_eq!(slice, &[5, 6, 7]); |
| } |
| |
| #[gtest] |
| fn test_as_mut_slice() { |
| let mut v = cc_std::std::vector::from(vec![5, 6, 7]); |
| let slice: &mut [i32] = v.as_mut_slice(); |
| expect_eq!(slice, &[5, 6, 7]); |
| slice[1] = 1; |
| expect_eq!(v[1], 1); |
| } |
| |
| #[gtest] |
| fn test_is_send() { |
| assert_impl_all!(cc_std::std::vector<i64>: Send); |
| } |
| |
| #[gtest] |
| fn test_is_sync() { |
| assert_impl_all!(cc_std::std::vector<i64>: Sync); |
| } |
| |
| mod layout_tests { |
| use crate::to_void_ptr; |
| use googletest::prelude::*; |
| |
| /// Tests that `vector` has the same memory layout as `std::vector` in C++. |
| #[gtest] |
| fn test_begin_end() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| v.push(1); |
| v.push(2); |
| v.push(3); |
| unsafe { |
| expect_eq!(cc_helper_functions::crubit_test::vector_int32_sum(to_void_ptr(&v)), 6); |
| } |
| } |
| |
| /// Tests that `vector` has the same memory layout as `std::vector` in C++. |
| #[gtest] |
| fn test_capacity() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| for i in 0..100 { |
| v.push(i); |
| } |
| unsafe { |
| expect_eq!( |
| cc_helper_functions::crubit_test::vector_int32_capacity(to_void_ptr(&v)), |
| v.capacity(), |
| ); |
| } |
| } |
| } |
| |
| mod allocation_tests { |
| use crate::to_void_ptr; |
| use googletest::prelude::*; |
| use std::mem::forget; |
| use std::mem::MaybeUninit; |
| |
| // The following tests check that the memory allocated in one language is |
| // correctly reallocated and dealocated in another language. |
| #[gtest] |
| fn test_allocate_in_rust_deallocate_in_cc() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| // Allocate heap memory in Rust (by adding elements) |
| for i in 0..10000 { |
| v.push(i); |
| } |
| // Deallocate the heap memory in C++. |
| unsafe { |
| cc_helper_functions::crubit_test::vector_int32_call_destructor(to_void_ptr(&v)); |
| } |
| forget(v); |
| } |
| |
| #[gtest] |
| fn test_allocate_in_cc_delocate_in_rust() { |
| unsafe { |
| // Allocate heap memory in C++ (by adding many elements) |
| let maybe_uninit_v = MaybeUninit::<cc_std::std::vector<i32>>::uninit(); |
| cc_helper_functions::crubit_test::vector_int32_construct(to_void_ptr(&maybe_uninit_v)); |
| let v = maybe_uninit_v.assume_init(); |
| expect_eq!(v.is_empty(), true); |
| |
| for i in 0..10000 { |
| cc_helper_functions::crubit_test::vector_int32_push_back(to_void_ptr(&v), i); |
| } |
| |
| expect_eq!(v.len(), 10000); |
| // Deallocate the heap memory in Rust. |
| drop(v) |
| } |
| } |
| |
| #[gtest] |
| fn test_allocate_in_cc_interchangeble_reallocate_in_different_languages() { |
| unsafe { |
| let maybe_uninit_v = MaybeUninit::<cc_std::std::vector<i32>>::uninit(); |
| cc_helper_functions::crubit_test::vector_int32_construct(to_void_ptr(&maybe_uninit_v)); |
| let mut v = maybe_uninit_v.assume_init(); |
| expect_eq!(v.is_empty(), true); |
| |
| // Allocate heap memory in C++. |
| for i in 0..10 { |
| cc_helper_functions::crubit_test::vector_int32_push_back(to_void_ptr(&v), i); |
| } |
| |
| // Reallocate heap memory in Rust by adding much more elements. |
| for i in 10..1000 { |
| v.push(i); |
| } |
| |
| // Reallocate heap memory in C++ by adding much much more elements. |
| for i in 1000..100000 { |
| cc_helper_functions::crubit_test::vector_int32_push_back(to_void_ptr(&v), i); |
| } |
| |
| expect_eq!(v.len(), 100000); |
| // Deallocate the heap memory in Rust. |
| drop(v) |
| } |
| } |
| |
| #[gtest] |
| fn test_allocate_in_rust_interchangeble_reallocate_in_different_languages() { |
| let mut v = cc_std::std::vector::<i32>::new(); |
| // Allocate heap memory in Rust (by adding elements) |
| for i in 0..10 { |
| v.push(i); |
| } |
| |
| unsafe { |
| // Reallocate heap memory in C++ by adding much more elements. |
| for i in 10..1000 { |
| cc_helper_functions::crubit_test::vector_int32_push_back(to_void_ptr(&v), i); |
| } |
| } |
| // Reallocate heap memory in Rust (by adding much much more elements) |
| for i in 1000..10000 { |
| v.push(i); |
| } |
| } |
| } |
| |
| mod alignment_tests { |
| use googletest::prelude::*; |
| // Tests that vector can hold a struct with correct alignment. |
| #[repr(align(1024))] |
| struct OveralignedStuct { |
| x: i32, |
| } |
| |
| #[gtest] |
| fn test_vector_of_overaligned_struct() { |
| let mut v = cc_std::std::vector::<OveralignedStuct>::new(); |
| v.push(OveralignedStuct { x: 1 }); |
| v.push(OveralignedStuct { x: 2 }); |
| expect_eq!(v[0].x, 1); |
| expect_eq!(v[1].x, 2); |
| expect_eq!(&raw const v[0] as usize % 1024, 0); |
| } |
| } |
| |
| mod partial_equal_tests { |
| use googletest::prelude::*; |
| |
| #[gtest] |
| fn test_vector_eq() { |
| let v = cc_std::std::vector::from(vec![1, 2, 3]); |
| let u = cc_std::std::vector::from(vec![1, 2]); |
| expect_eq!(v == v, true); |
| expect_eq!(v == u, false); |
| expect_eq!(v != u, true); |
| expect_eq!(v != v, false); |
| } |
| |
| #[gtest] |
| fn test_vec_partial_eq() { |
| let v = cc_std::std::vector::from(vec![1, 2, 3]); |
| expect_eq!(v == vec![1, 2, 3], true); |
| expect_eq!(vec![1, 2, 3] == v, true); |
| expect_eq!(v == vec![1, 2], false); |
| expect_eq!(v == vec![1i16, 2i16, 3i16], true); // i64 and i16 are |
| // comparable. |
| } |
| |
| #[gtest] |
| fn test_slice_partial_eq() { |
| let v = cc_std::std::vector::from(vec![1, 2, 3]); |
| expect_eq!(v == [1, 2, 3].as_slice(), true); |
| expect_eq!([1, 2, 3].as_slice() == v, true); |
| expect_eq!(v == [1, 2, 3].as_mut_slice(), true); |
| expect_eq!([1, 2, 3].as_mut_slice() == v, true); |
| } |
| |
| #[gtest] |
| fn test_array_partial_eq() { |
| let v = cc_std::std::vector::from(vec![1, 2, 3]); |
| expect_eq!(v == [1, 2, 3], true); |
| expect_eq!(v == &[1, 2, 3], true); |
| } |
| } |
| |
| #[gtest] |
| fn test_vector_from_slice() { |
| let v = cc_std::std::vector::from(vec![2, 3, 4].as_slice()); |
| expect_eq!(v, [2, 3, 4]); |
| } |
| |
| #[gtest] |
| fn test_vector_from_mut_slice() { |
| let v = cc_std::std::vector::from(vec![1.0, 2.0, 3.0].as_mut_slice()); |
| expect_eq!(v, [1.0, 2.0, 3.0]); |
| } |
| |
| #[gtest] |
| fn test_vector_from_array() { |
| let v = cc_std::std::vector::from(['a', 'b']); |
| expect_eq!(v, ['a', 'b']); |
| } |
| |
| #[gtest] |
| fn test_vector_from_array_ref() { |
| let v = cc_std::std::vector::from(&["ab", "cd"]); |
| expect_eq!(v, ["ab", "cd"]) |
| } |
| |
| #[gtest] |
| fn test_vector_from_array_mut_ref() { |
| let v = cc_std::std::vector::from(&mut [0, 1]); |
| expect_eq!(v, [0, 1]) |
| } |
| |
| #[gtest] |
| fn test_vector_covariant() { |
| // If this compiles, the test passes. |
| fn _compile_test<'a>( |
| mut _v1: cc_std::std::vector<&'a i32>, |
| v2: cc_std::std::vector<&'static i32>, |
| ) { |
| _v1 = v2; |
| } |
| } |
| |
| fn to_void_ptr<T>(t: &T) -> *mut c_void { |
| t as *const _ as *mut c_void |
| } |