Append to Node to an Empty LinkedList in Rust, self.head.borrow_next() is None and not self.tail - unit-testing

I have tried to reimplement LinkedList in Rust, below are my codes:
#![allow(dead_code)]
use std::cell::{RefCell, Ref, RefMut};
use std::rc::Rc;
type WrappedNode<T> = Rc<RefCell<Node<T>>>;
#[derive(Debug, PartialOrd, PartialEq, Clone)]
pub struct Node<T> where
T: Clone
{
next: Option<WrappedNode<T>>,
data: T,
}
#[derive(Debug, PartialOrd, PartialEq)]
pub struct LinkedList<T> where
T: Clone
{
head: Option<WrappedNode<T>>,
tail: Option<WrappedNode<T>>,
}
impl<T> Iterator for LinkedList<T> where
T: Clone
{
type Item = WrappedNode<T>;
fn next(&mut self) -> Option<Self::Item> {
unimplemented!()
}
}
impl<T> Node<T> where
T: Clone
{
pub fn new(data: T) -> Self {
Self {
next: None,
data,
}
}
pub fn borrow_data(self: &Self) -> &T {
&self.data
}
pub fn borrow_next(self: &Self) -> Option<Ref<Node<T>>> {
match &self.next {
Some(next_exists) => {
Some(next_exists.borrow())
},
None => {
None
}
}
}
pub fn borrow_mut_next(self: &Self) -> Option<RefMut<Node<T>>> {
match &self.next {
Some(next_exists) => {
Some(next_exists.borrow_mut())
},
None => {
None
}
}
}
pub fn set_next(self: &mut Self, next: Node<T>) {
let next_node = Rc::new(RefCell::new(next));
self.next = Some(next_node);
}
}
impl<T> LinkedList<T> where
T: Clone
{
pub fn new_empty() -> Self {
Self {
head: None,
tail: None,
}
}
pub fn new_with_node(first_node: Node<T>) -> Self {
let mut new_ll = Self::new_empty();
Self::append(&mut new_ll, first_node);
new_ll
}
pub fn append(&mut self, node: Node<T>) {
assert!(node.next.is_none()); // make sure its not joining two linkedlists
match self.tail.take() {
Some(old_tail) => {
old_tail
.borrow_mut()
.set_next(node.clone());
},
None => {
let mut node_clone = node.clone();
node_clone.next = self.tail.clone();
self.head = Some(Rc::new(RefCell::new(node_clone)));
}
}
self.tail = Some(Rc::new(RefCell::new(node)));
}
}
// CRUD -> create new, add to head tail, read head tail, update anywhere, delete anywhere, delete head tail
#[cfg(test)]
mod tests {
use super:: {Node, LinkedList};
use std::rc::Rc;
use std::cell::RefCell;
#[test]
fn test_node_ref_data() {
let node = Node::new(5);
assert_eq!(node.borrow_data(), &5);
}
#[test]
fn test_node_ref_next() {
let node = Node::new(5);
assert!(node.borrow_next().is_none());
}
#[test]
fn test_node_set_next() {
let mut node = Node::new(33);
let next_node = Node::new(34);
Node::set_next(&mut node,
next_node);
assert_eq!(node
.borrow_next()
.unwrap()
.borrow_data(), &34);
}
#[test]
fn test_ll_new_empty() {
#[derive(Debug, PartialEq, PartialOrd, Clone)]
struct NTH;
let new_ll = LinkedList::<NTH>::new_empty();
assert_eq!(new_ll, LinkedList{head: None, tail: None})
}
#[test]
fn test_ll_new_with_node() {
let new_node = Node::new(45);
let new_node_two = new_node.clone();
let new_node_three = new_node.clone();
let new_ll = LinkedList::new_with_node(new_node);
let new_node_two = Some(Rc::new(RefCell::new(new_node_two)));
let new_node_three = Some(Rc::new(RefCell::new(new_node_three)));
assert_eq!(new_ll, LinkedList{head: new_node_two, tail: new_node_three})
}
#[test]
fn test_ll_new_with_node_head_borrow_next_is_tail() {
let new_node = Node::new(45);
let new_node_two = new_node.clone();
let new_ll = LinkedList::new_with_node(new_node);
let new_node_two = Some(Rc::new(RefCell::new(new_node_two)));
assert_eq!(new_ll
.head
.unwrap()
.borrow()
.borrow_next()
.unwrap()
.borrow_data(), new_node_two.unwrap().borrow().borrow_data());
}
#[test]
fn test_ll_append_tail() {
let new_node = Node::new(45);
let new_node_two = new_node.clone();
let mut new_ll = LinkedList::new_with_node(new_node);
let new_node_two = Some(Rc::new(RefCell::new(new_node_two)));
let append_node = Node::new(77);
LinkedList::append(&mut new_ll, append_node);
assert_eq!(new_ll
.tail
.unwrap()
.borrow()
.borrow_data(), &77)
}
#[test]
fn test_ll_append_first_borrow_next() {
let new_node = Node::new(45);
let new_node_two = new_node.clone();
let mut new_ll = LinkedList::new_with_node(new_node);
let new_node_two = Some(Rc::new(RefCell::new(new_node_two)));
let append_node = Node::new(77);
LinkedList::append(&mut new_ll, append_node);
assert_eq!(new_ll
.head
.unwrap()
.borrow()
.borrow_next()
.unwrap()
.borrow_data(), &77)
}
// end of tests
}
Two tests failed, as shown below:
running 8 tests
test same_type_linked_list::tests::test_ll_new_empty ... ok
test same_type_linked_list::tests::test_ll_append_tail ... ok
test same_type_linked_list::tests::test_ll_new_with_node_head_borrow_next_is_tail ... FAILED
test same_type_linked_list::tests::test_ll_append_first_borrow_next ... FAILED
test same_type_linked_list::tests::test_ll_new_with_node ... ok
test same_type_linked_list::tests::test_node_ref_data ... ok
test same_type_linked_list::tests::test_node_set_next ... ok
test same_type_linked_list::tests::test_node_ref_next ... ok
failures:
---- same_type_linked_list::tests::test_ll_new_with_node_head_borrow_next_is_tail stdout ----
thread 'same_type_linked_list::tests::test_ll_new_with_node_head_borrow_next_is_tail' panicked at 'called `Option::unwrap()` on a `None` value', src/same_type_linked_list.rs:176:14
---- same_type_linked_list::tests::test_ll_append_first_borrow_next stdout ----
thread 'same_type_linked_list::tests::test_ll_append_first_borrow_next' panicked at 'called `Option::unwrap()` on a `None` value', src/same_type_linked_list.rs:210:16
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
same_type_linked_list::tests::test_ll_append_first_borrow_next
same_type_linked_list::tests::test_ll_new_with_node_head_borrow_next_is_tail
I suspect during the appending of a new Node<T>, concretely Node<u64>, to an empty LinkedList the self.head.next is not pointing to self.tail, despite me setting it explicitly. The error occurs when I call unwrap() on the None value which is returned from borrow_next(), an associated method of Node<T> to return a reference of the field .next. That means that new_ll.head.borrow_next() which ideally should return a reference to new_ll.tail instead returns a None, meaning that it is not pointing to new_ll.tail when a first node is appended/inserted into a completely empty LinkedList.

Looking at your code the head node is the one that you give to in
LinkedList::new_with_node()
Its calling
pub fn new_empty() -> Self {
Self {
head: None,
tail: None,
}
i.e. its initialized with no head node. So when you construct your list with a node you are adding a head
pub fn new_with_node(first_node: Node<T>) -> Self {
let mut new_ll = Self::new_empty();
Self::append(&mut new_ll, first_node);
new_ll
}
pub fn append(&mut self, node: Node<T>) {
assert!(node.next.is_none()); // make sure its not joining two linkedlists
match self.tail.take() {
Some(old_tail) => {
old_tail
.borrow_mut()
.set_next(node.clone());
},
None => {
let mut node_clone = node.clone();
node_clone.next = self.tail.clone();
self.head = Some(Rc::new(RefCell::new(node_clone)));
}
}
You are also calling append by explicitly passing the newly created list as self.
Self::append(&mut new_ll, first_node);
You could have called it
new_ll.append(first_node)
You are assuming there is another node beyond the head in your test:
assert_eq!(new_ll
.head
.unwrap()
.borrow()
.borrow_next()
.unwrap()
.borrow_data(), &77)

Related

AWS Kinesis Rust SDK is not compatible with Tokio Runtime

I am trying to bridging the async functionality of the SDK with sync code. I need this to create a tokio_stream (a struct with Stream trait implemented.) The problem is quite suprising,
#[cfg(test)]
mod tests {
use aws_config::meta::region::RegionProviderChain;
use aws_sdk_kinesis::{Client, Region};
use aws_config::SdkConfig;
use aws_sdk_kinesis::error::ListShardsError;
use aws_sdk_kinesis::output::ListShardsOutput;
use aws_sdk_kinesis::types::SdkError;
use futures::executor::block_on;
use tokio::runtime::Runtime;
/// It passes this test, without a problem.
#[tokio::test]
async fn testing_kinesis_stream_connection() -> () {
let region_provider = RegionProviderChain::first_try(Region::new("eu-central-1".to_string()));
let sdk_config =
aws_config::from_env()
.region(region_provider)
.load().await;
let client = Client::new(&sdk_config);
let shard_request = client.list_shards().stream_name("datafusion-stream".to_string());
let shards = shard_request.send().await.unwrap();
println!("{:?}", shards);
}
/// It passes this test, without a problem.
#[test]
fn testing_kinesis_stream_connection_without_tokio() -> () {
let runtime = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
let region_provider = RegionProviderChain::first_try(Region::new("eu-central-1".to_string()));
let sdk_config =
runtime.block_on(aws_config::from_env()
.region(region_provider)
.load());
let client = Client::new(&sdk_config);
let shard_request = client.list_shards().stream_name("datafusion-stream".to_string());
let shards = runtime.block_on(shard_request.send()).unwrap();
println!("{:?}", shards);
}
fn this_needs_to_be_sync_1() -> SdkConfig {
let region_provider = RegionProviderChain::first_try(Region::new("eu-central-1".to_string()));
let sdk_config =
futures::executor::block_on(aws_config::from_env()
.region(region_provider)
.load());
sdk_config
}
fn this_needs_to_be_sync_2(client: Client) -> ListShardsOutput {
let shard_request = client.list_shards().stream_name("datafusion-stream".to_string());
let shards = futures::executor::block_on(shard_request.send()).unwrap();
shards
}
/// It hangs in the second block_on.
#[tokio::test]
async fn testing_kinesis_stream_connection_sync_inside_async() -> () {
// Passes this block_on
let sdk_config = this_needs_to_be_sync_1();
let client = Client::new(&sdk_config);
// Blocks here
let shards = this_needs_to_be_sync_2(client);
println!("{:?}", shards);
}
}
I could not come up with a solution since there is no error, only hanged process.

return a new list from function in a for loop to pass in the updated list

I have a method that take a list as a parameter that performs some operation on it and returns the new list. However, in my for..loop I would to keep passing in the updated list until the for..loop has completed.
Is there a way to do this?
fun main(args: Array<String>) {
val listOfSeatRows = (1..127).toList()
// Just loop until all the listOfPass has completed.
listOfPass.forEach { seatPass ->
val seat = Seat.valueOf(seatPass.toString())
// I want to pass in the new updated list not the same list
getListOfSeatRows(listOfSeatRows, seat)
}
}
This method takes the list and return a updated list. However, in the for..loop above I would like to pass in the list that is returned from this method
private fun getListOfSeatRows(listOfSeat: List<Int>, seatPosition: Seat): List<Int> {
return when(seatPosition) {
Seat.F, Seat.L -> {
listOfSeat.windowed(listOfSeat.count() / 2).first()
}
Seat.B, Seat.R -> {
listOfSeat.windowed(listOfSeat.count() / 2).last()
}
}
}
enum class Seat(seat: Char) {
F('F'),
B('B'),
L('L'),
R('R')
}
Either you mutate the variable:
fun main(args: Array<String>) {
var listOfSeatRows = (1..127).toList()
// Just loop until all the listOfPass has completed.
listOfPass.forEach { seatPass ->
val seat = Seat.valueOf(seatPass.toString())
// I want to pass in the new updated list not the same list
listOfSeatRows = getListOfSeatRows(listOfSeatRows, seat)
}
}
or you mutate the list:
fun main(args: Array<String>) {
var listOfSeatRows = (1..127).toMutableList()
// Just loop until all the listOfPass has completed.
listOfPass.forEach { seatPass ->
val seat = Seat.valueOf(seatPass.toString())
// I want to pass in the new updated list not the same list
reduceListOfSeatRows(listOfSeatRows, seat)
}
}
private fun reduceListOfSeatRows(listOfSeat: MutableList<Int>, seatPosition: Seat) {
val half = listOfSeat.size / 2
when(seatPosition) {
Seat.F, Seat.L -> {
while (listOfSeat.size > half) listOfSeat.removeLast()
}
Seat.B, Seat.R -> {
while (listOfSeat.size > half) listOfSeat.removeFirst()
}
}
}
If you stick with mutating the property, your function can be simplified (and avoid wasteful creation of multiple intermediate lists) using take/takeLast:
private fun getListOfSeatRows(listOfSeat: List<Int>, seatPosition: Seat): List<Int> {
return when(seatPosition) {
Seat.F, Seat.L -> {
listOfSeat.take(listOfSeat.size / 2)
}
Seat.B, Seat.R -> {
listOfSeat.takeLast(listOfSeat.size / 2)
}
}
}
recursion
maybe that's will help with some enhancement depending on your code:
var ss = 1
val listOfPass = listOf<Char>('F', 'L','B','R')
fun main(args: Array<String>) {
val listOfSeatRows = (1..127).toList()
val answer = getListOfSeatRows(
listOfSeatRows,
listOfSeatRows.count() / 2,
Seat.valueOf(listOfPass[0].toString())
)
println(answer)
}
private fun getListOfSeatRows(listOfSeat: List<Int>, count: Int, seatPosition: Seat): List<Int> {
val tempList: List<Int> = when (seatPosition) {
Seat.F, Seat.L -> {
listOfSeat.windowed(count).first()
}
Seat.B, Seat.R -> {
listOfSeat.windowed(count).last()
}
else -> listOfSeat
}
if(count == 0 || count == 1) return listOfSeat
if (listOfPass.size > ss) {
val seat = Seat.valueOf(listOfPass[ss++].toString())
return getListOfSeatRows(tempList, count / 2, seat)
}
return listOfSeat
}

Why can "rust cookie::CookieJar" get a value through str type

I know that the underlying data structure is a HashSet, but why can the get method use the &str type instead of the cookie structure?
cargo.toml
[dependencies]
cookie = "0.14"
src/main.rs
use cookie::{Cookie, CookieJar};
fn main() {
let mut jar = CookieJar::new();
jar.add(Cookie::new("a", "one"));
jar.add(Cookie::new("b", "two"));
assert_eq!(jar.get("a").map(|c| c.value()), Some("one"));
assert_eq!(jar.get("b").map(|c| c.value()), Some("two"));
jar.remove(Cookie::named("b"));
assert!(jar.get("b").is_none());
}
The authors of cookie-rs implemented the Hash and Borrow trait for the values of the HashSet.
Here's an example mimicking the same behavior:
use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::collections::HashSet;
#[derive(Debug, Eq)]
struct Cookie<'a> {
name: &'a str,
id: u64,
}
impl Hash for Cookie<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl PartialEq for Cookie<'_> {
fn eq(&self, other: &Cookie) -> bool {
self.name == other.name
}
}
impl Borrow<str> for Cookie<'_> {
fn borrow(&self) -> &str {
self.name
}
}
fn main() {
let mut cookies: HashSet<Cookie> = HashSet::new();
cookies.insert(Cookie {
name: "example",
id: 42,
});
println!("{:?}", cookies.get("example"));
}
That would give us:
Some(Cookie { name: "example", id: 42 })

LiveData unit test do not pass under coroutine and multithread because of return true instead of expected false

EnrollmentViewModelTest
#Test
fun getUserProfile() {
val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
val user = Gson().fromJson<User>(responseSnapshot, User::class.java)
val response = Response.success(user)
val deferred = CompletableDeferred<Response<User>>(response)
coEvery { userService.getUserDetail() } returns deferred
viewModel.getUserProfile()
assert(viewModel.loadingStatus.value != null)
assert(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false, viewModel.loadingStatus.value!!)
}
Here is EnrollmentViewModel.kt
fun getUserProfile() {
loadingStatus.postValue(true)
job = launch {
callAsync {
userService.getUserDetail()
}.onSuccess { user ->
if (user != null) {
processUserDetails(user)
}
loadingStatus.postValue(false)
}.onError {
//
}.onException {
//
}
}
}
When I debug the test case, it show that the UITestUtil.getValue(viewModel.loadingStatus)!! is false.
But weirdly, the test case does not pass, and when I print the UITestUtil.getValue(viewModel.loadingStatus)!!. It is true.
It may related to the loadingStatus.postValue(true)
After I remove it, the print result is false.
But I do not know why.
object UITestUtil {
/**
* Gets the value of a LiveData safely.
*/
#Throws(InterruptedException::class)
fun <T> getValue(liveData: LiveData<T>): T? {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data = o
latch.countDown()
liveData.removeObserver(this)
}
}
liveData.observeForever(observer)
latch.await(2, TimeUnit.SECONDS)
return data
}
}
Updated:
import com.google.gson.Gson
import kotlinx.coroutines.Deferred
import retrofit2.Response
import retrofit2.Response.success
data class VPlusResult<T : Any?>(
val response: Response<T>? = null,
val exception: Exception? = null
)
inline fun <T : Any> VPlusResult<T>.onSuccess(action: (T?) -> Unit): VPlusResult<T> {
if (response?.isSuccessful == true)
action(response.body())
return this
}
inline fun <T : Any> VPlusResult<T>.onRawSuccess(action: (response: Response<T>) -> Unit): VPlusResult<T> {
if (response?.isSuccessful == true)
action(response)
return this
}
inline fun <T : Any, TR : Any> VPlusResult<T>.map(action: (T?) -> (TR)) =
if (response?.isSuccessful == true) VPlusResult(success(action(response.body())))
else this as VPlusResult<TR>
inline fun <T : Any> VPlusResult<T>.onError(action: (String) -> Unit): VPlusResult<T> {
if (response?.isSuccessful != true) {
response?.errorBody()?.let {
action(it.string())
}
}
return this
}
inline fun <T : Any, reified G : Any> VPlusResult<T>.onErrorJson(action: (G) -> Unit): VPlusResult<T> {
if (response?.isSuccessful != true) {
response?.errorBody()?.let {
action(Gson().fromJson(it.string(), G::class.java))
}
}
return this
}
inline fun <T : Any> VPlusResult<T>.onRawError(action: (Response<T>?) -> Unit): VPlusResult<T> {
if (response?.isSuccessful != true) {
action(response)
}
return this
}
inline fun <T : Any?> VPlusResult<T>.onException(action: (Exception) -> Unit) {
exception?.let { action(it) }
}
inline fun <T : Any> VPlusResult<T>.onSadness(action: (String?) -> Unit): VPlusResult<T> {
onError {
action(it)
}.onException {
action(it.message)
}
return this
}
suspend fun <T : Any> callAsync(block: () -> Deferred<Response<T>>): VPlusResult<T> {
return try {
VPlusResult(block().await())
} catch (e: Exception) {
VPlusResult(exception = e)
}
}
Updated 2:
adding either of the following statements before assert statement will get the value false, which passes the test case.
coVerify { userService.getUserDetail() }
coVerify { viewModel.processUserDetails(user) }
Update 3:
fun loadAllTasksFromRepository_loadingTogglesAndDataLoaded()
in https://github.com/android/architecture-samples
Also works, but I try to introduce into my codes, it also failed.
#ExperimentalCoroutinesApi
#Test
fun getUserProfile4Using() {
// using TestCoroutineScope in kotlinx.coroutines.test
// Pause dispatcher so we can verify initial values
mainCoroutineRule.pauseDispatcher()
val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
val user = Gson().fromJson<User>(responseSnapshot, User::class.java)
val response = Response.success(user)
val deferred = CompletableDeferred<Response<User>>(response)
// coEvery { userService.getUserDetail() } returns deferred
viewModel.getUserProfile()
assert(viewModel.loadingStatus.value != null)
// verify { viewModel.processUserDetails(user) }
print(viewModel.loadingStatus.value)
assert(UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(true, viewModel.loadingStatus.value!!)
// Execute pending coroutines actions
mainCoroutineRule.resumeDispatcher()
print(viewModel.loadingStatus.value!!)
assert(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false, viewModel.loadingStatus.value!!)
}
I'd say you should probably rewrite your test using runBlockingTest(https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/)
fun getUserProfile() = runBlockingTest{
val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
val user = Gson().fromJson<User>(responseSnapshot, User::class.java)
val response = Response.success(user)
val deferred = CompletableDeferred<Response<User>>(response)
coEvery { userService.getUserDetail() } returns deferred
viewModel.getUserProfile()
assert(viewModel.loadingStatus.value != null)
assert(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false, viewModel.loadingStatus.value!!)
}
You won't have to use those countdownlatches etc. This approach has literally fixed all of my issues with testing coroutines, hope it helps you as well :)! If not, just let me know.

How to fix a SIGSEGV in this simple doubly linked list implementation?

I get a SIGSEGV error when running this code.
The code compiles, the debugger shows what looks like random addresses in pointers.
use std::ptr;
pub struct List<T> {
head: *mut Node<T>,
tail: *mut Node<T>,
}
struct Node<T> {
data: Option<T>,
next: *mut Node<T>,
prev: *mut Node<T>,
}
impl<T> List<T> {
pub fn new() -> Self {
Self {
head: ptr::null_mut(),
tail: ptr::null_mut(),
}
}
pub fn add_tail(&mut self, data: T) {
let mut new_node = Box::new(Node {
data: Some(data),
next: ptr::null_mut(),
prev: ptr::null_mut(),
});
let new_node_ptr: *mut Node<T> = &mut *new_node;
if self.tail.is_null() {
self.head = new_node_ptr;
} else {
new_node.next = self.tail;
unsafe {
(*self.tail).prev = new_node_ptr;
}
}
self.tail = new_node_ptr;
}
pub fn remove_tail(&mut self) -> Option<T> {
if self.tail.is_null() {
None
} else {
let old_tail_ptr = self.tail;
unsafe {
if (*old_tail_ptr).next.is_null() {
self.tail = ptr::null_mut();
self.head = ptr::null_mut();
} else {
let new_tail_ptr = (*old_tail_ptr).next;
(*old_tail_ptr).next = ptr::null_mut();
(*new_tail_ptr).prev = ptr::null_mut();
self.tail = new_tail_ptr;
}
(*old_tail_ptr).data.take()
}
}
}
}
My test adds ten integers 0..9 and them pops them. On second pop, I get
signal: 11, SIGSEGV: invalid memory reference.
The following will fix the error. In add_tail:
replace let new_node_ptr: *mut Node<T> = &mut *new_node; with let new_node_ptr = Box::into_raw(new_node);
replace new_node.next = self.tail with (*new_node_ptr).next = self.tail;
include (*new_node_ptr).next = self.tail; in the unsafe block
The error was due to obtaining the underlying pointer from the Box incorrectly.
After let new_node_ptr: *mut Node<T> = &mut *new_node; the Box continued to manage the memory pointed to by new_node_ptr. At the end of the block, the Box deallocated the memory automatically leaving new_node_ptr dangling.
To obtain a pointer with manual memory management and to release control of memory from the Box, use Box::into_raw instead of &mut *.